diff --git a/.changeset/beige-colts-design.md b/.changeset/beige-colts-design.md new file mode 100644 index 000000000..499e591a5 --- /dev/null +++ b/.changeset/beige-colts-design.md @@ -0,0 +1,5 @@ +--- +'@tanstack/ai': minor +--- + +Added telemetry field to activities and events diff --git a/packages/typescript/ai/src/activities/chat/index.ts b/packages/typescript/ai/src/activities/chat/index.ts index feb5ef995..ed307b594 100644 --- a/packages/typescript/ai/src/activities/chat/index.ts +++ b/packages/typescript/ai/src/activities/chat/index.ts @@ -28,6 +28,7 @@ import type { RunFinishedEvent, SchemaInput, StreamChunk, + TelemetrySettings, TextMessageContentEvent, TextOptions, Tool, @@ -130,6 +131,10 @@ export interface TextActivityOptions< * ``` */ stream?: TStream + /** + * Telemetry data for tracking and monitoring. + */ + telemetry?: TextOptions['telemetry'] } // =========================== @@ -209,6 +214,7 @@ class TextEngine< private readonly streamId: string private readonly effectiveRequest?: Request | RequestInit private readonly effectiveSignal?: AbortSignal + private readonly telemetry?: TelemetrySettings private messages: Array private iterationCount = 0 @@ -241,6 +247,7 @@ class TextEngine< ? { signal: config.params.abortController.signal } : undefined this.effectiveSignal = config.params.abortController?.signal + this.telemetry = config.params.telemetry } /** Get the accumulated content after the chat loop completes */ @@ -942,6 +949,7 @@ class TextEngine< messageCount: number hasTools: boolean streaming: boolean + telemetry?: TelemetrySettings } { return { requestId: this.requestId, @@ -960,6 +968,7 @@ class TextEngine< messageCount: this.initialMessageCount, hasTools: this.tools.length > 0, streaming: true, + telemetry: this.telemetry, } } @@ -1194,10 +1203,10 @@ async function runAgenticStructuredOutput( } // Re-export adapter types +export { BaseTextAdapter } from './adapter' export type { - TextAdapter, - TextAdapterConfig, StructuredOutputOptions, StructuredOutputResult, + TextAdapter, + TextAdapterConfig, } from './adapter' -export { BaseTextAdapter } from './adapter' diff --git a/packages/typescript/ai/src/activities/generateImage/index.ts b/packages/typescript/ai/src/activities/generateImage/index.ts index d573b32f1..0caaa96af 100644 --- a/packages/typescript/ai/src/activities/generateImage/index.ts +++ b/packages/typescript/ai/src/activities/generateImage/index.ts @@ -6,8 +6,8 @@ */ import { aiEventClient } from '../../event-client.js' +import type { ImageGenerationOptions, ImageGenerationResult } from '../../types' import type { ImageAdapter } from './adapter' -import type { ImageGenerationResult } from '../../types' // =========================== // Activity Kind @@ -74,6 +74,10 @@ export interface ImageActivityOptions< size?: ImageSizeForModel /** Provider-specific options for image generation */ modelOptions?: ImageProviderOptionsForModel + /** + * Telemetry data for tracking and monitoring. + */ + telemetry?: ImageGenerationOptions['telemetry'] } // =========================== @@ -152,6 +156,7 @@ export async function generateImage< numberOfImages: rest.numberOfImages, size: rest.size as string | undefined, modelOptions: rest.modelOptions as Record | undefined, + telemetry: rest.telemetry, timestamp: startTime, }) @@ -168,6 +173,7 @@ export async function generateImage< })), duration, modelOptions: rest.modelOptions as Record | undefined, + telemetry: rest.telemetry, timestamp: Date.now(), }) @@ -177,6 +183,7 @@ export async function generateImage< model, usage: result.usage, modelOptions: rest.modelOptions as Record | undefined, + telemetry: rest.telemetry, timestamp: Date.now(), }) } @@ -199,9 +206,9 @@ export function createImageOptions< } // Re-export adapter types +export { BaseImageAdapter } from './adapter' export type { + AnyImageAdapter, ImageAdapter, ImageAdapterConfig, - AnyImageAdapter, } from './adapter' -export { BaseImageAdapter } from './adapter' diff --git a/packages/typescript/ai/src/activities/generateSpeech/index.ts b/packages/typescript/ai/src/activities/generateSpeech/index.ts index 39645ebab..2c0024573 100644 --- a/packages/typescript/ai/src/activities/generateSpeech/index.ts +++ b/packages/typescript/ai/src/activities/generateSpeech/index.ts @@ -6,8 +6,8 @@ */ import { aiEventClient } from '../../event-client.js' +import type { TTSOptions, TTSResult } from '../../types' import type { TTSAdapter } from './adapter' -import type { TTSResult } from '../../types' // =========================== // Activity Kind @@ -53,6 +53,10 @@ export interface TTSActivityOptions< speed?: number /** Provider-specific options for TTS generation */ modelOptions?: TTSProviderOptions + /** + * Telemetry data for tracking and monitoring. + */ + telemetry?: TTSOptions['telemetry'] } // =========================== @@ -117,6 +121,7 @@ export async function generateSpeech< format: rest.format, speed: rest.speed, modelOptions: rest.modelOptions as Record | undefined, + telemetry: rest.telemetry, timestamp: startTime, }) @@ -133,6 +138,7 @@ export async function generateSpeech< contentType: result.contentType, duration, modelOptions: rest.modelOptions as Record | undefined, + telemetry: rest.telemetry, timestamp: Date.now(), }) @@ -154,5 +160,5 @@ export function createSpeechOptions< } // Re-export adapter types -export type { TTSAdapter, TTSAdapterConfig, AnyTTSAdapter } from './adapter' export { BaseTTSAdapter } from './adapter' +export type { AnyTTSAdapter, TTSAdapter, TTSAdapterConfig } from './adapter' diff --git a/packages/typescript/ai/src/activities/generateTranscription/index.ts b/packages/typescript/ai/src/activities/generateTranscription/index.ts index dff9a477b..292bca5da 100644 --- a/packages/typescript/ai/src/activities/generateTranscription/index.ts +++ b/packages/typescript/ai/src/activities/generateTranscription/index.ts @@ -6,8 +6,8 @@ */ import { aiEventClient } from '../../event-client.js' +import type { TranscriptionOptions, TranscriptionResult } from '../../types' import type { TranscriptionAdapter } from './adapter' -import type { TranscriptionResult } from '../../types' // =========================== // Activity Kind @@ -53,6 +53,10 @@ export interface TranscriptionActivityOptions< responseFormat?: 'json' | 'text' | 'srt' | 'verbose_json' | 'vtt' /** Provider-specific options for transcription */ modelOptions?: TranscriptionProviderOptions + /** + * Telemetry data for tracking and monitoring. + */ + telemetry?: TranscriptionOptions['telemetry'] } // =========================== @@ -120,6 +124,7 @@ export async function generateTranscription< prompt: rest.prompt, responseFormat: rest.responseFormat, modelOptions: rest.modelOptions as Record | undefined, + telemetry: rest.telemetry, timestamp: startTime, }) @@ -134,6 +139,7 @@ export async function generateTranscription< language: result.language, duration, modelOptions: rest.modelOptions as Record | undefined, + telemetry: rest.telemetry, timestamp: Date.now(), }) @@ -156,9 +162,9 @@ export function createTranscriptionOptions< } // Re-export adapter types +export { BaseTranscriptionAdapter } from './adapter' export type { + AnyTranscriptionAdapter, TranscriptionAdapter, TranscriptionAdapterConfig, - AnyTranscriptionAdapter, } from './adapter' -export { BaseTranscriptionAdapter } from './adapter' diff --git a/packages/typescript/ai/src/activities/generateVideo/index.ts b/packages/typescript/ai/src/activities/generateVideo/index.ts index 9a7a46aa4..da9aae443 100644 --- a/packages/typescript/ai/src/activities/generateVideo/index.ts +++ b/packages/typescript/ai/src/activities/generateVideo/index.ts @@ -8,12 +8,13 @@ */ import { aiEventClient } from '../../event-client.js' -import type { VideoAdapter } from './adapter' import type { + VideoGenerationOptions, VideoJobResult, VideoStatusResult, VideoUrlResult, } from '../../types' +import type { VideoAdapter } from './adapter' // =========================== // Activity Kind @@ -51,6 +52,10 @@ interface VideoActivityBaseOptions< > { /** The video adapter to use (must be created with a model) */ adapter: TAdapter & { kind: typeof kind } + /** + * Telemetry data for tracking and monitoring. + */ + telemetry?: VideoGenerationOptions['telemetry'] } /** @@ -202,16 +207,15 @@ export async function generateVideo< */ export async function getVideoJobStatus< TAdapter extends VideoAdapter, ->(options: { - adapter: TAdapter & { kind: typeof kind } - jobId: string -}): Promise<{ +>( + options: VideoStatusOptions, +): Promise<{ status: 'pending' | 'processing' | 'completed' | 'failed' progress?: number url?: string error?: string }> { - const { adapter, jobId } = options + const { adapter, jobId, ...rest } = options const requestId = createId('video-status') const startTime = Date.now() @@ -221,6 +225,7 @@ export async function getVideoJobStatus< model: adapter.model, requestType: 'status', jobId, + telemetry: rest.telemetry, timestamp: startTime, }) @@ -241,6 +246,7 @@ export async function getVideoJobStatus< progress: statusResult.progress, url: urlResult.url, duration: Date.now() - startTime, + telemetry: rest.telemetry, timestamp: Date.now(), }) return { @@ -260,6 +266,7 @@ export async function getVideoJobStatus< error: error instanceof Error ? error.message : 'Failed to get video URL', duration: Date.now() - startTime, + telemetry: rest.telemetry, timestamp: Date.now(), }) // If URL fetch fails, still return status @@ -282,6 +289,7 @@ export async function getVideoJobStatus< progress: statusResult.progress, error: statusResult.error, duration: Date.now() - startTime, + telemetry: rest.telemetry, timestamp: Date.now(), }) @@ -307,9 +315,9 @@ export function createVideoOptions< } // Re-export adapter types +export { BaseVideoAdapter } from './adapter' export type { + AnyVideoAdapter, VideoAdapter, VideoAdapterConfig, - AnyVideoAdapter, } from './adapter' -export { BaseVideoAdapter } from './adapter' diff --git a/packages/typescript/ai/src/activities/summarize/index.ts b/packages/typescript/ai/src/activities/summarize/index.ts index ddee4280a..f28510324 100644 --- a/packages/typescript/ai/src/activities/summarize/index.ts +++ b/packages/typescript/ai/src/activities/summarize/index.ts @@ -6,12 +6,12 @@ */ import { aiEventClient } from '../../event-client.js' -import type { SummarizeAdapter } from './adapter' import type { StreamChunk, SummarizationOptions, SummarizationResult, } from '../../types' +import type { SummarizeAdapter } from './adapter' // =========================== // Activity Kind @@ -65,6 +65,10 @@ export interface SummarizeActivityOptions< * @default false */ stream?: TStream + /** + * Telemetry data for tracking and monitoring. + */ + telemetry?: SummarizationOptions['telemetry'] } // =========================== @@ -174,7 +178,7 @@ export function summarize< async function runSummarize( options: SummarizeActivityOptions, false>, ): Promise { - const { adapter, text, maxLength, style, focus } = options + const { adapter, text, maxLength, style, focus, telemetry } = options const model = adapter.model const requestId = createId('summarize') const inputLength = text.length @@ -185,6 +189,7 @@ async function runSummarize( provider: adapter.name, model, inputLength, + telemetry, timestamp: startTime, }) @@ -194,6 +199,7 @@ async function runSummarize( maxLength, style, focus, + telemetry, } const result = await adapter.summarize(summarizeOptions) @@ -208,6 +214,7 @@ async function runSummarize( inputLength, outputLength, duration, + telemetry, timestamp: Date.now(), }) @@ -231,6 +238,7 @@ async function* runStreamingSummarize( maxLength, style, focus, + telemetry: options.telemetry, } // Use real streaming if the adapter supports it @@ -280,9 +288,9 @@ export function createSummarizeOptions< } // Re-export adapter types +export { BaseSummarizeAdapter } from './adapter' export type { + AnySummarizeAdapter, SummarizeAdapter, SummarizeAdapterConfig, - AnySummarizeAdapter, } from './adapter' -export { BaseSummarizeAdapter } from './adapter' diff --git a/packages/typescript/ai/src/event-client.ts b/packages/typescript/ai/src/event-client.ts index b76d67055..b3567b2d4 100644 --- a/packages/typescript/ai/src/event-client.ts +++ b/packages/typescript/ai/src/event-client.ts @@ -1,5 +1,5 @@ import { EventClient } from '@tanstack/devtools-event-client' -import type { MessagePart, ToolCall } from './types' +import type { MessagePart, TelemetrySettings, ToolCall } from './types' /** * Tool call states - track the lifecycle of a tool call @@ -44,6 +44,7 @@ interface BaseEventContext { model?: string systemPrompts?: Array options?: Record + telemetry?: TelemetrySettings modelOptions?: Record toolNames?: Array messageCount?: number diff --git a/packages/typescript/ai/src/types.ts b/packages/typescript/ai/src/types.ts index 7bd3c52d9..e27f0707e 100644 --- a/packages/typescript/ai/src/types.ts +++ b/packages/typescript/ai/src/types.ts @@ -1,5 +1,34 @@ import type { StandardJSONSchemaV1 } from '@standard-schema/spec' +/** + * Type for telemetry metadata values. + * + * This type is intended to be replaced by OpenTelemetry AttributeType in the future. + */ +export type TelemetryMetadataValue = + | string + | number + | boolean + | Array + | Array + | Array + +/** + * Telemetry data for tracking and debugging. + */ +export type TelemetrySettings = { + /** + * Identifier for the specific function or operation being tracked. + */ + functionId?: string + + /** + * Arbitrary key-value pairs for tracking context. + * Common keys: userId, sessionId, billingAccount, environment, etc. + */ + metadata?: Record +} + /** * Tool call states - track the lifecycle of a tool call */ @@ -617,6 +646,10 @@ export interface TextOptions< * - Gemini: Not directly available in TextProviderOptions */ metadata?: Record + /** + * Telemetry data for tracking and monitoring. + */ + telemetry?: TelemetrySettings modelOptions?: TProviderOptionsForModel request?: Request | RequestInit @@ -912,6 +945,10 @@ export interface SummarizationOptions { maxLength?: number style?: 'bullet-points' | 'paragraph' | 'concise' focus?: Array + /** + * Telemetry data for tracking and monitoring. + */ + telemetry?: TelemetrySettings } export interface SummarizationResult { @@ -946,6 +983,10 @@ export interface ImageGenerationOptions< size?: string /** Model-specific options for image generation */ modelOptions?: TProviderOptions + /** + * Telemetry data for tracking and monitoring. + */ + telemetry?: TelemetrySettings } /** @@ -1001,6 +1042,10 @@ export interface VideoGenerationOptions< duration?: number /** Model-specific options for video generation */ modelOptions?: TProviderOptions + /** + * Telemetry data for tracking and monitoring. + */ + telemetry?: TelemetrySettings } /** @@ -1066,6 +1111,10 @@ export interface TTSOptions { speed?: number /** Model-specific options for TTS generation */ modelOptions?: TProviderOptions + /** + * Telemetry data for tracking and monitoring. + */ + telemetry?: TelemetrySettings } /** @@ -1109,6 +1158,10 @@ export interface TranscriptionOptions< responseFormat?: 'json' | 'text' | 'srt' | 'verbose_json' | 'vtt' /** Model-specific options for transcription */ modelOptions?: TProviderOptions + /** + * Telemetry data for tracking and monitoring. + */ + telemetry?: TelemetrySettings } /**