@mastra/posthog 1.4.0-alpha.4 → 1.4.1-alpha.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/dist/index.cjs +5 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/tracing.d.ts.map +1 -1
- package/package.json +6 -6
package/dist/index.cjs
CHANGED
|
@@ -261,6 +261,11 @@ var PosthogExporter = class PosthogExporter extends _mastra_observability.Tracki
|
|
|
261
261
|
if (span.tags?.length) for (const tag of span.tags) traceProperties[tag] = true;
|
|
262
262
|
const { userId, sessionId, ...customMetadata } = span.metadata ?? {};
|
|
263
263
|
Object.assign(traceProperties, customMetadata);
|
|
264
|
+
if (span.type === _mastra_core_observability.SpanType.MCP_SERVER_REQUEST) {
|
|
265
|
+
const { callerTraceparent, callerTracestate } = span.attributes ?? {};
|
|
266
|
+
if (callerTraceparent) traceProperties.callerTraceparent = callerTraceparent;
|
|
267
|
+
if (callerTracestate) traceProperties.callerTracestate = callerTracestate;
|
|
268
|
+
}
|
|
264
269
|
return {
|
|
265
270
|
distinctId,
|
|
266
271
|
event: "$ai_trace",
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["observability","coreFeatures","TrackingExporter","#client","PostHog","SpanType"],"sources":["../src/features.ts","../src/tracing.ts"],"sourcesContent":["/**\n * Feature detection for paired @mastra/core and @mastra/observability versions.\n *\n * Both are resolved synchronously so span classification is stable from the\n * very first span, without depending on a pending dynamic import.\n *\n * `@mastra/observability` is a hard dependency, but older versions do not\n * export `observabilityFeatures`. The namespace import reads it as `undefined`\n * in that case instead of failing to link, which is the graceful fallback\n * documented in `observability/mastra/src/features.ts`.\n */\n\nimport { coreFeatures } from '@mastra/core/features';\nimport * as observability from '@mastra/observability';\n\nconst FEATURE = 'model-inference-span';\n\nlet observabilityFeatures: ReadonlySet<string> | undefined = (\n observability as { observabilityFeatures?: ReadonlySet<string> }\n).observabilityFeatures;\n\n/**\n * Returns true when both packages report the `model-inference-span` feature,\n * meaning MODEL_INFERENCE spans are emitted by the tracker. Drives which span\n * is exported as `$ai_generation` (new: MODEL_INFERENCE; legacy:\n * MODEL_GENERATION).\n */\nexport function isModelInferenceEnabled(): boolean {\n return observabilityFeatures?.has(FEATURE) === true && coreFeatures.has(FEATURE);\n}\n\n/**\n * @internal Test-only override. Allows tests to simulate a paired older or\n * newer `@mastra/observability` without juggling module mocks.\n */\nexport function __setObservabilityFeaturesForTest(features: ReadonlySet<string> | undefined): void {\n observabilityFeatures = features;\n}\n","import type {\n AnyExportedSpan,\n ExportedFeedback,\n FeedbackEvent,\n ModelGenerationAttributes,\n SpanErrorInfo,\n UsageStats,\n} from '@mastra/core/observability';\nimport { SpanType } from '@mastra/core/observability';\nimport type { TraceData, TrackingExporterConfig } from '@mastra/observability';\nimport { TrackingExporter } from '@mastra/observability';\nimport { PostHog } from 'posthog-node';\nimport type { EventMessage } from 'posthog-node';\nimport { isModelInferenceEnabled } from './features';\n\n/**\n * Token usage format compatible with PostHog.\n * @see https://posthog.com/docs/llm-analytics/generations#event-properties\n */\nexport interface PostHogUsageMetrics {\n $ai_input_tokens?: number;\n $ai_output_tokens?: number;\n $ai_cache_read_input_tokens?: number;\n $ai_cache_creation_input_tokens?: number;\n $ai_cache_creation_5m_input_tokens?: number;\n $ai_cache_creation_1h_input_tokens?: number;\n}\n\n/**\n * Formats UsageStats to PostHog's expected property format.\n *\n * Pass through gross input token counts with cache fields as subsets.\n * PostHog subtracts cache tokens when computing costs for non-Anthropic\n * providers and detects Anthropic-style exclusive reporting on its own.\n *\n * @param usage - The UsageStats from span attributes\n * @returns PostHog-formatted usage properties\n */\nexport function formatUsageMetrics(usage?: UsageStats): PostHogUsageMetrics {\n if (!usage) return {};\n\n const props: PostHogUsageMetrics = {};\n\n if (usage.inputTokens !== undefined) {\n props.$ai_input_tokens = usage.inputTokens;\n }\n\n if (usage.inputDetails?.cacheRead !== undefined) {\n props.$ai_cache_read_input_tokens = usage.inputDetails.cacheRead;\n }\n\n if (usage.inputDetails?.cacheWrite !== undefined) {\n props.$ai_cache_creation_input_tokens = usage.inputDetails.cacheWrite;\n }\n if (usage.inputDetails?.cacheWrite5m !== undefined) {\n props.$ai_cache_creation_5m_input_tokens = usage.inputDetails.cacheWrite5m;\n }\n if (usage.inputDetails?.cacheWrite1h !== undefined) {\n props.$ai_cache_creation_1h_input_tokens = usage.inputDetails.cacheWrite1h;\n }\n\n if (usage.outputTokens !== undefined) {\n props.$ai_output_tokens = usage.outputTokens;\n }\n\n return props;\n}\n\ninterface PostHogMessage {\n role: 'user' | 'assistant' | 'system' | 'tool';\n content: PostHogContent[];\n}\n\ninterface PostHogContent {\n type: string;\n text?: string;\n [key: string]: unknown;\n}\n\ninterface MastraMessage {\n role: string;\n content: string | MastraContent[];\n}\n\ninterface MastraContent {\n type: string;\n text?: string;\n [key: string]: unknown;\n}\n\ntype SpanData = string | MastraMessage[] | Record<string, unknown> | unknown;\n\nconst DISTINCT_ID = 'distinctId';\n/** Per-trace key prefix for the provider calls and tool results recorded under one MODEL_GENERATION. */\nconst CONVERSATION = 'conversation:';\n\n/** Ended spans under one MODEL_GENERATION, used to rebuild each provider call's `$ai_input`. */\ninterface Conversation {\n /** Ended MODEL_INFERENCE spans, in the order they ended. */\n calls: AnyExportedSpan[];\n /** Ended TOOL_CALL / MCP_TOOL_CALL spans and PROVIDER_TOOL_CALL spans with a result, keyed by toolCallId. */\n toolResults: Map<string, AnyExportedSpan>;\n}\n\nexport interface PosthogExporterConfig extends TrackingExporterConfig {\n /** PostHog API key. Defaults to POSTHOG_API_KEY environment variable. */\n apiKey?: string;\n /** PostHog host URL. Defaults to POSTHOG_HOST environment variable or US region. */\n host?: string;\n flushAt?: number;\n flushInterval?: number;\n serverless?: boolean;\n defaultDistinctId?: string;\n enablePrivacyMode?: boolean;\n}\n\ntype PosthogRoot = unknown;\ntype PosthogSpan = AnyExportedSpan;\n// used as a placeholder for event data since we don't need to cache\n// event data for Posthog\ntype PosthogEvent = boolean;\ntype PosthogMetadata = unknown;\ntype PosthogTraceData = TraceData<PosthogRoot, PosthogSpan, PosthogEvent, PosthogMetadata>;\n\nexport class PosthogExporter extends TrackingExporter<\n PosthogRoot,\n PosthogSpan,\n PosthogEvent,\n PosthogMetadata,\n PosthogExporterConfig\n> {\n name = 'posthog';\n #client: PostHog | undefined;\n\n private static readonly SERVERLESS_FLUSH_AT = 10;\n private static readonly SERVERLESS_FLUSH_INTERVAL = 2000;\n private static readonly DEFAULT_FLUSH_AT = 20;\n private static readonly DEFAULT_FLUSH_INTERVAL = 10000;\n\n constructor(config: PosthogExporterConfig = {}) {\n // Resolve env vars BEFORE calling super (config is readonly in base class)\n const apiKey = config.apiKey ?? process.env.POSTHOG_API_KEY;\n\n super({ ...config, apiKey });\n\n if (!apiKey) {\n this.setDisabled('Missing required API key. Set POSTHOG_API_KEY environment variable or pass apiKey in config.');\n return;\n }\n\n const clientConfig = this.buildClientConfig(this.config);\n this.#client = new PostHog(apiKey, clientConfig);\n const message =\n (config.serverless ?? false) ? 'PostHog exporter initialized in serverless mode' : 'PostHog exporter initialized';\n this.logger.debug(message, config);\n }\n\n private buildClientConfig(config: PosthogExporterConfig) {\n const isServerless = config.serverless ?? false;\n const flushAt =\n config.flushAt ?? (isServerless ? PosthogExporter.SERVERLESS_FLUSH_AT : PosthogExporter.DEFAULT_FLUSH_AT);\n const flushInterval =\n config.flushInterval ??\n (isServerless ? PosthogExporter.SERVERLESS_FLUSH_INTERVAL : PosthogExporter.DEFAULT_FLUSH_INTERVAL);\n\n const host = config.host || process.env.POSTHOG_HOST || 'https://us.i.posthog.com';\n\n if (!config.host && !process.env.POSTHOG_HOST) {\n this.logger.info(\n 'No PostHog host specified, using US default (https://us.i.posthog.com). ' +\n 'For EU region, set `host: \"https://eu.i.posthog.com\"` in config or POSTHOG_HOST env var. ' +\n 'For self-hosted, provide your instance URL.',\n );\n }\n\n return {\n host,\n flushAt,\n flushInterval,\n privacyMode: config.enablePrivacyMode,\n };\n }\n\n protected override skipBuildRootTask = true;\n protected override async _buildRoot(_args: {\n span: AnyExportedSpan;\n traceData: PosthogTraceData;\n }): Promise<PosthogRoot | undefined> {\n throw new Error('Method not implemented.');\n }\n\n protected override skipCachingEventSpans = true;\n protected override async _buildEvent(args: {\n span: AnyExportedSpan;\n traceData: PosthogTraceData;\n }): Promise<PosthogEvent> {\n const { span, traceData } = args;\n\n const isModelCall = this.isModelCall(span);\n const distinctId = this.getDistinctId(span, traceData);\n const properties = this.buildEventProperties(span, 0, false, isModelCall);\n\n // captureAi() targets PostHog's dedicated AI endpoint (8 MiB per event, oversized events\n // dropped individually). Plain capture() uses /batch/, which returns 413 for large spans.\n this.#client?.captureAi(\n this.withGroups({\n distinctId,\n event: isModelCall ? '$ai_generation' : '$ai_span',\n properties,\n timestamp: span.endTime ? new Date(span.endTime) : new Date(),\n }),\n );\n\n return true;\n }\n\n protected override async _buildSpan(args: {\n span: AnyExportedSpan;\n traceData: PosthogTraceData;\n }): Promise<PosthogSpan | undefined> {\n const { span, traceData } = args;\n if (!traceData.hasExtraValue(DISTINCT_ID)) {\n const userId = span.metadata?.userId;\n if (userId) {\n traceData.setExtraValue(DISTINCT_ID, String(userId));\n }\n }\n\n return span;\n }\n\n protected override skipSpanUpdateEvents = true;\n protected override _updateSpan(_args: { span: AnyExportedSpan; traceData: PosthogTraceData }): Promise<void> {\n throw new Error('Method not implemented.');\n }\n\n protected override async _finishSpan(args: { span: AnyExportedSpan; traceData: PosthogTraceData }): Promise<void> {\n const { span, traceData } = args;\n\n // Merge input from cached span (SPAN_STARTED) if not present on end span\n // This handles the case where input is only sent at start\n const cachedSpan = traceData.getSpan({ spanId: span.id });\n const mergedSpan = !span.input && cachedSpan?.input ? { ...span, input: cachedSpan.input } : span;\n\n const eventMessage = this.buildEventMessage({ span: this.withCallInput(mergedSpan, traceData), traceData });\n this.#client?.captureAi(this.withGroups(eventMessage));\n\n this.recordForConversation(span, traceData);\n }\n\n protected override async _abortSpan(args: {\n span: PosthogSpan;\n reason: SpanErrorInfo;\n traceData: PosthogTraceData;\n }): Promise<void> {\n const { span, reason, traceData } = args;\n\n // update span with the abort reason\n span.errorInfo = reason;\n\n const eventMessage = this.buildEventMessage({ span: this.withCallInput(span, traceData), traceData });\n this.#client?.captureAi(this.withGroups(eventMessage));\n }\n\n /**\n * Forward feedback recorded via `addFeedback()` to PostHog as a native\n * `$ai_feedback` event, shown as \"User feedback\" on the linked trace in\n * PostHog's AI observability UI.\n */\n async onFeedbackEvent(event: FeedbackEvent): Promise<void> {\n if (!this.#client) return;\n\n const { feedback } = event;\n if (!feedback.traceId) {\n this.logger.debug('PostHog exporter: dropping feedback with no traceId; PostHog requires $ai_trace_id', {\n feedbackId: feedback.feedbackId,\n });\n return;\n }\n\n const properties: Record<string, any> = {\n // Custom metadata goes first so it cannot overwrite the natively mapped fields below\n ...this.extractCustomMetadata(feedback.metadata),\n $ai_trace_id: feedback.traceId,\n // PostHog's trace UI only displays feedback events that carry $ai_feedback_text\n $ai_feedback_text: feedback.comment ?? String(feedback.value),\n feedback_id: feedback.feedbackId,\n feedback_type: feedback.feedbackType,\n feedback_value: feedback.value,\n };\n\n const feedbackSource = feedback.feedbackSource ?? feedback.source;\n if (feedbackSource) properties.feedback_source = feedbackSource;\n if (feedback.spanId) properties.span_id = feedback.spanId;\n if (feedback.sourceId) properties.source_id = feedback.sourceId;\n if (feedback.metadata?.sessionId) properties.$ai_session_id = feedback.metadata.sessionId;\n\n try {\n this.#client.captureAi(\n this.withGroups({\n distinctId: this.getFeedbackDistinctId(feedback),\n event: '$ai_feedback',\n properties,\n timestamp: new Date(feedback.timestamp),\n }),\n );\n } catch (err) {\n this.logger.error('PostHog exporter: failed to submit feedback', {\n error: err,\n traceId: feedback.traceId,\n feedbackId: feedback.feedbackId,\n });\n }\n }\n\n private getFeedbackDistinctId(feedback: ExportedFeedback): string {\n const userId = feedback.feedbackUserId ?? feedback.userId ?? feedback.metadata?.userId;\n if (userId) {\n return String(userId);\n }\n return this.config.defaultDistinctId ?? 'anonymous';\n }\n\n /**\n * PostHog group analytics are keyed off the top-level `groups` field on the\n * capture call. The Node SDK derives the event's `$groups` from that field and\n * overwrites any property-level `$groups`, so group metadata carried in\n * properties is dropped unless it is mirrored here.\n */\n private withGroups(message: EventMessage): EventMessage {\n const groups = message.properties?.$groups;\n if (groups && typeof groups === 'object' && !Array.isArray(groups)) {\n return { ...message, groups };\n }\n return message;\n }\n\n private buildEventMessage(args: { span: AnyExportedSpan; traceData: PosthogTraceData }): EventMessage {\n const { span, traceData } = args;\n\n const endTime = span.endTime ? this.toDate(span.endTime).getTime() : Date.now();\n\n const distinctId = this.getDistinctId(span, traceData);\n\n if (span.isRootSpan) {\n return this.buildRootEventMessage({ span, distinctId, endTime });\n } else {\n return this.buildChildEventMessage({ span, distinctId, endTime, traceData });\n }\n }\n\n /**\n * Capture an explicit $ai_trace event for root spans.\n * This gives us control over trace-level metadata like name and tags,\n * rather than relying on PostHog's pseudo-trace auto-creation.\n */\n private buildRootEventMessage(args: { span: AnyExportedSpan; distinctId: string; endTime: number }): EventMessage {\n const { span, distinctId, endTime } = args;\n\n // Note: We don't set $ai_latency on $ai_trace events because PostHog\n // aggregates latency from child events. Setting it here causes double-counting.\n const traceProperties: Record<string, any> = {\n $ai_trace_id: span.traceId,\n $ai_span_name: span.name,\n $ai_is_error: !!span.errorInfo,\n };\n\n if (span.metadata?.sessionId) {\n traceProperties.$ai_session_id = span.metadata.sessionId;\n }\n\n if (span.input) {\n traceProperties.$ai_input_state = span.input;\n }\n\n if (span.output) {\n traceProperties.$ai_output_state = span.output;\n }\n\n if (span.errorInfo) {\n traceProperties.$ai_error = {\n message: span.errorInfo.message,\n ...(span.errorInfo.id && { id: span.errorInfo.id }),\n ...(span.errorInfo.category && { category: span.errorInfo.category }),\n };\n }\n\n // Add tags as custom properties (PostHog doesn't have native tag support on traces)\n if (span.tags?.length) {\n for (const tag of span.tags) {\n traceProperties[tag] = true;\n }\n }\n\n // Add custom metadata (excluding userId and sessionId which are handled separately)\n const { userId, sessionId, ...customMetadata } = span.metadata ?? {};\n Object.assign(traceProperties, customMetadata);\n\n return {\n distinctId,\n event: '$ai_trace',\n properties: traceProperties,\n timestamp: new Date(endTime),\n };\n }\n\n private buildChildEventMessage(args: {\n span: AnyExportedSpan;\n distinctId: string;\n endTime: number;\n traceData: PosthogTraceData;\n }): EventMessage {\n const { span, distinctId, endTime, traceData } = args;\n\n const isModelCall = this.isModelCall(span);\n const startTime = span.startTime.getTime();\n const latency = (endTime - startTime) / 1000;\n\n // Check if parent is the root span - if so, use traceId as parent_id\n // since we don't create an $ai_span for root spans\n const parentIsRootSpan = this.isParentRootSpan(span, traceData);\n const properties = this.buildEventProperties(span, latency, parentIsRootSpan, isModelCall);\n\n return {\n distinctId,\n event: isModelCall ? '$ai_generation' : '$ai_span',\n properties,\n timestamp: new Date(endTime),\n };\n }\n\n private toDate(timestamp: Date | number): Date {\n return timestamp instanceof Date ? timestamp : new Date(timestamp);\n }\n\n /**\n * Whether this span is exported as `$ai_generation`. PostHog expects one per\n * provider call and sums tokens and cost across them, so exactly one span\n * per call may carry usage. With paired packages that emit MODEL_INFERENCE,\n * that is the call and MODEL_GENERATION is the loop around it, exported as\n * `$ai_span`. Older pairings only emit MODEL_GENERATION, which keeps the\n * `$ai_generation` role.\n */\n private isModelCall(span: AnyExportedSpan): boolean {\n return span.type === (isModelInferenceEnabled() ? SpanType.MODEL_INFERENCE : SpanType.MODEL_GENERATION);\n }\n\n /**\n * Give a MODEL_INFERENCE exported as `$ai_generation` the conversation that\n * call received. The span has no input of its own, so it is rebuilt from the\n * generation's input plus, for each earlier call in the same generation, its\n * output and the results of the tools it called (as Braintrust's Thread view\n * does). Earlier calls and their tools end before this call does, so they are\n * already recorded.\n */\n private withCallInput(span: AnyExportedSpan, traceData: PosthogTraceData): AnyExportedSpan {\n if (span.type !== SpanType.MODEL_INFERENCE || !this.isModelCall(span)) return span;\n\n const generation = this.findGeneration(span, traceData);\n if (!generation?.input) return span;\n\n const messages = this.formatMessages(generation.input, 'user');\n const conversation = traceData.getExtraValue(CONVERSATION + generation.id) as Conversation | undefined;\n for (const call of conversation?.calls ?? []) {\n const output = call.output as\n | { text?: string; toolCalls?: Array<{ toolCallId: string; toolName: string }> }\n | undefined;\n if (!output?.text && !output?.toolCalls?.length) continue;\n messages.push(...this.formatMessages(output, 'assistant'));\n\n // Parallel tool calls are ordered by when each tool started.\n const results = (output.toolCalls ?? [])\n .map(toolCall => ({ toolCall, toolSpan: conversation!.toolResults.get(toolCall.toolCallId) }))\n .filter(\n (result): result is { toolCall: typeof result.toolCall; toolSpan: AnyExportedSpan } => !!result.toolSpan,\n )\n .sort((a, b) => this.toDate(a.toolSpan.startTime).getTime() - this.toDate(b.toolSpan.startTime).getTime());\n for (const { toolCall, toolSpan } of results) {\n // Provider-executed tools report failure through `success`, not `errorInfo`.\n const isError =\n !!toolSpan.errorInfo ||\n (toolSpan.type === SpanType.PROVIDER_TOOL_CALL &&\n (toolSpan.attributes as { success?: boolean } | undefined)?.success === false);\n // Same `tool-result` part shape PostHog's own AI SDK integrations send.\n messages.push({\n role: 'tool',\n content: [\n {\n type: 'tool-result',\n toolCallId: toolCall.toolCallId,\n toolName: toolCall.toolName,\n output: toolSpan.errorInfo ? toolSpan.errorInfo.message : toolSpan.output,\n ...(isError ? { isError: true } : {}),\n },\n ],\n });\n }\n }\n\n return { ...span, input: messages };\n }\n\n /** Record ended calls and tool results so later calls in the same generation can rebuild their input. */\n private recordForConversation(span: AnyExportedSpan, traceData: PosthogTraceData): void {\n const isCall = span.type === SpanType.MODEL_INFERENCE && !span.errorInfo;\n // A PROVIDER_TOOL_CALL span ended without a result (e.g. the run stopped first)\n // has no `success`, and recording it would add an empty result.\n const isProviderToolWithResult =\n span.type === SpanType.PROVIDER_TOOL_CALL &&\n typeof (span.attributes as { success?: unknown } | undefined)?.success === 'boolean';\n const isTool = span.type === SpanType.TOOL_CALL || span.type === SpanType.MCP_TOOL_CALL || isProviderToolWithResult;\n if (!isModelInferenceEnabled() || (!isCall && !isTool)) return;\n\n const generation = this.findGeneration(span, traceData);\n if (!generation) return;\n\n const key = CONVERSATION + generation.id;\n let conversation = traceData.getExtraValue(key) as Conversation | undefined;\n if (!conversation) {\n conversation = { calls: [], toolResults: new Map() };\n traceData.setExtraValue(key, conversation);\n }\n if (isCall) {\n conversation.calls.push(span);\n } else {\n const toolCallId = this.resolveToolCallId(span);\n if (toolCallId) conversation.toolResults.set(toolCallId, span);\n }\n }\n\n private findGeneration(span: AnyExportedSpan, traceData: PosthogTraceData): AnyExportedSpan | undefined {\n let ancestor = span.parentSpanId ? traceData.getSpan({ spanId: span.parentSpanId }) : undefined;\n while (ancestor && ancestor.type !== SpanType.MODEL_GENERATION) {\n ancestor = ancestor.parentSpanId ? traceData.getSpan({ spanId: ancestor.parentSpanId }) : undefined;\n }\n return ancestor;\n }\n\n private resolveToolCallId(span: AnyExportedSpan): string | undefined {\n const attrs = span.attributes as { toolCallId?: string } | undefined;\n return (\n attrs?.toolCallId ??\n (span.metadata?.toolCallId as string | undefined) ??\n (span.input as { toolCallId?: string } | undefined)?.toolCallId\n );\n }\n\n private getDistinctId(span: AnyExportedSpan, traceData?: PosthogTraceData): string {\n if (span.metadata?.userId) {\n return String(span.metadata.userId);\n }\n\n if (traceData?.hasExtraValue(DISTINCT_ID)) {\n return String(traceData.getExtraValue(DISTINCT_ID));\n }\n\n if (this.config.defaultDistinctId) {\n return this.config.defaultDistinctId;\n }\n\n return 'anonymous';\n }\n\n /**\n * Check if the parent of this span is the root span.\n * We need this because we don't create $ai_span for root spans,\n * so children of root spans should use $ai_trace_id as their $ai_parent_id.\n */\n private isParentRootSpan(span: AnyExportedSpan, traceData: PosthogTraceData): boolean {\n if (!span.parentSpanId) {\n return false;\n }\n\n // Look up the parent span in our cache to check if it's a root span\n const parentCache = traceData.getSpan({ spanId: span.parentSpanId });\n if (parentCache) {\n return parentCache.isRootSpan;\n }\n\n // Parent not found in cache - shouldn't happen normally, but default to false\n return false;\n }\n\n private buildEventProperties(\n span: AnyExportedSpan,\n latency: number,\n parentIsRootSpan: boolean = false,\n isModelCall: boolean = this.isModelCall(span),\n ): Record<string, any> {\n const baseProperties: Record<string, any> = {\n $ai_trace_id: span.traceId,\n $ai_latency: latency,\n $ai_is_error: !!span.errorInfo,\n };\n\n if (span.parentSpanId) {\n // If parent is the root span, use trace_id as parent_id since we don't\n // create an $ai_span for root spans (only $ai_trace)\n baseProperties.$ai_parent_id = parentIsRootSpan ? span.traceId : span.parentSpanId;\n }\n\n if (span.metadata?.sessionId) {\n baseProperties.$ai_session_id = span.metadata.sessionId;\n }\n\n // Include tags for root spans (tags are only set on root spans by design)\n // PostHog doesn't allow setting tags directly, so we iterate through each tag\n // and set it as a property with value true\n if (span.isRootSpan && span.tags?.length) {\n for (const tag of span.tags) {\n baseProperties[tag] = true;\n }\n }\n\n if (isModelCall) {\n baseProperties.$ai_generation_id = span.id;\n return { ...baseProperties, ...this.buildGenerationProperties(span) };\n } else {\n baseProperties.$ai_span_id = span.id;\n baseProperties.$ai_span_name = span.name;\n return { ...baseProperties, ...this.buildSpanProperties(span) };\n }\n }\n\n private extractErrorProperties(errorInfo?: SpanErrorInfo): Record<string, any> {\n if (!errorInfo) {\n return {};\n }\n\n const props: Record<string, string> = {\n error_message: errorInfo.message,\n };\n\n if (errorInfo.id) {\n props.error_id = errorInfo.id;\n }\n\n if (errorInfo.category) {\n props.error_category = errorInfo.category;\n }\n\n return props;\n }\n\n private extractCustomMetadata(metadata?: Record<string, unknown>): Record<string, any> {\n const { userId, sessionId, ...customMetadata } = metadata ?? {};\n return customMetadata;\n }\n\n private buildGenerationProperties(span: AnyExportedSpan): Record<string, any> {\n const props: Record<string, any> = {};\n const attrs = (span.attributes ?? {}) as ModelGenerationAttributes;\n\n props.$ai_model = attrs.model || 'unknown-model';\n props.$ai_provider = attrs.provider || 'unknown-provider';\n\n if (span.input) props.$ai_input = this.formatMessages(span.input, 'user');\n if (span.output) props.$ai_output_choices = this.formatMessages(span.output, 'assistant');\n\n // Extract usage properties using the shared utility\n Object.assign(props, formatUsageMetrics(attrs.usage));\n\n if (attrs.parameters) {\n if (attrs.parameters.temperature !== undefined) props.$ai_temperature = attrs.parameters.temperature;\n if (attrs.parameters.maxOutputTokens !== undefined) props.$ai_max_tokens = attrs.parameters.maxOutputTokens;\n }\n if (attrs.streaming !== undefined) props.$ai_stream = attrs.streaming;\n if (attrs.tools?.length) {\n // OpenAI-style shape — the format PostHog's own AI SDKs send and its\n // trace view renders. Provider-defined tools pass through as-is.\n props.$ai_tools = attrs.tools.map(tool =>\n tool.type === 'function'\n ? {\n type: 'function',\n function: { name: tool.name, description: tool.description, parameters: tool.parameters },\n }\n : tool,\n );\n }\n\n return { ...props, ...this.extractErrorProperties(span.errorInfo), ...this.extractCustomMetadata(span.metadata) };\n }\n\n private buildSpanProperties(span: AnyExportedSpan): Record<string, any> {\n const props: Record<string, any> = {};\n\n if (span.input) props.$ai_input_state = span.input;\n if (span.output) props.$ai_output_state = span.output;\n\n if (span.type === SpanType.MODEL_CHUNK) {\n const attrs = span.attributes as any;\n if (attrs?.chunkType) props.chunk_type = attrs.chunkType;\n if (attrs?.sequenceNumber !== undefined) props.chunk_sequence_number = attrs.sequenceNumber;\n }\n\n if (span.attributes) {\n Object.assign(props, span.attributes);\n }\n\n return { ...props, ...this.extractErrorProperties(span.errorInfo), ...this.extractCustomMetadata(span.metadata) };\n }\n\n private formatMessages(data: SpanData, defaultRole: 'user' | 'assistant' = 'user'): PostHogMessage[] {\n // Unwrap {messages: [...]} wrapper produced by generation span inputs\n if (typeof data === 'object' && data !== null && !Array.isArray(data) && 'messages' in data) {\n const wrapped = (data as Record<string, unknown>).messages;\n if (this.isMessageArray(wrapped)) {\n return wrapped.map(msg => this.normalizeMessage(msg));\n }\n }\n\n if (this.isMessageArray(data)) {\n return data.map(msg => this.normalizeMessage(msg));\n }\n\n if (typeof data === 'string') {\n return [{ role: defaultRole, content: [{ type: 'text', text: data }] }];\n }\n\n if (this.isSpanOutputWithToolCalls(data)) {\n const content: PostHogContent[] = [];\n if (data.text) {\n content.push({ type: 'text', text: data.text });\n }\n for (const tc of data.toolCalls) {\n content.push({\n type: 'tool-call',\n id: tc.toolCallId,\n function: { name: tc.toolName, arguments: tc.args },\n });\n }\n return [{ role: 'assistant', content }];\n }\n\n // Extract text from output objects (e.g. generation outputs with text but no tool calls)\n if (typeof data === 'object' && data !== null && !Array.isArray(data) && 'text' in data) {\n const text = (data as Record<string, unknown>).text;\n if (typeof text === 'string') {\n return [{ role: defaultRole, content: [{ type: 'text', text }] }];\n }\n }\n\n return [{ role: defaultRole, content: [{ type: 'text', text: this.safeStringify(data) }] }];\n }\n\n private isSpanOutputWithToolCalls(\n data: unknown,\n ): data is { text?: string; toolCalls: Array<{ toolCallId: string; toolName: string; args: unknown }> } {\n if (typeof data !== 'object' || data === null || !('toolCalls' in data)) return false;\n const { toolCalls } = data as Record<string, unknown>;\n return Array.isArray(toolCalls) && toolCalls.length > 0;\n }\n\n private isMessageArray(data: unknown): data is MastraMessage[] {\n if (!Array.isArray(data)) {\n return false;\n }\n\n return data.every(item => typeof item === 'object' && item !== null && 'role' in item && 'content' in item);\n }\n\n private normalizeMessage(msg: MastraMessage): PostHogMessage {\n if (typeof msg.content === 'string') {\n return {\n role: msg.role as PostHogMessage['role'],\n content: [{ type: 'text', text: msg.content }],\n };\n }\n\n return {\n role: msg.role as PostHogMessage['role'],\n content: msg.content as PostHogContent[],\n };\n }\n\n private safeStringify(data: unknown): string {\n try {\n return JSON.stringify(data);\n } catch {\n if (typeof data === 'object' && data !== null) {\n return `[Non-serializable ${data.constructor?.name || 'Object'}]`;\n }\n return String(data);\n }\n }\n\n /**\n * Force flush any buffered data to PostHog without shutting down.\n */\n protected override async _flush(): Promise<void> {\n if (this.#client) {\n await this.#client.flush();\n }\n }\n\n override async _postShutdown(): Promise<void> {\n if (this.#client) {\n await this.#client.shutdown();\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["observability","coreFeatures","TrackingExporter","#client","PostHog","SpanType"],"sources":["../src/features.ts","../src/tracing.ts"],"sourcesContent":["/**\n * Feature detection for paired @mastra/core and @mastra/observability versions.\n *\n * Both are resolved synchronously so span classification is stable from the\n * very first span, without depending on a pending dynamic import.\n *\n * `@mastra/observability` is a hard dependency, but older versions do not\n * export `observabilityFeatures`. The namespace import reads it as `undefined`\n * in that case instead of failing to link, which is the graceful fallback\n * documented in `observability/mastra/src/features.ts`.\n */\n\nimport { coreFeatures } from '@mastra/core/features';\nimport * as observability from '@mastra/observability';\n\nconst FEATURE = 'model-inference-span';\n\nlet observabilityFeatures: ReadonlySet<string> | undefined = (\n observability as { observabilityFeatures?: ReadonlySet<string> }\n).observabilityFeatures;\n\n/**\n * Returns true when both packages report the `model-inference-span` feature,\n * meaning MODEL_INFERENCE spans are emitted by the tracker. Drives which span\n * is exported as `$ai_generation` (new: MODEL_INFERENCE; legacy:\n * MODEL_GENERATION).\n */\nexport function isModelInferenceEnabled(): boolean {\n return observabilityFeatures?.has(FEATURE) === true && coreFeatures.has(FEATURE);\n}\n\n/**\n * @internal Test-only override. Allows tests to simulate a paired older or\n * newer `@mastra/observability` without juggling module mocks.\n */\nexport function __setObservabilityFeaturesForTest(features: ReadonlySet<string> | undefined): void {\n observabilityFeatures = features;\n}\n","import type {\n AnyExportedSpan,\n ExportedFeedback,\n FeedbackEvent,\n ModelGenerationAttributes,\n SpanErrorInfo,\n UsageStats,\n} from '@mastra/core/observability';\nimport { SpanType } from '@mastra/core/observability';\nimport type { TraceData, TrackingExporterConfig } from '@mastra/observability';\nimport { TrackingExporter } from '@mastra/observability';\nimport { PostHog } from 'posthog-node';\nimport type { EventMessage } from 'posthog-node';\nimport { isModelInferenceEnabled } from './features';\n\n/**\n * Token usage format compatible with PostHog.\n * @see https://posthog.com/docs/llm-analytics/generations#event-properties\n */\nexport interface PostHogUsageMetrics {\n $ai_input_tokens?: number;\n $ai_output_tokens?: number;\n $ai_cache_read_input_tokens?: number;\n $ai_cache_creation_input_tokens?: number;\n $ai_cache_creation_5m_input_tokens?: number;\n $ai_cache_creation_1h_input_tokens?: number;\n}\n\n/**\n * Formats UsageStats to PostHog's expected property format.\n *\n * Pass through gross input token counts with cache fields as subsets.\n * PostHog subtracts cache tokens when computing costs for non-Anthropic\n * providers and detects Anthropic-style exclusive reporting on its own.\n *\n * @param usage - The UsageStats from span attributes\n * @returns PostHog-formatted usage properties\n */\nexport function formatUsageMetrics(usage?: UsageStats): PostHogUsageMetrics {\n if (!usage) return {};\n\n const props: PostHogUsageMetrics = {};\n\n if (usage.inputTokens !== undefined) {\n props.$ai_input_tokens = usage.inputTokens;\n }\n\n if (usage.inputDetails?.cacheRead !== undefined) {\n props.$ai_cache_read_input_tokens = usage.inputDetails.cacheRead;\n }\n\n if (usage.inputDetails?.cacheWrite !== undefined) {\n props.$ai_cache_creation_input_tokens = usage.inputDetails.cacheWrite;\n }\n if (usage.inputDetails?.cacheWrite5m !== undefined) {\n props.$ai_cache_creation_5m_input_tokens = usage.inputDetails.cacheWrite5m;\n }\n if (usage.inputDetails?.cacheWrite1h !== undefined) {\n props.$ai_cache_creation_1h_input_tokens = usage.inputDetails.cacheWrite1h;\n }\n\n if (usage.outputTokens !== undefined) {\n props.$ai_output_tokens = usage.outputTokens;\n }\n\n return props;\n}\n\ninterface PostHogMessage {\n role: 'user' | 'assistant' | 'system' | 'tool';\n content: PostHogContent[];\n}\n\ninterface PostHogContent {\n type: string;\n text?: string;\n [key: string]: unknown;\n}\n\ninterface MastraMessage {\n role: string;\n content: string | MastraContent[];\n}\n\ninterface MastraContent {\n type: string;\n text?: string;\n [key: string]: unknown;\n}\n\ntype SpanData = string | MastraMessage[] | Record<string, unknown> | unknown;\n\nconst DISTINCT_ID = 'distinctId';\n/** Per-trace key prefix for the provider calls and tool results recorded under one MODEL_GENERATION. */\nconst CONVERSATION = 'conversation:';\n\n/** Ended spans under one MODEL_GENERATION, used to rebuild each provider call's `$ai_input`. */\ninterface Conversation {\n /** Ended MODEL_INFERENCE spans, in the order they ended. */\n calls: AnyExportedSpan[];\n /** Ended TOOL_CALL / MCP_TOOL_CALL spans and PROVIDER_TOOL_CALL spans with a result, keyed by toolCallId. */\n toolResults: Map<string, AnyExportedSpan>;\n}\n\nexport interface PosthogExporterConfig extends TrackingExporterConfig {\n /** PostHog API key. Defaults to POSTHOG_API_KEY environment variable. */\n apiKey?: string;\n /** PostHog host URL. Defaults to POSTHOG_HOST environment variable or US region. */\n host?: string;\n flushAt?: number;\n flushInterval?: number;\n serverless?: boolean;\n defaultDistinctId?: string;\n enablePrivacyMode?: boolean;\n}\n\ntype PosthogRoot = unknown;\ntype PosthogSpan = AnyExportedSpan;\n// used as a placeholder for event data since we don't need to cache\n// event data for Posthog\ntype PosthogEvent = boolean;\ntype PosthogMetadata = unknown;\ntype PosthogTraceData = TraceData<PosthogRoot, PosthogSpan, PosthogEvent, PosthogMetadata>;\n\nexport class PosthogExporter extends TrackingExporter<\n PosthogRoot,\n PosthogSpan,\n PosthogEvent,\n PosthogMetadata,\n PosthogExporterConfig\n> {\n name = 'posthog';\n #client: PostHog | undefined;\n\n private static readonly SERVERLESS_FLUSH_AT = 10;\n private static readonly SERVERLESS_FLUSH_INTERVAL = 2000;\n private static readonly DEFAULT_FLUSH_AT = 20;\n private static readonly DEFAULT_FLUSH_INTERVAL = 10000;\n\n constructor(config: PosthogExporterConfig = {}) {\n // Resolve env vars BEFORE calling super (config is readonly in base class)\n const apiKey = config.apiKey ?? process.env.POSTHOG_API_KEY;\n\n super({ ...config, apiKey });\n\n if (!apiKey) {\n this.setDisabled('Missing required API key. Set POSTHOG_API_KEY environment variable or pass apiKey in config.');\n return;\n }\n\n const clientConfig = this.buildClientConfig(this.config);\n this.#client = new PostHog(apiKey, clientConfig);\n const message =\n (config.serverless ?? false) ? 'PostHog exporter initialized in serverless mode' : 'PostHog exporter initialized';\n this.logger.debug(message, config);\n }\n\n private buildClientConfig(config: PosthogExporterConfig) {\n const isServerless = config.serverless ?? false;\n const flushAt =\n config.flushAt ?? (isServerless ? PosthogExporter.SERVERLESS_FLUSH_AT : PosthogExporter.DEFAULT_FLUSH_AT);\n const flushInterval =\n config.flushInterval ??\n (isServerless ? PosthogExporter.SERVERLESS_FLUSH_INTERVAL : PosthogExporter.DEFAULT_FLUSH_INTERVAL);\n\n const host = config.host || process.env.POSTHOG_HOST || 'https://us.i.posthog.com';\n\n if (!config.host && !process.env.POSTHOG_HOST) {\n this.logger.info(\n 'No PostHog host specified, using US default (https://us.i.posthog.com). ' +\n 'For EU region, set `host: \"https://eu.i.posthog.com\"` in config or POSTHOG_HOST env var. ' +\n 'For self-hosted, provide your instance URL.',\n );\n }\n\n return {\n host,\n flushAt,\n flushInterval,\n privacyMode: config.enablePrivacyMode,\n };\n }\n\n protected override skipBuildRootTask = true;\n protected override async _buildRoot(_args: {\n span: AnyExportedSpan;\n traceData: PosthogTraceData;\n }): Promise<PosthogRoot | undefined> {\n throw new Error('Method not implemented.');\n }\n\n protected override skipCachingEventSpans = true;\n protected override async _buildEvent(args: {\n span: AnyExportedSpan;\n traceData: PosthogTraceData;\n }): Promise<PosthogEvent> {\n const { span, traceData } = args;\n\n const isModelCall = this.isModelCall(span);\n const distinctId = this.getDistinctId(span, traceData);\n const properties = this.buildEventProperties(span, 0, false, isModelCall);\n\n // captureAi() targets PostHog's dedicated AI endpoint (8 MiB per event, oversized events\n // dropped individually). Plain capture() uses /batch/, which returns 413 for large spans.\n this.#client?.captureAi(\n this.withGroups({\n distinctId,\n event: isModelCall ? '$ai_generation' : '$ai_span',\n properties,\n timestamp: span.endTime ? new Date(span.endTime) : new Date(),\n }),\n );\n\n return true;\n }\n\n protected override async _buildSpan(args: {\n span: AnyExportedSpan;\n traceData: PosthogTraceData;\n }): Promise<PosthogSpan | undefined> {\n const { span, traceData } = args;\n if (!traceData.hasExtraValue(DISTINCT_ID)) {\n const userId = span.metadata?.userId;\n if (userId) {\n traceData.setExtraValue(DISTINCT_ID, String(userId));\n }\n }\n\n return span;\n }\n\n protected override skipSpanUpdateEvents = true;\n protected override _updateSpan(_args: { span: AnyExportedSpan; traceData: PosthogTraceData }): Promise<void> {\n throw new Error('Method not implemented.');\n }\n\n protected override async _finishSpan(args: { span: AnyExportedSpan; traceData: PosthogTraceData }): Promise<void> {\n const { span, traceData } = args;\n\n // Merge input from cached span (SPAN_STARTED) if not present on end span\n // This handles the case where input is only sent at start\n const cachedSpan = traceData.getSpan({ spanId: span.id });\n const mergedSpan = !span.input && cachedSpan?.input ? { ...span, input: cachedSpan.input } : span;\n\n const eventMessage = this.buildEventMessage({ span: this.withCallInput(mergedSpan, traceData), traceData });\n this.#client?.captureAi(this.withGroups(eventMessage));\n\n this.recordForConversation(span, traceData);\n }\n\n protected override async _abortSpan(args: {\n span: PosthogSpan;\n reason: SpanErrorInfo;\n traceData: PosthogTraceData;\n }): Promise<void> {\n const { span, reason, traceData } = args;\n\n // update span with the abort reason\n span.errorInfo = reason;\n\n const eventMessage = this.buildEventMessage({ span: this.withCallInput(span, traceData), traceData });\n this.#client?.captureAi(this.withGroups(eventMessage));\n }\n\n /**\n * Forward feedback recorded via `addFeedback()` to PostHog as a native\n * `$ai_feedback` event, shown as \"User feedback\" on the linked trace in\n * PostHog's AI observability UI.\n */\n async onFeedbackEvent(event: FeedbackEvent): Promise<void> {\n if (!this.#client) return;\n\n const { feedback } = event;\n if (!feedback.traceId) {\n this.logger.debug('PostHog exporter: dropping feedback with no traceId; PostHog requires $ai_trace_id', {\n feedbackId: feedback.feedbackId,\n });\n return;\n }\n\n const properties: Record<string, any> = {\n // Custom metadata goes first so it cannot overwrite the natively mapped fields below\n ...this.extractCustomMetadata(feedback.metadata),\n $ai_trace_id: feedback.traceId,\n // PostHog's trace UI only displays feedback events that carry $ai_feedback_text\n $ai_feedback_text: feedback.comment ?? String(feedback.value),\n feedback_id: feedback.feedbackId,\n feedback_type: feedback.feedbackType,\n feedback_value: feedback.value,\n };\n\n const feedbackSource = feedback.feedbackSource ?? feedback.source;\n if (feedbackSource) properties.feedback_source = feedbackSource;\n if (feedback.spanId) properties.span_id = feedback.spanId;\n if (feedback.sourceId) properties.source_id = feedback.sourceId;\n if (feedback.metadata?.sessionId) properties.$ai_session_id = feedback.metadata.sessionId;\n\n try {\n this.#client.captureAi(\n this.withGroups({\n distinctId: this.getFeedbackDistinctId(feedback),\n event: '$ai_feedback',\n properties,\n timestamp: new Date(feedback.timestamp),\n }),\n );\n } catch (err) {\n this.logger.error('PostHog exporter: failed to submit feedback', {\n error: err,\n traceId: feedback.traceId,\n feedbackId: feedback.feedbackId,\n });\n }\n }\n\n private getFeedbackDistinctId(feedback: ExportedFeedback): string {\n const userId = feedback.feedbackUserId ?? feedback.userId ?? feedback.metadata?.userId;\n if (userId) {\n return String(userId);\n }\n return this.config.defaultDistinctId ?? 'anonymous';\n }\n\n /**\n * PostHog group analytics are keyed off the top-level `groups` field on the\n * capture call. The Node SDK derives the event's `$groups` from that field and\n * overwrites any property-level `$groups`, so group metadata carried in\n * properties is dropped unless it is mirrored here.\n */\n private withGroups(message: EventMessage): EventMessage {\n const groups = message.properties?.$groups;\n if (groups && typeof groups === 'object' && !Array.isArray(groups)) {\n return { ...message, groups };\n }\n return message;\n }\n\n private buildEventMessage(args: { span: AnyExportedSpan; traceData: PosthogTraceData }): EventMessage {\n const { span, traceData } = args;\n\n const endTime = span.endTime ? this.toDate(span.endTime).getTime() : Date.now();\n\n const distinctId = this.getDistinctId(span, traceData);\n\n if (span.isRootSpan) {\n return this.buildRootEventMessage({ span, distinctId, endTime });\n } else {\n return this.buildChildEventMessage({ span, distinctId, endTime, traceData });\n }\n }\n\n /**\n * Capture an explicit $ai_trace event for root spans.\n * This gives us control over trace-level metadata like name and tags,\n * rather than relying on PostHog's pseudo-trace auto-creation.\n */\n private buildRootEventMessage(args: { span: AnyExportedSpan; distinctId: string; endTime: number }): EventMessage {\n const { span, distinctId, endTime } = args;\n\n // Note: We don't set $ai_latency on $ai_trace events because PostHog\n // aggregates latency from child events. Setting it here causes double-counting.\n const traceProperties: Record<string, any> = {\n $ai_trace_id: span.traceId,\n $ai_span_name: span.name,\n $ai_is_error: !!span.errorInfo,\n };\n\n if (span.metadata?.sessionId) {\n traceProperties.$ai_session_id = span.metadata.sessionId;\n }\n\n if (span.input) {\n traceProperties.$ai_input_state = span.input;\n }\n\n if (span.output) {\n traceProperties.$ai_output_state = span.output;\n }\n\n if (span.errorInfo) {\n traceProperties.$ai_error = {\n message: span.errorInfo.message,\n ...(span.errorInfo.id && { id: span.errorInfo.id }),\n ...(span.errorInfo.category && { category: span.errorInfo.category }),\n };\n }\n\n // Add tags as custom properties (PostHog doesn't have native tag support on traces)\n if (span.tags?.length) {\n for (const tag of span.tags) {\n traceProperties[tag] = true;\n }\n }\n\n // Add custom metadata (excluding userId and sessionId which are handled separately)\n const { userId, sessionId, ...customMetadata } = span.metadata ?? {};\n Object.assign(traceProperties, customMetadata);\n\n // A served MCP request is always a root span. Keep the caller's W3C context\n // on the trace, since PostHog has no span links to point at the caller.\n if (span.type === SpanType.MCP_SERVER_REQUEST) {\n const { callerTraceparent, callerTracestate } = (span.attributes ?? {}) as {\n callerTraceparent?: string;\n callerTracestate?: string;\n };\n if (callerTraceparent) traceProperties.callerTraceparent = callerTraceparent;\n if (callerTracestate) traceProperties.callerTracestate = callerTracestate;\n }\n\n return {\n distinctId,\n event: '$ai_trace',\n properties: traceProperties,\n timestamp: new Date(endTime),\n };\n }\n\n private buildChildEventMessage(args: {\n span: AnyExportedSpan;\n distinctId: string;\n endTime: number;\n traceData: PosthogTraceData;\n }): EventMessage {\n const { span, distinctId, endTime, traceData } = args;\n\n const isModelCall = this.isModelCall(span);\n const startTime = span.startTime.getTime();\n const latency = (endTime - startTime) / 1000;\n\n // Check if parent is the root span - if so, use traceId as parent_id\n // since we don't create an $ai_span for root spans\n const parentIsRootSpan = this.isParentRootSpan(span, traceData);\n const properties = this.buildEventProperties(span, latency, parentIsRootSpan, isModelCall);\n\n return {\n distinctId,\n event: isModelCall ? '$ai_generation' : '$ai_span',\n properties,\n timestamp: new Date(endTime),\n };\n }\n\n private toDate(timestamp: Date | number): Date {\n return timestamp instanceof Date ? timestamp : new Date(timestamp);\n }\n\n /**\n * Whether this span is exported as `$ai_generation`. PostHog expects one per\n * provider call and sums tokens and cost across them, so exactly one span\n * per call may carry usage. With paired packages that emit MODEL_INFERENCE,\n * that is the call and MODEL_GENERATION is the loop around it, exported as\n * `$ai_span`. Older pairings only emit MODEL_GENERATION, which keeps the\n * `$ai_generation` role.\n */\n private isModelCall(span: AnyExportedSpan): boolean {\n return span.type === (isModelInferenceEnabled() ? SpanType.MODEL_INFERENCE : SpanType.MODEL_GENERATION);\n }\n\n /**\n * Give a MODEL_INFERENCE exported as `$ai_generation` the conversation that\n * call received. The span has no input of its own, so it is rebuilt from the\n * generation's input plus, for each earlier call in the same generation, its\n * output and the results of the tools it called (as Braintrust's Thread view\n * does). Earlier calls and their tools end before this call does, so they are\n * already recorded.\n */\n private withCallInput(span: AnyExportedSpan, traceData: PosthogTraceData): AnyExportedSpan {\n if (span.type !== SpanType.MODEL_INFERENCE || !this.isModelCall(span)) return span;\n\n const generation = this.findGeneration(span, traceData);\n if (!generation?.input) return span;\n\n const messages = this.formatMessages(generation.input, 'user');\n const conversation = traceData.getExtraValue(CONVERSATION + generation.id) as Conversation | undefined;\n for (const call of conversation?.calls ?? []) {\n const output = call.output as\n | { text?: string; toolCalls?: Array<{ toolCallId: string; toolName: string }> }\n | undefined;\n if (!output?.text && !output?.toolCalls?.length) continue;\n messages.push(...this.formatMessages(output, 'assistant'));\n\n // Parallel tool calls are ordered by when each tool started.\n const results = (output.toolCalls ?? [])\n .map(toolCall => ({ toolCall, toolSpan: conversation!.toolResults.get(toolCall.toolCallId) }))\n .filter(\n (result): result is { toolCall: typeof result.toolCall; toolSpan: AnyExportedSpan } => !!result.toolSpan,\n )\n .sort((a, b) => this.toDate(a.toolSpan.startTime).getTime() - this.toDate(b.toolSpan.startTime).getTime());\n for (const { toolCall, toolSpan } of results) {\n // Provider-executed tools report failure through `success`, not `errorInfo`.\n const isError =\n !!toolSpan.errorInfo ||\n (toolSpan.type === SpanType.PROVIDER_TOOL_CALL &&\n (toolSpan.attributes as { success?: boolean } | undefined)?.success === false);\n // Same `tool-result` part shape PostHog's own AI SDK integrations send.\n messages.push({\n role: 'tool',\n content: [\n {\n type: 'tool-result',\n toolCallId: toolCall.toolCallId,\n toolName: toolCall.toolName,\n output: toolSpan.errorInfo ? toolSpan.errorInfo.message : toolSpan.output,\n ...(isError ? { isError: true } : {}),\n },\n ],\n });\n }\n }\n\n return { ...span, input: messages };\n }\n\n /** Record ended calls and tool results so later calls in the same generation can rebuild their input. */\n private recordForConversation(span: AnyExportedSpan, traceData: PosthogTraceData): void {\n const isCall = span.type === SpanType.MODEL_INFERENCE && !span.errorInfo;\n // A PROVIDER_TOOL_CALL span ended without a result (e.g. the run stopped first)\n // has no `success`, and recording it would add an empty result.\n const isProviderToolWithResult =\n span.type === SpanType.PROVIDER_TOOL_CALL &&\n typeof (span.attributes as { success?: unknown } | undefined)?.success === 'boolean';\n const isTool = span.type === SpanType.TOOL_CALL || span.type === SpanType.MCP_TOOL_CALL || isProviderToolWithResult;\n if (!isModelInferenceEnabled() || (!isCall && !isTool)) return;\n\n const generation = this.findGeneration(span, traceData);\n if (!generation) return;\n\n const key = CONVERSATION + generation.id;\n let conversation = traceData.getExtraValue(key) as Conversation | undefined;\n if (!conversation) {\n conversation = { calls: [], toolResults: new Map() };\n traceData.setExtraValue(key, conversation);\n }\n if (isCall) {\n conversation.calls.push(span);\n } else {\n const toolCallId = this.resolveToolCallId(span);\n if (toolCallId) conversation.toolResults.set(toolCallId, span);\n }\n }\n\n private findGeneration(span: AnyExportedSpan, traceData: PosthogTraceData): AnyExportedSpan | undefined {\n let ancestor = span.parentSpanId ? traceData.getSpan({ spanId: span.parentSpanId }) : undefined;\n while (ancestor && ancestor.type !== SpanType.MODEL_GENERATION) {\n ancestor = ancestor.parentSpanId ? traceData.getSpan({ spanId: ancestor.parentSpanId }) : undefined;\n }\n return ancestor;\n }\n\n private resolveToolCallId(span: AnyExportedSpan): string | undefined {\n const attrs = span.attributes as { toolCallId?: string } | undefined;\n return (\n attrs?.toolCallId ??\n (span.metadata?.toolCallId as string | undefined) ??\n (span.input as { toolCallId?: string } | undefined)?.toolCallId\n );\n }\n\n private getDistinctId(span: AnyExportedSpan, traceData?: PosthogTraceData): string {\n if (span.metadata?.userId) {\n return String(span.metadata.userId);\n }\n\n if (traceData?.hasExtraValue(DISTINCT_ID)) {\n return String(traceData.getExtraValue(DISTINCT_ID));\n }\n\n if (this.config.defaultDistinctId) {\n return this.config.defaultDistinctId;\n }\n\n return 'anonymous';\n }\n\n /**\n * Check if the parent of this span is the root span.\n * We need this because we don't create $ai_span for root spans,\n * so children of root spans should use $ai_trace_id as their $ai_parent_id.\n */\n private isParentRootSpan(span: AnyExportedSpan, traceData: PosthogTraceData): boolean {\n if (!span.parentSpanId) {\n return false;\n }\n\n // Look up the parent span in our cache to check if it's a root span\n const parentCache = traceData.getSpan({ spanId: span.parentSpanId });\n if (parentCache) {\n return parentCache.isRootSpan;\n }\n\n // Parent not found in cache - shouldn't happen normally, but default to false\n return false;\n }\n\n private buildEventProperties(\n span: AnyExportedSpan,\n latency: number,\n parentIsRootSpan: boolean = false,\n isModelCall: boolean = this.isModelCall(span),\n ): Record<string, any> {\n const baseProperties: Record<string, any> = {\n $ai_trace_id: span.traceId,\n $ai_latency: latency,\n $ai_is_error: !!span.errorInfo,\n };\n\n if (span.parentSpanId) {\n // If parent is the root span, use trace_id as parent_id since we don't\n // create an $ai_span for root spans (only $ai_trace)\n baseProperties.$ai_parent_id = parentIsRootSpan ? span.traceId : span.parentSpanId;\n }\n\n if (span.metadata?.sessionId) {\n baseProperties.$ai_session_id = span.metadata.sessionId;\n }\n\n // Include tags for root spans (tags are only set on root spans by design)\n // PostHog doesn't allow setting tags directly, so we iterate through each tag\n // and set it as a property with value true\n if (span.isRootSpan && span.tags?.length) {\n for (const tag of span.tags) {\n baseProperties[tag] = true;\n }\n }\n\n if (isModelCall) {\n baseProperties.$ai_generation_id = span.id;\n return { ...baseProperties, ...this.buildGenerationProperties(span) };\n } else {\n baseProperties.$ai_span_id = span.id;\n baseProperties.$ai_span_name = span.name;\n return { ...baseProperties, ...this.buildSpanProperties(span) };\n }\n }\n\n private extractErrorProperties(errorInfo?: SpanErrorInfo): Record<string, any> {\n if (!errorInfo) {\n return {};\n }\n\n const props: Record<string, string> = {\n error_message: errorInfo.message,\n };\n\n if (errorInfo.id) {\n props.error_id = errorInfo.id;\n }\n\n if (errorInfo.category) {\n props.error_category = errorInfo.category;\n }\n\n return props;\n }\n\n private extractCustomMetadata(metadata?: Record<string, unknown>): Record<string, any> {\n const { userId, sessionId, ...customMetadata } = metadata ?? {};\n return customMetadata;\n }\n\n private buildGenerationProperties(span: AnyExportedSpan): Record<string, any> {\n const props: Record<string, any> = {};\n const attrs = (span.attributes ?? {}) as ModelGenerationAttributes;\n\n props.$ai_model = attrs.model || 'unknown-model';\n props.$ai_provider = attrs.provider || 'unknown-provider';\n\n if (span.input) props.$ai_input = this.formatMessages(span.input, 'user');\n if (span.output) props.$ai_output_choices = this.formatMessages(span.output, 'assistant');\n\n // Extract usage properties using the shared utility\n Object.assign(props, formatUsageMetrics(attrs.usage));\n\n if (attrs.parameters) {\n if (attrs.parameters.temperature !== undefined) props.$ai_temperature = attrs.parameters.temperature;\n if (attrs.parameters.maxOutputTokens !== undefined) props.$ai_max_tokens = attrs.parameters.maxOutputTokens;\n }\n if (attrs.streaming !== undefined) props.$ai_stream = attrs.streaming;\n if (attrs.tools?.length) {\n // OpenAI-style shape — the format PostHog's own AI SDKs send and its\n // trace view renders. Provider-defined tools pass through as-is.\n props.$ai_tools = attrs.tools.map(tool =>\n tool.type === 'function'\n ? {\n type: 'function',\n function: { name: tool.name, description: tool.description, parameters: tool.parameters },\n }\n : tool,\n );\n }\n\n return { ...props, ...this.extractErrorProperties(span.errorInfo), ...this.extractCustomMetadata(span.metadata) };\n }\n\n private buildSpanProperties(span: AnyExportedSpan): Record<string, any> {\n const props: Record<string, any> = {};\n\n if (span.input) props.$ai_input_state = span.input;\n if (span.output) props.$ai_output_state = span.output;\n\n if (span.type === SpanType.MODEL_CHUNK) {\n const attrs = span.attributes as any;\n if (attrs?.chunkType) props.chunk_type = attrs.chunkType;\n if (attrs?.sequenceNumber !== undefined) props.chunk_sequence_number = attrs.sequenceNumber;\n }\n\n if (span.attributes) {\n Object.assign(props, span.attributes);\n }\n\n return { ...props, ...this.extractErrorProperties(span.errorInfo), ...this.extractCustomMetadata(span.metadata) };\n }\n\n private formatMessages(data: SpanData, defaultRole: 'user' | 'assistant' = 'user'): PostHogMessage[] {\n // Unwrap {messages: [...]} wrapper produced by generation span inputs\n if (typeof data === 'object' && data !== null && !Array.isArray(data) && 'messages' in data) {\n const wrapped = (data as Record<string, unknown>).messages;\n if (this.isMessageArray(wrapped)) {\n return wrapped.map(msg => this.normalizeMessage(msg));\n }\n }\n\n if (this.isMessageArray(data)) {\n return data.map(msg => this.normalizeMessage(msg));\n }\n\n if (typeof data === 'string') {\n return [{ role: defaultRole, content: [{ type: 'text', text: data }] }];\n }\n\n if (this.isSpanOutputWithToolCalls(data)) {\n const content: PostHogContent[] = [];\n if (data.text) {\n content.push({ type: 'text', text: data.text });\n }\n for (const tc of data.toolCalls) {\n content.push({\n type: 'tool-call',\n id: tc.toolCallId,\n function: { name: tc.toolName, arguments: tc.args },\n });\n }\n return [{ role: 'assistant', content }];\n }\n\n // Extract text from output objects (e.g. generation outputs with text but no tool calls)\n if (typeof data === 'object' && data !== null && !Array.isArray(data) && 'text' in data) {\n const text = (data as Record<string, unknown>).text;\n if (typeof text === 'string') {\n return [{ role: defaultRole, content: [{ type: 'text', text }] }];\n }\n }\n\n return [{ role: defaultRole, content: [{ type: 'text', text: this.safeStringify(data) }] }];\n }\n\n private isSpanOutputWithToolCalls(\n data: unknown,\n ): data is { text?: string; toolCalls: Array<{ toolCallId: string; toolName: string; args: unknown }> } {\n if (typeof data !== 'object' || data === null || !('toolCalls' in data)) return false;\n const { toolCalls } = data as Record<string, unknown>;\n return Array.isArray(toolCalls) && toolCalls.length > 0;\n }\n\n private isMessageArray(data: unknown): data is MastraMessage[] {\n if (!Array.isArray(data)) {\n return false;\n }\n\n return data.every(item => typeof item === 'object' && item !== null && 'role' in item && 'content' in item);\n }\n\n private normalizeMessage(msg: MastraMessage): PostHogMessage {\n if (typeof msg.content === 'string') {\n return {\n role: msg.role as PostHogMessage['role'],\n content: [{ type: 'text', text: msg.content }],\n };\n }\n\n return {\n role: msg.role as PostHogMessage['role'],\n content: msg.content as PostHogContent[],\n };\n }\n\n private safeStringify(data: unknown): string {\n try {\n return JSON.stringify(data);\n } catch {\n if (typeof data === 'object' && data !== null) {\n return `[Non-serializable ${data.constructor?.name || 'Object'}]`;\n }\n return String(data);\n }\n }\n\n /**\n * Force flush any buffered data to PostHog without shutting down.\n */\n protected override async _flush(): Promise<void> {\n if (this.#client) {\n await this.#client.flush();\n }\n }\n\n override async _postShutdown(): Promise<void> {\n if (this.#client) {\n await this.#client.shutdown();\n }\n }\n}\n"],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -238,6 +238,11 @@ var PosthogExporter = class PosthogExporter extends TrackingExporter {
|
|
|
238
238
|
if (span.tags?.length) for (const tag of span.tags) traceProperties[tag] = true;
|
|
239
239
|
const { userId, sessionId, ...customMetadata } = span.metadata ?? {};
|
|
240
240
|
Object.assign(traceProperties, customMetadata);
|
|
241
|
+
if (span.type === SpanType.MCP_SERVER_REQUEST) {
|
|
242
|
+
const { callerTraceparent, callerTracestate } = span.attributes ?? {};
|
|
243
|
+
if (callerTraceparent) traceProperties.callerTraceparent = callerTraceparent;
|
|
244
|
+
if (callerTracestate) traceProperties.callerTracestate = callerTracestate;
|
|
245
|
+
}
|
|
241
246
|
return {
|
|
242
247
|
distinctId,
|
|
243
248
|
event: "$ai_trace",
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["#client"],"sources":["../src/features.ts","../src/tracing.ts"],"sourcesContent":["/**\n * Feature detection for paired @mastra/core and @mastra/observability versions.\n *\n * Both are resolved synchronously so span classification is stable from the\n * very first span, without depending on a pending dynamic import.\n *\n * `@mastra/observability` is a hard dependency, but older versions do not\n * export `observabilityFeatures`. The namespace import reads it as `undefined`\n * in that case instead of failing to link, which is the graceful fallback\n * documented in `observability/mastra/src/features.ts`.\n */\n\nimport { coreFeatures } from '@mastra/core/features';\nimport * as observability from '@mastra/observability';\n\nconst FEATURE = 'model-inference-span';\n\nlet observabilityFeatures: ReadonlySet<string> | undefined = (\n observability as { observabilityFeatures?: ReadonlySet<string> }\n).observabilityFeatures;\n\n/**\n * Returns true when both packages report the `model-inference-span` feature,\n * meaning MODEL_INFERENCE spans are emitted by the tracker. Drives which span\n * is exported as `$ai_generation` (new: MODEL_INFERENCE; legacy:\n * MODEL_GENERATION).\n */\nexport function isModelInferenceEnabled(): boolean {\n return observabilityFeatures?.has(FEATURE) === true && coreFeatures.has(FEATURE);\n}\n\n/**\n * @internal Test-only override. Allows tests to simulate a paired older or\n * newer `@mastra/observability` without juggling module mocks.\n */\nexport function __setObservabilityFeaturesForTest(features: ReadonlySet<string> | undefined): void {\n observabilityFeatures = features;\n}\n","import type {\n AnyExportedSpan,\n ExportedFeedback,\n FeedbackEvent,\n ModelGenerationAttributes,\n SpanErrorInfo,\n UsageStats,\n} from '@mastra/core/observability';\nimport { SpanType } from '@mastra/core/observability';\nimport type { TraceData, TrackingExporterConfig } from '@mastra/observability';\nimport { TrackingExporter } from '@mastra/observability';\nimport { PostHog } from 'posthog-node';\nimport type { EventMessage } from 'posthog-node';\nimport { isModelInferenceEnabled } from './features';\n\n/**\n * Token usage format compatible with PostHog.\n * @see https://posthog.com/docs/llm-analytics/generations#event-properties\n */\nexport interface PostHogUsageMetrics {\n $ai_input_tokens?: number;\n $ai_output_tokens?: number;\n $ai_cache_read_input_tokens?: number;\n $ai_cache_creation_input_tokens?: number;\n $ai_cache_creation_5m_input_tokens?: number;\n $ai_cache_creation_1h_input_tokens?: number;\n}\n\n/**\n * Formats UsageStats to PostHog's expected property format.\n *\n * Pass through gross input token counts with cache fields as subsets.\n * PostHog subtracts cache tokens when computing costs for non-Anthropic\n * providers and detects Anthropic-style exclusive reporting on its own.\n *\n * @param usage - The UsageStats from span attributes\n * @returns PostHog-formatted usage properties\n */\nexport function formatUsageMetrics(usage?: UsageStats): PostHogUsageMetrics {\n if (!usage) return {};\n\n const props: PostHogUsageMetrics = {};\n\n if (usage.inputTokens !== undefined) {\n props.$ai_input_tokens = usage.inputTokens;\n }\n\n if (usage.inputDetails?.cacheRead !== undefined) {\n props.$ai_cache_read_input_tokens = usage.inputDetails.cacheRead;\n }\n\n if (usage.inputDetails?.cacheWrite !== undefined) {\n props.$ai_cache_creation_input_tokens = usage.inputDetails.cacheWrite;\n }\n if (usage.inputDetails?.cacheWrite5m !== undefined) {\n props.$ai_cache_creation_5m_input_tokens = usage.inputDetails.cacheWrite5m;\n }\n if (usage.inputDetails?.cacheWrite1h !== undefined) {\n props.$ai_cache_creation_1h_input_tokens = usage.inputDetails.cacheWrite1h;\n }\n\n if (usage.outputTokens !== undefined) {\n props.$ai_output_tokens = usage.outputTokens;\n }\n\n return props;\n}\n\ninterface PostHogMessage {\n role: 'user' | 'assistant' | 'system' | 'tool';\n content: PostHogContent[];\n}\n\ninterface PostHogContent {\n type: string;\n text?: string;\n [key: string]: unknown;\n}\n\ninterface MastraMessage {\n role: string;\n content: string | MastraContent[];\n}\n\ninterface MastraContent {\n type: string;\n text?: string;\n [key: string]: unknown;\n}\n\ntype SpanData = string | MastraMessage[] | Record<string, unknown> | unknown;\n\nconst DISTINCT_ID = 'distinctId';\n/** Per-trace key prefix for the provider calls and tool results recorded under one MODEL_GENERATION. */\nconst CONVERSATION = 'conversation:';\n\n/** Ended spans under one MODEL_GENERATION, used to rebuild each provider call's `$ai_input`. */\ninterface Conversation {\n /** Ended MODEL_INFERENCE spans, in the order they ended. */\n calls: AnyExportedSpan[];\n /** Ended TOOL_CALL / MCP_TOOL_CALL spans and PROVIDER_TOOL_CALL spans with a result, keyed by toolCallId. */\n toolResults: Map<string, AnyExportedSpan>;\n}\n\nexport interface PosthogExporterConfig extends TrackingExporterConfig {\n /** PostHog API key. Defaults to POSTHOG_API_KEY environment variable. */\n apiKey?: string;\n /** PostHog host URL. Defaults to POSTHOG_HOST environment variable or US region. */\n host?: string;\n flushAt?: number;\n flushInterval?: number;\n serverless?: boolean;\n defaultDistinctId?: string;\n enablePrivacyMode?: boolean;\n}\n\ntype PosthogRoot = unknown;\ntype PosthogSpan = AnyExportedSpan;\n// used as a placeholder for event data since we don't need to cache\n// event data for Posthog\ntype PosthogEvent = boolean;\ntype PosthogMetadata = unknown;\ntype PosthogTraceData = TraceData<PosthogRoot, PosthogSpan, PosthogEvent, PosthogMetadata>;\n\nexport class PosthogExporter extends TrackingExporter<\n PosthogRoot,\n PosthogSpan,\n PosthogEvent,\n PosthogMetadata,\n PosthogExporterConfig\n> {\n name = 'posthog';\n #client: PostHog | undefined;\n\n private static readonly SERVERLESS_FLUSH_AT = 10;\n private static readonly SERVERLESS_FLUSH_INTERVAL = 2000;\n private static readonly DEFAULT_FLUSH_AT = 20;\n private static readonly DEFAULT_FLUSH_INTERVAL = 10000;\n\n constructor(config: PosthogExporterConfig = {}) {\n // Resolve env vars BEFORE calling super (config is readonly in base class)\n const apiKey = config.apiKey ?? process.env.POSTHOG_API_KEY;\n\n super({ ...config, apiKey });\n\n if (!apiKey) {\n this.setDisabled('Missing required API key. Set POSTHOG_API_KEY environment variable or pass apiKey in config.');\n return;\n }\n\n const clientConfig = this.buildClientConfig(this.config);\n this.#client = new PostHog(apiKey, clientConfig);\n const message =\n (config.serverless ?? false) ? 'PostHog exporter initialized in serverless mode' : 'PostHog exporter initialized';\n this.logger.debug(message, config);\n }\n\n private buildClientConfig(config: PosthogExporterConfig) {\n const isServerless = config.serverless ?? false;\n const flushAt =\n config.flushAt ?? (isServerless ? PosthogExporter.SERVERLESS_FLUSH_AT : PosthogExporter.DEFAULT_FLUSH_AT);\n const flushInterval =\n config.flushInterval ??\n (isServerless ? PosthogExporter.SERVERLESS_FLUSH_INTERVAL : PosthogExporter.DEFAULT_FLUSH_INTERVAL);\n\n const host = config.host || process.env.POSTHOG_HOST || 'https://us.i.posthog.com';\n\n if (!config.host && !process.env.POSTHOG_HOST) {\n this.logger.info(\n 'No PostHog host specified, using US default (https://us.i.posthog.com). ' +\n 'For EU region, set `host: \"https://eu.i.posthog.com\"` in config or POSTHOG_HOST env var. ' +\n 'For self-hosted, provide your instance URL.',\n );\n }\n\n return {\n host,\n flushAt,\n flushInterval,\n privacyMode: config.enablePrivacyMode,\n };\n }\n\n protected override skipBuildRootTask = true;\n protected override async _buildRoot(_args: {\n span: AnyExportedSpan;\n traceData: PosthogTraceData;\n }): Promise<PosthogRoot | undefined> {\n throw new Error('Method not implemented.');\n }\n\n protected override skipCachingEventSpans = true;\n protected override async _buildEvent(args: {\n span: AnyExportedSpan;\n traceData: PosthogTraceData;\n }): Promise<PosthogEvent> {\n const { span, traceData } = args;\n\n const isModelCall = this.isModelCall(span);\n const distinctId = this.getDistinctId(span, traceData);\n const properties = this.buildEventProperties(span, 0, false, isModelCall);\n\n // captureAi() targets PostHog's dedicated AI endpoint (8 MiB per event, oversized events\n // dropped individually). Plain capture() uses /batch/, which returns 413 for large spans.\n this.#client?.captureAi(\n this.withGroups({\n distinctId,\n event: isModelCall ? '$ai_generation' : '$ai_span',\n properties,\n timestamp: span.endTime ? new Date(span.endTime) : new Date(),\n }),\n );\n\n return true;\n }\n\n protected override async _buildSpan(args: {\n span: AnyExportedSpan;\n traceData: PosthogTraceData;\n }): Promise<PosthogSpan | undefined> {\n const { span, traceData } = args;\n if (!traceData.hasExtraValue(DISTINCT_ID)) {\n const userId = span.metadata?.userId;\n if (userId) {\n traceData.setExtraValue(DISTINCT_ID, String(userId));\n }\n }\n\n return span;\n }\n\n protected override skipSpanUpdateEvents = true;\n protected override _updateSpan(_args: { span: AnyExportedSpan; traceData: PosthogTraceData }): Promise<void> {\n throw new Error('Method not implemented.');\n }\n\n protected override async _finishSpan(args: { span: AnyExportedSpan; traceData: PosthogTraceData }): Promise<void> {\n const { span, traceData } = args;\n\n // Merge input from cached span (SPAN_STARTED) if not present on end span\n // This handles the case where input is only sent at start\n const cachedSpan = traceData.getSpan({ spanId: span.id });\n const mergedSpan = !span.input && cachedSpan?.input ? { ...span, input: cachedSpan.input } : span;\n\n const eventMessage = this.buildEventMessage({ span: this.withCallInput(mergedSpan, traceData), traceData });\n this.#client?.captureAi(this.withGroups(eventMessage));\n\n this.recordForConversation(span, traceData);\n }\n\n protected override async _abortSpan(args: {\n span: PosthogSpan;\n reason: SpanErrorInfo;\n traceData: PosthogTraceData;\n }): Promise<void> {\n const { span, reason, traceData } = args;\n\n // update span with the abort reason\n span.errorInfo = reason;\n\n const eventMessage = this.buildEventMessage({ span: this.withCallInput(span, traceData), traceData });\n this.#client?.captureAi(this.withGroups(eventMessage));\n }\n\n /**\n * Forward feedback recorded via `addFeedback()` to PostHog as a native\n * `$ai_feedback` event, shown as \"User feedback\" on the linked trace in\n * PostHog's AI observability UI.\n */\n async onFeedbackEvent(event: FeedbackEvent): Promise<void> {\n if (!this.#client) return;\n\n const { feedback } = event;\n if (!feedback.traceId) {\n this.logger.debug('PostHog exporter: dropping feedback with no traceId; PostHog requires $ai_trace_id', {\n feedbackId: feedback.feedbackId,\n });\n return;\n }\n\n const properties: Record<string, any> = {\n // Custom metadata goes first so it cannot overwrite the natively mapped fields below\n ...this.extractCustomMetadata(feedback.metadata),\n $ai_trace_id: feedback.traceId,\n // PostHog's trace UI only displays feedback events that carry $ai_feedback_text\n $ai_feedback_text: feedback.comment ?? String(feedback.value),\n feedback_id: feedback.feedbackId,\n feedback_type: feedback.feedbackType,\n feedback_value: feedback.value,\n };\n\n const feedbackSource = feedback.feedbackSource ?? feedback.source;\n if (feedbackSource) properties.feedback_source = feedbackSource;\n if (feedback.spanId) properties.span_id = feedback.spanId;\n if (feedback.sourceId) properties.source_id = feedback.sourceId;\n if (feedback.metadata?.sessionId) properties.$ai_session_id = feedback.metadata.sessionId;\n\n try {\n this.#client.captureAi(\n this.withGroups({\n distinctId: this.getFeedbackDistinctId(feedback),\n event: '$ai_feedback',\n properties,\n timestamp: new Date(feedback.timestamp),\n }),\n );\n } catch (err) {\n this.logger.error('PostHog exporter: failed to submit feedback', {\n error: err,\n traceId: feedback.traceId,\n feedbackId: feedback.feedbackId,\n });\n }\n }\n\n private getFeedbackDistinctId(feedback: ExportedFeedback): string {\n const userId = feedback.feedbackUserId ?? feedback.userId ?? feedback.metadata?.userId;\n if (userId) {\n return String(userId);\n }\n return this.config.defaultDistinctId ?? 'anonymous';\n }\n\n /**\n * PostHog group analytics are keyed off the top-level `groups` field on the\n * capture call. The Node SDK derives the event's `$groups` from that field and\n * overwrites any property-level `$groups`, so group metadata carried in\n * properties is dropped unless it is mirrored here.\n */\n private withGroups(message: EventMessage): EventMessage {\n const groups = message.properties?.$groups;\n if (groups && typeof groups === 'object' && !Array.isArray(groups)) {\n return { ...message, groups };\n }\n return message;\n }\n\n private buildEventMessage(args: { span: AnyExportedSpan; traceData: PosthogTraceData }): EventMessage {\n const { span, traceData } = args;\n\n const endTime = span.endTime ? this.toDate(span.endTime).getTime() : Date.now();\n\n const distinctId = this.getDistinctId(span, traceData);\n\n if (span.isRootSpan) {\n return this.buildRootEventMessage({ span, distinctId, endTime });\n } else {\n return this.buildChildEventMessage({ span, distinctId, endTime, traceData });\n }\n }\n\n /**\n * Capture an explicit $ai_trace event for root spans.\n * This gives us control over trace-level metadata like name and tags,\n * rather than relying on PostHog's pseudo-trace auto-creation.\n */\n private buildRootEventMessage(args: { span: AnyExportedSpan; distinctId: string; endTime: number }): EventMessage {\n const { span, distinctId, endTime } = args;\n\n // Note: We don't set $ai_latency on $ai_trace events because PostHog\n // aggregates latency from child events. Setting it here causes double-counting.\n const traceProperties: Record<string, any> = {\n $ai_trace_id: span.traceId,\n $ai_span_name: span.name,\n $ai_is_error: !!span.errorInfo,\n };\n\n if (span.metadata?.sessionId) {\n traceProperties.$ai_session_id = span.metadata.sessionId;\n }\n\n if (span.input) {\n traceProperties.$ai_input_state = span.input;\n }\n\n if (span.output) {\n traceProperties.$ai_output_state = span.output;\n }\n\n if (span.errorInfo) {\n traceProperties.$ai_error = {\n message: span.errorInfo.message,\n ...(span.errorInfo.id && { id: span.errorInfo.id }),\n ...(span.errorInfo.category && { category: span.errorInfo.category }),\n };\n }\n\n // Add tags as custom properties (PostHog doesn't have native tag support on traces)\n if (span.tags?.length) {\n for (const tag of span.tags) {\n traceProperties[tag] = true;\n }\n }\n\n // Add custom metadata (excluding userId and sessionId which are handled separately)\n const { userId, sessionId, ...customMetadata } = span.metadata ?? {};\n Object.assign(traceProperties, customMetadata);\n\n return {\n distinctId,\n event: '$ai_trace',\n properties: traceProperties,\n timestamp: new Date(endTime),\n };\n }\n\n private buildChildEventMessage(args: {\n span: AnyExportedSpan;\n distinctId: string;\n endTime: number;\n traceData: PosthogTraceData;\n }): EventMessage {\n const { span, distinctId, endTime, traceData } = args;\n\n const isModelCall = this.isModelCall(span);\n const startTime = span.startTime.getTime();\n const latency = (endTime - startTime) / 1000;\n\n // Check if parent is the root span - if so, use traceId as parent_id\n // since we don't create an $ai_span for root spans\n const parentIsRootSpan = this.isParentRootSpan(span, traceData);\n const properties = this.buildEventProperties(span, latency, parentIsRootSpan, isModelCall);\n\n return {\n distinctId,\n event: isModelCall ? '$ai_generation' : '$ai_span',\n properties,\n timestamp: new Date(endTime),\n };\n }\n\n private toDate(timestamp: Date | number): Date {\n return timestamp instanceof Date ? timestamp : new Date(timestamp);\n }\n\n /**\n * Whether this span is exported as `$ai_generation`. PostHog expects one per\n * provider call and sums tokens and cost across them, so exactly one span\n * per call may carry usage. With paired packages that emit MODEL_INFERENCE,\n * that is the call and MODEL_GENERATION is the loop around it, exported as\n * `$ai_span`. Older pairings only emit MODEL_GENERATION, which keeps the\n * `$ai_generation` role.\n */\n private isModelCall(span: AnyExportedSpan): boolean {\n return span.type === (isModelInferenceEnabled() ? SpanType.MODEL_INFERENCE : SpanType.MODEL_GENERATION);\n }\n\n /**\n * Give a MODEL_INFERENCE exported as `$ai_generation` the conversation that\n * call received. The span has no input of its own, so it is rebuilt from the\n * generation's input plus, for each earlier call in the same generation, its\n * output and the results of the tools it called (as Braintrust's Thread view\n * does). Earlier calls and their tools end before this call does, so they are\n * already recorded.\n */\n private withCallInput(span: AnyExportedSpan, traceData: PosthogTraceData): AnyExportedSpan {\n if (span.type !== SpanType.MODEL_INFERENCE || !this.isModelCall(span)) return span;\n\n const generation = this.findGeneration(span, traceData);\n if (!generation?.input) return span;\n\n const messages = this.formatMessages(generation.input, 'user');\n const conversation = traceData.getExtraValue(CONVERSATION + generation.id) as Conversation | undefined;\n for (const call of conversation?.calls ?? []) {\n const output = call.output as\n | { text?: string; toolCalls?: Array<{ toolCallId: string; toolName: string }> }\n | undefined;\n if (!output?.text && !output?.toolCalls?.length) continue;\n messages.push(...this.formatMessages(output, 'assistant'));\n\n // Parallel tool calls are ordered by when each tool started.\n const results = (output.toolCalls ?? [])\n .map(toolCall => ({ toolCall, toolSpan: conversation!.toolResults.get(toolCall.toolCallId) }))\n .filter(\n (result): result is { toolCall: typeof result.toolCall; toolSpan: AnyExportedSpan } => !!result.toolSpan,\n )\n .sort((a, b) => this.toDate(a.toolSpan.startTime).getTime() - this.toDate(b.toolSpan.startTime).getTime());\n for (const { toolCall, toolSpan } of results) {\n // Provider-executed tools report failure through `success`, not `errorInfo`.\n const isError =\n !!toolSpan.errorInfo ||\n (toolSpan.type === SpanType.PROVIDER_TOOL_CALL &&\n (toolSpan.attributes as { success?: boolean } | undefined)?.success === false);\n // Same `tool-result` part shape PostHog's own AI SDK integrations send.\n messages.push({\n role: 'tool',\n content: [\n {\n type: 'tool-result',\n toolCallId: toolCall.toolCallId,\n toolName: toolCall.toolName,\n output: toolSpan.errorInfo ? toolSpan.errorInfo.message : toolSpan.output,\n ...(isError ? { isError: true } : {}),\n },\n ],\n });\n }\n }\n\n return { ...span, input: messages };\n }\n\n /** Record ended calls and tool results so later calls in the same generation can rebuild their input. */\n private recordForConversation(span: AnyExportedSpan, traceData: PosthogTraceData): void {\n const isCall = span.type === SpanType.MODEL_INFERENCE && !span.errorInfo;\n // A PROVIDER_TOOL_CALL span ended without a result (e.g. the run stopped first)\n // has no `success`, and recording it would add an empty result.\n const isProviderToolWithResult =\n span.type === SpanType.PROVIDER_TOOL_CALL &&\n typeof (span.attributes as { success?: unknown } | undefined)?.success === 'boolean';\n const isTool = span.type === SpanType.TOOL_CALL || span.type === SpanType.MCP_TOOL_CALL || isProviderToolWithResult;\n if (!isModelInferenceEnabled() || (!isCall && !isTool)) return;\n\n const generation = this.findGeneration(span, traceData);\n if (!generation) return;\n\n const key = CONVERSATION + generation.id;\n let conversation = traceData.getExtraValue(key) as Conversation | undefined;\n if (!conversation) {\n conversation = { calls: [], toolResults: new Map() };\n traceData.setExtraValue(key, conversation);\n }\n if (isCall) {\n conversation.calls.push(span);\n } else {\n const toolCallId = this.resolveToolCallId(span);\n if (toolCallId) conversation.toolResults.set(toolCallId, span);\n }\n }\n\n private findGeneration(span: AnyExportedSpan, traceData: PosthogTraceData): AnyExportedSpan | undefined {\n let ancestor = span.parentSpanId ? traceData.getSpan({ spanId: span.parentSpanId }) : undefined;\n while (ancestor && ancestor.type !== SpanType.MODEL_GENERATION) {\n ancestor = ancestor.parentSpanId ? traceData.getSpan({ spanId: ancestor.parentSpanId }) : undefined;\n }\n return ancestor;\n }\n\n private resolveToolCallId(span: AnyExportedSpan): string | undefined {\n const attrs = span.attributes as { toolCallId?: string } | undefined;\n return (\n attrs?.toolCallId ??\n (span.metadata?.toolCallId as string | undefined) ??\n (span.input as { toolCallId?: string } | undefined)?.toolCallId\n );\n }\n\n private getDistinctId(span: AnyExportedSpan, traceData?: PosthogTraceData): string {\n if (span.metadata?.userId) {\n return String(span.metadata.userId);\n }\n\n if (traceData?.hasExtraValue(DISTINCT_ID)) {\n return String(traceData.getExtraValue(DISTINCT_ID));\n }\n\n if (this.config.defaultDistinctId) {\n return this.config.defaultDistinctId;\n }\n\n return 'anonymous';\n }\n\n /**\n * Check if the parent of this span is the root span.\n * We need this because we don't create $ai_span for root spans,\n * so children of root spans should use $ai_trace_id as their $ai_parent_id.\n */\n private isParentRootSpan(span: AnyExportedSpan, traceData: PosthogTraceData): boolean {\n if (!span.parentSpanId) {\n return false;\n }\n\n // Look up the parent span in our cache to check if it's a root span\n const parentCache = traceData.getSpan({ spanId: span.parentSpanId });\n if (parentCache) {\n return parentCache.isRootSpan;\n }\n\n // Parent not found in cache - shouldn't happen normally, but default to false\n return false;\n }\n\n private buildEventProperties(\n span: AnyExportedSpan,\n latency: number,\n parentIsRootSpan: boolean = false,\n isModelCall: boolean = this.isModelCall(span),\n ): Record<string, any> {\n const baseProperties: Record<string, any> = {\n $ai_trace_id: span.traceId,\n $ai_latency: latency,\n $ai_is_error: !!span.errorInfo,\n };\n\n if (span.parentSpanId) {\n // If parent is the root span, use trace_id as parent_id since we don't\n // create an $ai_span for root spans (only $ai_trace)\n baseProperties.$ai_parent_id = parentIsRootSpan ? span.traceId : span.parentSpanId;\n }\n\n if (span.metadata?.sessionId) {\n baseProperties.$ai_session_id = span.metadata.sessionId;\n }\n\n // Include tags for root spans (tags are only set on root spans by design)\n // PostHog doesn't allow setting tags directly, so we iterate through each tag\n // and set it as a property with value true\n if (span.isRootSpan && span.tags?.length) {\n for (const tag of span.tags) {\n baseProperties[tag] = true;\n }\n }\n\n if (isModelCall) {\n baseProperties.$ai_generation_id = span.id;\n return { ...baseProperties, ...this.buildGenerationProperties(span) };\n } else {\n baseProperties.$ai_span_id = span.id;\n baseProperties.$ai_span_name = span.name;\n return { ...baseProperties, ...this.buildSpanProperties(span) };\n }\n }\n\n private extractErrorProperties(errorInfo?: SpanErrorInfo): Record<string, any> {\n if (!errorInfo) {\n return {};\n }\n\n const props: Record<string, string> = {\n error_message: errorInfo.message,\n };\n\n if (errorInfo.id) {\n props.error_id = errorInfo.id;\n }\n\n if (errorInfo.category) {\n props.error_category = errorInfo.category;\n }\n\n return props;\n }\n\n private extractCustomMetadata(metadata?: Record<string, unknown>): Record<string, any> {\n const { userId, sessionId, ...customMetadata } = metadata ?? {};\n return customMetadata;\n }\n\n private buildGenerationProperties(span: AnyExportedSpan): Record<string, any> {\n const props: Record<string, any> = {};\n const attrs = (span.attributes ?? {}) as ModelGenerationAttributes;\n\n props.$ai_model = attrs.model || 'unknown-model';\n props.$ai_provider = attrs.provider || 'unknown-provider';\n\n if (span.input) props.$ai_input = this.formatMessages(span.input, 'user');\n if (span.output) props.$ai_output_choices = this.formatMessages(span.output, 'assistant');\n\n // Extract usage properties using the shared utility\n Object.assign(props, formatUsageMetrics(attrs.usage));\n\n if (attrs.parameters) {\n if (attrs.parameters.temperature !== undefined) props.$ai_temperature = attrs.parameters.temperature;\n if (attrs.parameters.maxOutputTokens !== undefined) props.$ai_max_tokens = attrs.parameters.maxOutputTokens;\n }\n if (attrs.streaming !== undefined) props.$ai_stream = attrs.streaming;\n if (attrs.tools?.length) {\n // OpenAI-style shape — the format PostHog's own AI SDKs send and its\n // trace view renders. Provider-defined tools pass through as-is.\n props.$ai_tools = attrs.tools.map(tool =>\n tool.type === 'function'\n ? {\n type: 'function',\n function: { name: tool.name, description: tool.description, parameters: tool.parameters },\n }\n : tool,\n );\n }\n\n return { ...props, ...this.extractErrorProperties(span.errorInfo), ...this.extractCustomMetadata(span.metadata) };\n }\n\n private buildSpanProperties(span: AnyExportedSpan): Record<string, any> {\n const props: Record<string, any> = {};\n\n if (span.input) props.$ai_input_state = span.input;\n if (span.output) props.$ai_output_state = span.output;\n\n if (span.type === SpanType.MODEL_CHUNK) {\n const attrs = span.attributes as any;\n if (attrs?.chunkType) props.chunk_type = attrs.chunkType;\n if (attrs?.sequenceNumber !== undefined) props.chunk_sequence_number = attrs.sequenceNumber;\n }\n\n if (span.attributes) {\n Object.assign(props, span.attributes);\n }\n\n return { ...props, ...this.extractErrorProperties(span.errorInfo), ...this.extractCustomMetadata(span.metadata) };\n }\n\n private formatMessages(data: SpanData, defaultRole: 'user' | 'assistant' = 'user'): PostHogMessage[] {\n // Unwrap {messages: [...]} wrapper produced by generation span inputs\n if (typeof data === 'object' && data !== null && !Array.isArray(data) && 'messages' in data) {\n const wrapped = (data as Record<string, unknown>).messages;\n if (this.isMessageArray(wrapped)) {\n return wrapped.map(msg => this.normalizeMessage(msg));\n }\n }\n\n if (this.isMessageArray(data)) {\n return data.map(msg => this.normalizeMessage(msg));\n }\n\n if (typeof data === 'string') {\n return [{ role: defaultRole, content: [{ type: 'text', text: data }] }];\n }\n\n if (this.isSpanOutputWithToolCalls(data)) {\n const content: PostHogContent[] = [];\n if (data.text) {\n content.push({ type: 'text', text: data.text });\n }\n for (const tc of data.toolCalls) {\n content.push({\n type: 'tool-call',\n id: tc.toolCallId,\n function: { name: tc.toolName, arguments: tc.args },\n });\n }\n return [{ role: 'assistant', content }];\n }\n\n // Extract text from output objects (e.g. generation outputs with text but no tool calls)\n if (typeof data === 'object' && data !== null && !Array.isArray(data) && 'text' in data) {\n const text = (data as Record<string, unknown>).text;\n if (typeof text === 'string') {\n return [{ role: defaultRole, content: [{ type: 'text', text }] }];\n }\n }\n\n return [{ role: defaultRole, content: [{ type: 'text', text: this.safeStringify(data) }] }];\n }\n\n private isSpanOutputWithToolCalls(\n data: unknown,\n ): data is { text?: string; toolCalls: Array<{ toolCallId: string; toolName: string; args: unknown }> } {\n if (typeof data !== 'object' || data === null || !('toolCalls' in data)) return false;\n const { toolCalls } = data as Record<string, unknown>;\n return Array.isArray(toolCalls) && toolCalls.length > 0;\n }\n\n private isMessageArray(data: unknown): data is MastraMessage[] {\n if (!Array.isArray(data)) {\n return false;\n }\n\n return data.every(item => typeof item === 'object' && item !== null && 'role' in item && 'content' in item);\n }\n\n private normalizeMessage(msg: MastraMessage): PostHogMessage {\n if (typeof msg.content === 'string') {\n return {\n role: msg.role as PostHogMessage['role'],\n content: [{ type: 'text', text: msg.content }],\n };\n }\n\n return {\n role: msg.role as PostHogMessage['role'],\n content: msg.content as PostHogContent[],\n };\n }\n\n private safeStringify(data: unknown): string {\n try {\n return JSON.stringify(data);\n } catch {\n if (typeof data === 'object' && data !== null) {\n return `[Non-serializable ${data.constructor?.name || 'Object'}]`;\n }\n return String(data);\n }\n }\n\n /**\n * Force flush any buffered data to PostHog without shutting down.\n */\n protected override async _flush(): Promise<void> {\n if (this.#client) {\n await this.#client.flush();\n }\n }\n\n override async _postShutdown(): Promise<void> {\n if (this.#client) {\n await this.#client.shutdown();\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["#client"],"sources":["../src/features.ts","../src/tracing.ts"],"sourcesContent":["/**\n * Feature detection for paired @mastra/core and @mastra/observability versions.\n *\n * Both are resolved synchronously so span classification is stable from the\n * very first span, without depending on a pending dynamic import.\n *\n * `@mastra/observability` is a hard dependency, but older versions do not\n * export `observabilityFeatures`. The namespace import reads it as `undefined`\n * in that case instead of failing to link, which is the graceful fallback\n * documented in `observability/mastra/src/features.ts`.\n */\n\nimport { coreFeatures } from '@mastra/core/features';\nimport * as observability from '@mastra/observability';\n\nconst FEATURE = 'model-inference-span';\n\nlet observabilityFeatures: ReadonlySet<string> | undefined = (\n observability as { observabilityFeatures?: ReadonlySet<string> }\n).observabilityFeatures;\n\n/**\n * Returns true when both packages report the `model-inference-span` feature,\n * meaning MODEL_INFERENCE spans are emitted by the tracker. Drives which span\n * is exported as `$ai_generation` (new: MODEL_INFERENCE; legacy:\n * MODEL_GENERATION).\n */\nexport function isModelInferenceEnabled(): boolean {\n return observabilityFeatures?.has(FEATURE) === true && coreFeatures.has(FEATURE);\n}\n\n/**\n * @internal Test-only override. Allows tests to simulate a paired older or\n * newer `@mastra/observability` without juggling module mocks.\n */\nexport function __setObservabilityFeaturesForTest(features: ReadonlySet<string> | undefined): void {\n observabilityFeatures = features;\n}\n","import type {\n AnyExportedSpan,\n ExportedFeedback,\n FeedbackEvent,\n ModelGenerationAttributes,\n SpanErrorInfo,\n UsageStats,\n} from '@mastra/core/observability';\nimport { SpanType } from '@mastra/core/observability';\nimport type { TraceData, TrackingExporterConfig } from '@mastra/observability';\nimport { TrackingExporter } from '@mastra/observability';\nimport { PostHog } from 'posthog-node';\nimport type { EventMessage } from 'posthog-node';\nimport { isModelInferenceEnabled } from './features';\n\n/**\n * Token usage format compatible with PostHog.\n * @see https://posthog.com/docs/llm-analytics/generations#event-properties\n */\nexport interface PostHogUsageMetrics {\n $ai_input_tokens?: number;\n $ai_output_tokens?: number;\n $ai_cache_read_input_tokens?: number;\n $ai_cache_creation_input_tokens?: number;\n $ai_cache_creation_5m_input_tokens?: number;\n $ai_cache_creation_1h_input_tokens?: number;\n}\n\n/**\n * Formats UsageStats to PostHog's expected property format.\n *\n * Pass through gross input token counts with cache fields as subsets.\n * PostHog subtracts cache tokens when computing costs for non-Anthropic\n * providers and detects Anthropic-style exclusive reporting on its own.\n *\n * @param usage - The UsageStats from span attributes\n * @returns PostHog-formatted usage properties\n */\nexport function formatUsageMetrics(usage?: UsageStats): PostHogUsageMetrics {\n if (!usage) return {};\n\n const props: PostHogUsageMetrics = {};\n\n if (usage.inputTokens !== undefined) {\n props.$ai_input_tokens = usage.inputTokens;\n }\n\n if (usage.inputDetails?.cacheRead !== undefined) {\n props.$ai_cache_read_input_tokens = usage.inputDetails.cacheRead;\n }\n\n if (usage.inputDetails?.cacheWrite !== undefined) {\n props.$ai_cache_creation_input_tokens = usage.inputDetails.cacheWrite;\n }\n if (usage.inputDetails?.cacheWrite5m !== undefined) {\n props.$ai_cache_creation_5m_input_tokens = usage.inputDetails.cacheWrite5m;\n }\n if (usage.inputDetails?.cacheWrite1h !== undefined) {\n props.$ai_cache_creation_1h_input_tokens = usage.inputDetails.cacheWrite1h;\n }\n\n if (usage.outputTokens !== undefined) {\n props.$ai_output_tokens = usage.outputTokens;\n }\n\n return props;\n}\n\ninterface PostHogMessage {\n role: 'user' | 'assistant' | 'system' | 'tool';\n content: PostHogContent[];\n}\n\ninterface PostHogContent {\n type: string;\n text?: string;\n [key: string]: unknown;\n}\n\ninterface MastraMessage {\n role: string;\n content: string | MastraContent[];\n}\n\ninterface MastraContent {\n type: string;\n text?: string;\n [key: string]: unknown;\n}\n\ntype SpanData = string | MastraMessage[] | Record<string, unknown> | unknown;\n\nconst DISTINCT_ID = 'distinctId';\n/** Per-trace key prefix for the provider calls and tool results recorded under one MODEL_GENERATION. */\nconst CONVERSATION = 'conversation:';\n\n/** Ended spans under one MODEL_GENERATION, used to rebuild each provider call's `$ai_input`. */\ninterface Conversation {\n /** Ended MODEL_INFERENCE spans, in the order they ended. */\n calls: AnyExportedSpan[];\n /** Ended TOOL_CALL / MCP_TOOL_CALL spans and PROVIDER_TOOL_CALL spans with a result, keyed by toolCallId. */\n toolResults: Map<string, AnyExportedSpan>;\n}\n\nexport interface PosthogExporterConfig extends TrackingExporterConfig {\n /** PostHog API key. Defaults to POSTHOG_API_KEY environment variable. */\n apiKey?: string;\n /** PostHog host URL. Defaults to POSTHOG_HOST environment variable or US region. */\n host?: string;\n flushAt?: number;\n flushInterval?: number;\n serverless?: boolean;\n defaultDistinctId?: string;\n enablePrivacyMode?: boolean;\n}\n\ntype PosthogRoot = unknown;\ntype PosthogSpan = AnyExportedSpan;\n// used as a placeholder for event data since we don't need to cache\n// event data for Posthog\ntype PosthogEvent = boolean;\ntype PosthogMetadata = unknown;\ntype PosthogTraceData = TraceData<PosthogRoot, PosthogSpan, PosthogEvent, PosthogMetadata>;\n\nexport class PosthogExporter extends TrackingExporter<\n PosthogRoot,\n PosthogSpan,\n PosthogEvent,\n PosthogMetadata,\n PosthogExporterConfig\n> {\n name = 'posthog';\n #client: PostHog | undefined;\n\n private static readonly SERVERLESS_FLUSH_AT = 10;\n private static readonly SERVERLESS_FLUSH_INTERVAL = 2000;\n private static readonly DEFAULT_FLUSH_AT = 20;\n private static readonly DEFAULT_FLUSH_INTERVAL = 10000;\n\n constructor(config: PosthogExporterConfig = {}) {\n // Resolve env vars BEFORE calling super (config is readonly in base class)\n const apiKey = config.apiKey ?? process.env.POSTHOG_API_KEY;\n\n super({ ...config, apiKey });\n\n if (!apiKey) {\n this.setDisabled('Missing required API key. Set POSTHOG_API_KEY environment variable or pass apiKey in config.');\n return;\n }\n\n const clientConfig = this.buildClientConfig(this.config);\n this.#client = new PostHog(apiKey, clientConfig);\n const message =\n (config.serverless ?? false) ? 'PostHog exporter initialized in serverless mode' : 'PostHog exporter initialized';\n this.logger.debug(message, config);\n }\n\n private buildClientConfig(config: PosthogExporterConfig) {\n const isServerless = config.serverless ?? false;\n const flushAt =\n config.flushAt ?? (isServerless ? PosthogExporter.SERVERLESS_FLUSH_AT : PosthogExporter.DEFAULT_FLUSH_AT);\n const flushInterval =\n config.flushInterval ??\n (isServerless ? PosthogExporter.SERVERLESS_FLUSH_INTERVAL : PosthogExporter.DEFAULT_FLUSH_INTERVAL);\n\n const host = config.host || process.env.POSTHOG_HOST || 'https://us.i.posthog.com';\n\n if (!config.host && !process.env.POSTHOG_HOST) {\n this.logger.info(\n 'No PostHog host specified, using US default (https://us.i.posthog.com). ' +\n 'For EU region, set `host: \"https://eu.i.posthog.com\"` in config or POSTHOG_HOST env var. ' +\n 'For self-hosted, provide your instance URL.',\n );\n }\n\n return {\n host,\n flushAt,\n flushInterval,\n privacyMode: config.enablePrivacyMode,\n };\n }\n\n protected override skipBuildRootTask = true;\n protected override async _buildRoot(_args: {\n span: AnyExportedSpan;\n traceData: PosthogTraceData;\n }): Promise<PosthogRoot | undefined> {\n throw new Error('Method not implemented.');\n }\n\n protected override skipCachingEventSpans = true;\n protected override async _buildEvent(args: {\n span: AnyExportedSpan;\n traceData: PosthogTraceData;\n }): Promise<PosthogEvent> {\n const { span, traceData } = args;\n\n const isModelCall = this.isModelCall(span);\n const distinctId = this.getDistinctId(span, traceData);\n const properties = this.buildEventProperties(span, 0, false, isModelCall);\n\n // captureAi() targets PostHog's dedicated AI endpoint (8 MiB per event, oversized events\n // dropped individually). Plain capture() uses /batch/, which returns 413 for large spans.\n this.#client?.captureAi(\n this.withGroups({\n distinctId,\n event: isModelCall ? '$ai_generation' : '$ai_span',\n properties,\n timestamp: span.endTime ? new Date(span.endTime) : new Date(),\n }),\n );\n\n return true;\n }\n\n protected override async _buildSpan(args: {\n span: AnyExportedSpan;\n traceData: PosthogTraceData;\n }): Promise<PosthogSpan | undefined> {\n const { span, traceData } = args;\n if (!traceData.hasExtraValue(DISTINCT_ID)) {\n const userId = span.metadata?.userId;\n if (userId) {\n traceData.setExtraValue(DISTINCT_ID, String(userId));\n }\n }\n\n return span;\n }\n\n protected override skipSpanUpdateEvents = true;\n protected override _updateSpan(_args: { span: AnyExportedSpan; traceData: PosthogTraceData }): Promise<void> {\n throw new Error('Method not implemented.');\n }\n\n protected override async _finishSpan(args: { span: AnyExportedSpan; traceData: PosthogTraceData }): Promise<void> {\n const { span, traceData } = args;\n\n // Merge input from cached span (SPAN_STARTED) if not present on end span\n // This handles the case where input is only sent at start\n const cachedSpan = traceData.getSpan({ spanId: span.id });\n const mergedSpan = !span.input && cachedSpan?.input ? { ...span, input: cachedSpan.input } : span;\n\n const eventMessage = this.buildEventMessage({ span: this.withCallInput(mergedSpan, traceData), traceData });\n this.#client?.captureAi(this.withGroups(eventMessage));\n\n this.recordForConversation(span, traceData);\n }\n\n protected override async _abortSpan(args: {\n span: PosthogSpan;\n reason: SpanErrorInfo;\n traceData: PosthogTraceData;\n }): Promise<void> {\n const { span, reason, traceData } = args;\n\n // update span with the abort reason\n span.errorInfo = reason;\n\n const eventMessage = this.buildEventMessage({ span: this.withCallInput(span, traceData), traceData });\n this.#client?.captureAi(this.withGroups(eventMessage));\n }\n\n /**\n * Forward feedback recorded via `addFeedback()` to PostHog as a native\n * `$ai_feedback` event, shown as \"User feedback\" on the linked trace in\n * PostHog's AI observability UI.\n */\n async onFeedbackEvent(event: FeedbackEvent): Promise<void> {\n if (!this.#client) return;\n\n const { feedback } = event;\n if (!feedback.traceId) {\n this.logger.debug('PostHog exporter: dropping feedback with no traceId; PostHog requires $ai_trace_id', {\n feedbackId: feedback.feedbackId,\n });\n return;\n }\n\n const properties: Record<string, any> = {\n // Custom metadata goes first so it cannot overwrite the natively mapped fields below\n ...this.extractCustomMetadata(feedback.metadata),\n $ai_trace_id: feedback.traceId,\n // PostHog's trace UI only displays feedback events that carry $ai_feedback_text\n $ai_feedback_text: feedback.comment ?? String(feedback.value),\n feedback_id: feedback.feedbackId,\n feedback_type: feedback.feedbackType,\n feedback_value: feedback.value,\n };\n\n const feedbackSource = feedback.feedbackSource ?? feedback.source;\n if (feedbackSource) properties.feedback_source = feedbackSource;\n if (feedback.spanId) properties.span_id = feedback.spanId;\n if (feedback.sourceId) properties.source_id = feedback.sourceId;\n if (feedback.metadata?.sessionId) properties.$ai_session_id = feedback.metadata.sessionId;\n\n try {\n this.#client.captureAi(\n this.withGroups({\n distinctId: this.getFeedbackDistinctId(feedback),\n event: '$ai_feedback',\n properties,\n timestamp: new Date(feedback.timestamp),\n }),\n );\n } catch (err) {\n this.logger.error('PostHog exporter: failed to submit feedback', {\n error: err,\n traceId: feedback.traceId,\n feedbackId: feedback.feedbackId,\n });\n }\n }\n\n private getFeedbackDistinctId(feedback: ExportedFeedback): string {\n const userId = feedback.feedbackUserId ?? feedback.userId ?? feedback.metadata?.userId;\n if (userId) {\n return String(userId);\n }\n return this.config.defaultDistinctId ?? 'anonymous';\n }\n\n /**\n * PostHog group analytics are keyed off the top-level `groups` field on the\n * capture call. The Node SDK derives the event's `$groups` from that field and\n * overwrites any property-level `$groups`, so group metadata carried in\n * properties is dropped unless it is mirrored here.\n */\n private withGroups(message: EventMessage): EventMessage {\n const groups = message.properties?.$groups;\n if (groups && typeof groups === 'object' && !Array.isArray(groups)) {\n return { ...message, groups };\n }\n return message;\n }\n\n private buildEventMessage(args: { span: AnyExportedSpan; traceData: PosthogTraceData }): EventMessage {\n const { span, traceData } = args;\n\n const endTime = span.endTime ? this.toDate(span.endTime).getTime() : Date.now();\n\n const distinctId = this.getDistinctId(span, traceData);\n\n if (span.isRootSpan) {\n return this.buildRootEventMessage({ span, distinctId, endTime });\n } else {\n return this.buildChildEventMessage({ span, distinctId, endTime, traceData });\n }\n }\n\n /**\n * Capture an explicit $ai_trace event for root spans.\n * This gives us control over trace-level metadata like name and tags,\n * rather than relying on PostHog's pseudo-trace auto-creation.\n */\n private buildRootEventMessage(args: { span: AnyExportedSpan; distinctId: string; endTime: number }): EventMessage {\n const { span, distinctId, endTime } = args;\n\n // Note: We don't set $ai_latency on $ai_trace events because PostHog\n // aggregates latency from child events. Setting it here causes double-counting.\n const traceProperties: Record<string, any> = {\n $ai_trace_id: span.traceId,\n $ai_span_name: span.name,\n $ai_is_error: !!span.errorInfo,\n };\n\n if (span.metadata?.sessionId) {\n traceProperties.$ai_session_id = span.metadata.sessionId;\n }\n\n if (span.input) {\n traceProperties.$ai_input_state = span.input;\n }\n\n if (span.output) {\n traceProperties.$ai_output_state = span.output;\n }\n\n if (span.errorInfo) {\n traceProperties.$ai_error = {\n message: span.errorInfo.message,\n ...(span.errorInfo.id && { id: span.errorInfo.id }),\n ...(span.errorInfo.category && { category: span.errorInfo.category }),\n };\n }\n\n // Add tags as custom properties (PostHog doesn't have native tag support on traces)\n if (span.tags?.length) {\n for (const tag of span.tags) {\n traceProperties[tag] = true;\n }\n }\n\n // Add custom metadata (excluding userId and sessionId which are handled separately)\n const { userId, sessionId, ...customMetadata } = span.metadata ?? {};\n Object.assign(traceProperties, customMetadata);\n\n // A served MCP request is always a root span. Keep the caller's W3C context\n // on the trace, since PostHog has no span links to point at the caller.\n if (span.type === SpanType.MCP_SERVER_REQUEST) {\n const { callerTraceparent, callerTracestate } = (span.attributes ?? {}) as {\n callerTraceparent?: string;\n callerTracestate?: string;\n };\n if (callerTraceparent) traceProperties.callerTraceparent = callerTraceparent;\n if (callerTracestate) traceProperties.callerTracestate = callerTracestate;\n }\n\n return {\n distinctId,\n event: '$ai_trace',\n properties: traceProperties,\n timestamp: new Date(endTime),\n };\n }\n\n private buildChildEventMessage(args: {\n span: AnyExportedSpan;\n distinctId: string;\n endTime: number;\n traceData: PosthogTraceData;\n }): EventMessage {\n const { span, distinctId, endTime, traceData } = args;\n\n const isModelCall = this.isModelCall(span);\n const startTime = span.startTime.getTime();\n const latency = (endTime - startTime) / 1000;\n\n // Check if parent is the root span - if so, use traceId as parent_id\n // since we don't create an $ai_span for root spans\n const parentIsRootSpan = this.isParentRootSpan(span, traceData);\n const properties = this.buildEventProperties(span, latency, parentIsRootSpan, isModelCall);\n\n return {\n distinctId,\n event: isModelCall ? '$ai_generation' : '$ai_span',\n properties,\n timestamp: new Date(endTime),\n };\n }\n\n private toDate(timestamp: Date | number): Date {\n return timestamp instanceof Date ? timestamp : new Date(timestamp);\n }\n\n /**\n * Whether this span is exported as `$ai_generation`. PostHog expects one per\n * provider call and sums tokens and cost across them, so exactly one span\n * per call may carry usage. With paired packages that emit MODEL_INFERENCE,\n * that is the call and MODEL_GENERATION is the loop around it, exported as\n * `$ai_span`. Older pairings only emit MODEL_GENERATION, which keeps the\n * `$ai_generation` role.\n */\n private isModelCall(span: AnyExportedSpan): boolean {\n return span.type === (isModelInferenceEnabled() ? SpanType.MODEL_INFERENCE : SpanType.MODEL_GENERATION);\n }\n\n /**\n * Give a MODEL_INFERENCE exported as `$ai_generation` the conversation that\n * call received. The span has no input of its own, so it is rebuilt from the\n * generation's input plus, for each earlier call in the same generation, its\n * output and the results of the tools it called (as Braintrust's Thread view\n * does). Earlier calls and their tools end before this call does, so they are\n * already recorded.\n */\n private withCallInput(span: AnyExportedSpan, traceData: PosthogTraceData): AnyExportedSpan {\n if (span.type !== SpanType.MODEL_INFERENCE || !this.isModelCall(span)) return span;\n\n const generation = this.findGeneration(span, traceData);\n if (!generation?.input) return span;\n\n const messages = this.formatMessages(generation.input, 'user');\n const conversation = traceData.getExtraValue(CONVERSATION + generation.id) as Conversation | undefined;\n for (const call of conversation?.calls ?? []) {\n const output = call.output as\n | { text?: string; toolCalls?: Array<{ toolCallId: string; toolName: string }> }\n | undefined;\n if (!output?.text && !output?.toolCalls?.length) continue;\n messages.push(...this.formatMessages(output, 'assistant'));\n\n // Parallel tool calls are ordered by when each tool started.\n const results = (output.toolCalls ?? [])\n .map(toolCall => ({ toolCall, toolSpan: conversation!.toolResults.get(toolCall.toolCallId) }))\n .filter(\n (result): result is { toolCall: typeof result.toolCall; toolSpan: AnyExportedSpan } => !!result.toolSpan,\n )\n .sort((a, b) => this.toDate(a.toolSpan.startTime).getTime() - this.toDate(b.toolSpan.startTime).getTime());\n for (const { toolCall, toolSpan } of results) {\n // Provider-executed tools report failure through `success`, not `errorInfo`.\n const isError =\n !!toolSpan.errorInfo ||\n (toolSpan.type === SpanType.PROVIDER_TOOL_CALL &&\n (toolSpan.attributes as { success?: boolean } | undefined)?.success === false);\n // Same `tool-result` part shape PostHog's own AI SDK integrations send.\n messages.push({\n role: 'tool',\n content: [\n {\n type: 'tool-result',\n toolCallId: toolCall.toolCallId,\n toolName: toolCall.toolName,\n output: toolSpan.errorInfo ? toolSpan.errorInfo.message : toolSpan.output,\n ...(isError ? { isError: true } : {}),\n },\n ],\n });\n }\n }\n\n return { ...span, input: messages };\n }\n\n /** Record ended calls and tool results so later calls in the same generation can rebuild their input. */\n private recordForConversation(span: AnyExportedSpan, traceData: PosthogTraceData): void {\n const isCall = span.type === SpanType.MODEL_INFERENCE && !span.errorInfo;\n // A PROVIDER_TOOL_CALL span ended without a result (e.g. the run stopped first)\n // has no `success`, and recording it would add an empty result.\n const isProviderToolWithResult =\n span.type === SpanType.PROVIDER_TOOL_CALL &&\n typeof (span.attributes as { success?: unknown } | undefined)?.success === 'boolean';\n const isTool = span.type === SpanType.TOOL_CALL || span.type === SpanType.MCP_TOOL_CALL || isProviderToolWithResult;\n if (!isModelInferenceEnabled() || (!isCall && !isTool)) return;\n\n const generation = this.findGeneration(span, traceData);\n if (!generation) return;\n\n const key = CONVERSATION + generation.id;\n let conversation = traceData.getExtraValue(key) as Conversation | undefined;\n if (!conversation) {\n conversation = { calls: [], toolResults: new Map() };\n traceData.setExtraValue(key, conversation);\n }\n if (isCall) {\n conversation.calls.push(span);\n } else {\n const toolCallId = this.resolveToolCallId(span);\n if (toolCallId) conversation.toolResults.set(toolCallId, span);\n }\n }\n\n private findGeneration(span: AnyExportedSpan, traceData: PosthogTraceData): AnyExportedSpan | undefined {\n let ancestor = span.parentSpanId ? traceData.getSpan({ spanId: span.parentSpanId }) : undefined;\n while (ancestor && ancestor.type !== SpanType.MODEL_GENERATION) {\n ancestor = ancestor.parentSpanId ? traceData.getSpan({ spanId: ancestor.parentSpanId }) : undefined;\n }\n return ancestor;\n }\n\n private resolveToolCallId(span: AnyExportedSpan): string | undefined {\n const attrs = span.attributes as { toolCallId?: string } | undefined;\n return (\n attrs?.toolCallId ??\n (span.metadata?.toolCallId as string | undefined) ??\n (span.input as { toolCallId?: string } | undefined)?.toolCallId\n );\n }\n\n private getDistinctId(span: AnyExportedSpan, traceData?: PosthogTraceData): string {\n if (span.metadata?.userId) {\n return String(span.metadata.userId);\n }\n\n if (traceData?.hasExtraValue(DISTINCT_ID)) {\n return String(traceData.getExtraValue(DISTINCT_ID));\n }\n\n if (this.config.defaultDistinctId) {\n return this.config.defaultDistinctId;\n }\n\n return 'anonymous';\n }\n\n /**\n * Check if the parent of this span is the root span.\n * We need this because we don't create $ai_span for root spans,\n * so children of root spans should use $ai_trace_id as their $ai_parent_id.\n */\n private isParentRootSpan(span: AnyExportedSpan, traceData: PosthogTraceData): boolean {\n if (!span.parentSpanId) {\n return false;\n }\n\n // Look up the parent span in our cache to check if it's a root span\n const parentCache = traceData.getSpan({ spanId: span.parentSpanId });\n if (parentCache) {\n return parentCache.isRootSpan;\n }\n\n // Parent not found in cache - shouldn't happen normally, but default to false\n return false;\n }\n\n private buildEventProperties(\n span: AnyExportedSpan,\n latency: number,\n parentIsRootSpan: boolean = false,\n isModelCall: boolean = this.isModelCall(span),\n ): Record<string, any> {\n const baseProperties: Record<string, any> = {\n $ai_trace_id: span.traceId,\n $ai_latency: latency,\n $ai_is_error: !!span.errorInfo,\n };\n\n if (span.parentSpanId) {\n // If parent is the root span, use trace_id as parent_id since we don't\n // create an $ai_span for root spans (only $ai_trace)\n baseProperties.$ai_parent_id = parentIsRootSpan ? span.traceId : span.parentSpanId;\n }\n\n if (span.metadata?.sessionId) {\n baseProperties.$ai_session_id = span.metadata.sessionId;\n }\n\n // Include tags for root spans (tags are only set on root spans by design)\n // PostHog doesn't allow setting tags directly, so we iterate through each tag\n // and set it as a property with value true\n if (span.isRootSpan && span.tags?.length) {\n for (const tag of span.tags) {\n baseProperties[tag] = true;\n }\n }\n\n if (isModelCall) {\n baseProperties.$ai_generation_id = span.id;\n return { ...baseProperties, ...this.buildGenerationProperties(span) };\n } else {\n baseProperties.$ai_span_id = span.id;\n baseProperties.$ai_span_name = span.name;\n return { ...baseProperties, ...this.buildSpanProperties(span) };\n }\n }\n\n private extractErrorProperties(errorInfo?: SpanErrorInfo): Record<string, any> {\n if (!errorInfo) {\n return {};\n }\n\n const props: Record<string, string> = {\n error_message: errorInfo.message,\n };\n\n if (errorInfo.id) {\n props.error_id = errorInfo.id;\n }\n\n if (errorInfo.category) {\n props.error_category = errorInfo.category;\n }\n\n return props;\n }\n\n private extractCustomMetadata(metadata?: Record<string, unknown>): Record<string, any> {\n const { userId, sessionId, ...customMetadata } = metadata ?? {};\n return customMetadata;\n }\n\n private buildGenerationProperties(span: AnyExportedSpan): Record<string, any> {\n const props: Record<string, any> = {};\n const attrs = (span.attributes ?? {}) as ModelGenerationAttributes;\n\n props.$ai_model = attrs.model || 'unknown-model';\n props.$ai_provider = attrs.provider || 'unknown-provider';\n\n if (span.input) props.$ai_input = this.formatMessages(span.input, 'user');\n if (span.output) props.$ai_output_choices = this.formatMessages(span.output, 'assistant');\n\n // Extract usage properties using the shared utility\n Object.assign(props, formatUsageMetrics(attrs.usage));\n\n if (attrs.parameters) {\n if (attrs.parameters.temperature !== undefined) props.$ai_temperature = attrs.parameters.temperature;\n if (attrs.parameters.maxOutputTokens !== undefined) props.$ai_max_tokens = attrs.parameters.maxOutputTokens;\n }\n if (attrs.streaming !== undefined) props.$ai_stream = attrs.streaming;\n if (attrs.tools?.length) {\n // OpenAI-style shape — the format PostHog's own AI SDKs send and its\n // trace view renders. Provider-defined tools pass through as-is.\n props.$ai_tools = attrs.tools.map(tool =>\n tool.type === 'function'\n ? {\n type: 'function',\n function: { name: tool.name, description: tool.description, parameters: tool.parameters },\n }\n : tool,\n );\n }\n\n return { ...props, ...this.extractErrorProperties(span.errorInfo), ...this.extractCustomMetadata(span.metadata) };\n }\n\n private buildSpanProperties(span: AnyExportedSpan): Record<string, any> {\n const props: Record<string, any> = {};\n\n if (span.input) props.$ai_input_state = span.input;\n if (span.output) props.$ai_output_state = span.output;\n\n if (span.type === SpanType.MODEL_CHUNK) {\n const attrs = span.attributes as any;\n if (attrs?.chunkType) props.chunk_type = attrs.chunkType;\n if (attrs?.sequenceNumber !== undefined) props.chunk_sequence_number = attrs.sequenceNumber;\n }\n\n if (span.attributes) {\n Object.assign(props, span.attributes);\n }\n\n return { ...props, ...this.extractErrorProperties(span.errorInfo), ...this.extractCustomMetadata(span.metadata) };\n }\n\n private formatMessages(data: SpanData, defaultRole: 'user' | 'assistant' = 'user'): PostHogMessage[] {\n // Unwrap {messages: [...]} wrapper produced by generation span inputs\n if (typeof data === 'object' && data !== null && !Array.isArray(data) && 'messages' in data) {\n const wrapped = (data as Record<string, unknown>).messages;\n if (this.isMessageArray(wrapped)) {\n return wrapped.map(msg => this.normalizeMessage(msg));\n }\n }\n\n if (this.isMessageArray(data)) {\n return data.map(msg => this.normalizeMessage(msg));\n }\n\n if (typeof data === 'string') {\n return [{ role: defaultRole, content: [{ type: 'text', text: data }] }];\n }\n\n if (this.isSpanOutputWithToolCalls(data)) {\n const content: PostHogContent[] = [];\n if (data.text) {\n content.push({ type: 'text', text: data.text });\n }\n for (const tc of data.toolCalls) {\n content.push({\n type: 'tool-call',\n id: tc.toolCallId,\n function: { name: tc.toolName, arguments: tc.args },\n });\n }\n return [{ role: 'assistant', content }];\n }\n\n // Extract text from output objects (e.g. generation outputs with text but no tool calls)\n if (typeof data === 'object' && data !== null && !Array.isArray(data) && 'text' in data) {\n const text = (data as Record<string, unknown>).text;\n if (typeof text === 'string') {\n return [{ role: defaultRole, content: [{ type: 'text', text }] }];\n }\n }\n\n return [{ role: defaultRole, content: [{ type: 'text', text: this.safeStringify(data) }] }];\n }\n\n private isSpanOutputWithToolCalls(\n data: unknown,\n ): data is { text?: string; toolCalls: Array<{ toolCallId: string; toolName: string; args: unknown }> } {\n if (typeof data !== 'object' || data === null || !('toolCalls' in data)) return false;\n const { toolCalls } = data as Record<string, unknown>;\n return Array.isArray(toolCalls) && toolCalls.length > 0;\n }\n\n private isMessageArray(data: unknown): data is MastraMessage[] {\n if (!Array.isArray(data)) {\n return false;\n }\n\n return data.every(item => typeof item === 'object' && item !== null && 'role' in item && 'content' in item);\n }\n\n private normalizeMessage(msg: MastraMessage): PostHogMessage {\n if (typeof msg.content === 'string') {\n return {\n role: msg.role as PostHogMessage['role'],\n content: [{ type: 'text', text: msg.content }],\n };\n }\n\n return {\n role: msg.role as PostHogMessage['role'],\n content: msg.content as PostHogContent[],\n };\n }\n\n private safeStringify(data: unknown): string {\n try {\n return JSON.stringify(data);\n } catch {\n if (typeof data === 'object' && data !== null) {\n return `[Non-serializable ${data.constructor?.name || 'Object'}]`;\n }\n return String(data);\n }\n }\n\n /**\n * Force flush any buffered data to PostHog without shutting down.\n */\n protected override async _flush(): Promise<void> {\n if (this.#client) {\n await this.#client.flush();\n }\n }\n\n override async _postShutdown(): Promise<void> {\n if (this.#client) {\n await this.#client.shutdown();\n }\n }\n}\n"],"mappings":"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"}
|
package/dist/tracing.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tracing.d.ts","sourceRoot":"","sources":["../src/tracing.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"tracing.d.ts","sourceRoot":"","sources":["../src/tracing.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mastra/posthog",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.1-alpha.0",
|
|
4
4
|
"description": "PostHog observability provider for Mastra",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"license": "Apache-2.0",
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"posthog-node": "^5.49.0",
|
|
27
|
-
"@mastra/observability": "1.
|
|
27
|
+
"@mastra/observability": "1.20.0-alpha.0"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"@types/node": "22.20.1",
|
|
@@ -32,10 +32,10 @@
|
|
|
32
32
|
"tsdown": "0.22.9",
|
|
33
33
|
"typescript": "^7.0.2",
|
|
34
34
|
"vitest": "4.1.11",
|
|
35
|
-
"@internal/lint": "0.0.
|
|
36
|
-
"@
|
|
37
|
-
"@
|
|
38
|
-
"@
|
|
35
|
+
"@internal/lint": "0.0.142",
|
|
36
|
+
"@observability/test-utils": "0.1.0",
|
|
37
|
+
"@internal/types-builder": "0.0.117",
|
|
38
|
+
"@mastra/core": "1.77.0-alpha.1"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
41
41
|
"@mastra/core": ">=1.16.0-0 <2.0.0-0"
|