@tanstack/ai-client 0.20.0 → 0.22.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.
@@ -1 +1 @@
1
- {"version":3,"file":"devtools.js","sources":["../../src/devtools.ts"],"sourcesContent":["import {\n aiEventClient,\n createAIDevtoolsEventEnvelope,\n emitAIDevtoolsEvent,\n} from '@tanstack/ai-event-client'\nimport { convertSchemaToJsonSchema } from '@tanstack/ai/client'\nimport { DefaultChatClientEventEmitter } from './events'\nimport type { AnyClientTool, StreamChunk } from '@tanstack/ai/client'\nimport type { AIDevtoolsEventVisibility } from '@tanstack/ai-event-client'\nimport type {\n ChatClientEventContext,\n ChatClientEventEmitter,\n ChatClientRunEventContext,\n} from './events'\nimport type {\n ChatClientState,\n ConnectionStatus,\n MessagePart,\n ToolCallPart,\n UIMessage,\n} from './types'\n\nexport interface AIDevtoolsDisplayOptions {\n name?: string\n}\n\nexport interface AIDevtoolsClientMetadata extends AIDevtoolsDisplayOptions {\n framework?: string\n hookName: string\n outputKind?: 'chat' | 'text' | 'structured' | 'image' | 'video' | 'audio'\n}\n\nexport interface AIDevtoolsGenerationProgress {\n value: number\n message?: string\n}\n\nexport interface AIDevtoolsGenerationMediaItem {\n src: string\n sourceType: 'url' | 'base64'\n mimeType?: string\n format?: string\n duration?: number\n}\n\nexport interface AIDevtoolsGenerationVideoJob {\n jobId: string\n status?: string\n progress?: number\n error?: string\n}\n\nexport type AIDevtoolsGenerationPreview =\n | {\n kind: 'image'\n items: Array<AIDevtoolsGenerationMediaItem>\n }\n | {\n kind: 'audio'\n items: Array<AIDevtoolsGenerationMediaItem>\n }\n | {\n kind: 'video'\n items: Array<AIDevtoolsGenerationMediaItem>\n job?: AIDevtoolsGenerationVideoJob\n }\n | {\n kind: 'text'\n text: string\n }\n | {\n kind: 'structured'\n value: unknown\n }\n | {\n kind: 'empty'\n }\n\nexport type AIDevtoolsGenerationRunStatus =\n | 'idle'\n | 'generating'\n | 'success'\n | 'error'\n | 'cancelled'\n\nexport interface AIDevtoolsGenerationRunSnapshot<TOutput = unknown> {\n id: string\n input: unknown\n result: TOutput | null\n preview: AIDevtoolsGenerationPreview\n progress: AIDevtoolsGenerationProgress | null\n status: AIDevtoolsGenerationRunStatus\n isLoading: boolean\n startedAt: number\n updatedAt: number\n completedAt?: number\n error?: string\n jobId?: string | null\n videoStatus?: unknown\n}\n\nexport interface AIDevtoolsGenerationPreviewInput {\n outputKind?: AIDevtoolsClientMetadata['outputKind']\n result: unknown\n videoStatus?: unknown\n}\n\nexport interface AIDevtoolsChatSnapshot {\n [key: string]: unknown\n messages: Array<UIMessage>\n status: ChatClientState\n isLoading: boolean\n isSubscribed: boolean\n connectionStatus: ConnectionStatus\n sessionGenerating: boolean\n activeRunIds: Array<string>\n error?: string\n}\n\nexport function createAIDevtoolsGenerationPreview(\n input: AIDevtoolsGenerationPreviewInput,\n): AIDevtoolsGenerationPreview {\n if (input.outputKind === 'image') {\n return imagePreviewFromResult(input.result)\n }\n\n if (input.outputKind === 'audio') {\n return audioPreviewFromResult(input.result)\n }\n\n if (input.outputKind === 'video') {\n return videoPreviewFromResult(input.result, input.videoStatus)\n }\n\n if (input.outputKind === 'text') {\n return textPreviewFromResult(input.result)\n }\n\n if (input.result === null || input.result === undefined) {\n return { kind: 'empty' }\n }\n\n return {\n kind: 'structured',\n value: input.result,\n }\n}\n\ntype UnknownRecord = { [key: string]: unknown }\n\nfunction imagePreviewFromResult(result: unknown): AIDevtoolsGenerationPreview {\n const record = asRecord(result)\n const images = Array.isArray(record?.images) ? record.images : []\n const items = images\n .map((image) => mediaItemFromSource(image, 'image/png'))\n .filter(isGenerationMediaItem)\n\n if (items.length === 0 && result !== null && result !== undefined) {\n const directItem = mediaItemFromSource(result, 'image/png')\n if (directItem) {\n items.push(directItem)\n }\n }\n\n return { kind: 'image', items }\n}\n\nfunction audioPreviewFromResult(result: unknown): AIDevtoolsGenerationPreview {\n const record = asRecord(result)\n const audio = record?.audio\n const resultContentType = stringField(record, 'contentType')\n const format = stringField(record, 'format')\n const mimeType = resultContentType ?? mimeTypeFromAudioFormat(format)\n\n const items: Array<AIDevtoolsGenerationMediaItem> = []\n const directItem =\n typeof audio === 'string'\n ? base64MediaItem(audio, mimeType, {\n format,\n duration: numberField(record, 'duration'),\n })\n : mediaItemFromSource(audio, mimeType, {\n format,\n })\n\n if (directItem) {\n items.push(directItem)\n }\n\n return { kind: 'audio', items }\n}\n\nfunction videoPreviewFromResult(\n result: unknown,\n videoStatus: unknown,\n): AIDevtoolsGenerationPreview {\n const resultRecord = asRecord(result)\n const statusRecord = asRecord(videoStatus)\n const item =\n mediaItemFromSource(result, 'video/mp4') ??\n mediaItemFromSource(videoStatus, 'video/mp4')\n const items = item ? [item] : []\n const job = videoJobFromStatus(statusRecord ?? resultRecord)\n\n return {\n kind: 'video',\n items,\n ...(job ? { job } : {}),\n }\n}\n\nfunction textPreviewFromResult(result: unknown): AIDevtoolsGenerationPreview {\n const record = asRecord(result)\n const text =\n stringField(record, 'text') ??\n stringField(record, 'summary') ??\n stringField(record, 'content') ??\n (typeof result === 'string' ? result : undefined)\n\n if (text !== undefined) {\n return { kind: 'text', text }\n }\n\n if (result === null || result === undefined) {\n return { kind: 'empty' }\n }\n\n return {\n kind: 'structured',\n value: result,\n }\n}\n\nfunction videoJobFromStatus(\n record: UnknownRecord | undefined,\n): AIDevtoolsGenerationVideoJob | undefined {\n const jobId = stringField(record, 'jobId')\n if (!jobId) return undefined\n\n return {\n jobId,\n ...(stringField(record, 'status')\n ? { status: stringField(record, 'status') }\n : {}),\n ...(numberField(record, 'progress') !== undefined\n ? { progress: numberField(record, 'progress') }\n : {}),\n ...(stringField(record, 'error')\n ? { error: stringField(record, 'error') }\n : {}),\n }\n}\n\nfunction mediaItemFromSource(\n value: unknown,\n defaultMimeType: string,\n extras: {\n format?: string\n duration?: number\n } = {},\n): AIDevtoolsGenerationMediaItem | undefined {\n const record = asRecord(value)\n if (!record) return undefined\n\n const explicitContentType =\n stringField(record, 'contentType') ?? stringField(record, 'mimeType')\n const duration = numberField(record, 'duration') ?? extras.duration\n const format = stringField(record, 'format') ?? extras.format\n const url = stringField(record, 'url')\n if (url) {\n return {\n src: url,\n sourceType: 'url',\n ...(explicitContentType ? { mimeType: explicitContentType } : {}),\n ...(format ? { format } : {}),\n ...(duration !== undefined ? { duration } : {}),\n }\n }\n\n const b64Json = stringField(record, 'b64Json')\n if (!b64Json) return undefined\n\n return base64MediaItem(b64Json, explicitContentType ?? defaultMimeType, {\n format,\n duration,\n })\n}\n\nfunction base64MediaItem(\n value: string,\n mimeType: string | undefined,\n extras: {\n format?: string\n duration?: number\n } = {},\n): AIDevtoolsGenerationMediaItem {\n const src = value.startsWith('data:')\n ? value\n : `data:${mimeType ?? 'application/octet-stream'};base64,${value}`\n\n return {\n src,\n sourceType: 'base64',\n ...(mimeType ? { mimeType } : {}),\n ...(extras.format ? { format: extras.format } : {}),\n ...(extras.duration !== undefined ? { duration: extras.duration } : {}),\n }\n}\n\nfunction mimeTypeFromAudioFormat(format: string | undefined): string {\n if (!format) return 'audio/mpeg'\n if (format === 'mp3') return 'audio/mpeg'\n return `audio/${format}`\n}\n\nfunction asRecord(value: unknown): UnknownRecord | undefined {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n return undefined\n }\n return value as UnknownRecord\n}\n\nfunction stringField(\n record: UnknownRecord | undefined,\n field: string,\n): string | undefined {\n const value = record?.[field]\n return typeof value === 'string' && value.length > 0 ? value : undefined\n}\n\nfunction numberField(\n record: UnknownRecord | undefined,\n field: string,\n): number | undefined {\n const value = record?.[field]\n return typeof value === 'number' ? value : undefined\n}\n\nfunction isGenerationMediaItem(\n value: AIDevtoolsGenerationMediaItem | undefined,\n): value is AIDevtoolsGenerationMediaItem {\n return Boolean(value)\n}\n\nexport interface AIDevtoolsToolFixture {\n fixtureId?: string\n hookId?: string\n threadId?: string\n runId?: string\n toolName: string\n input: unknown\n output: unknown\n execute?: boolean\n message?: {\n id: string\n role: UIMessage['role']\n parts: Array<unknown>\n createdAt?: number | string\n }\n toolCallId?: string\n messageId?: string\n errorText?: string\n}\n\ntype AIDevtoolsRunEventType =\n | 'run:created'\n | 'run:started'\n | 'run:updated'\n | 'run:completed'\n | 'run:errored'\n | 'run:cancelled'\n\ntype AIDevtoolsRunStatus =\n | 'created'\n | 'started'\n | 'updated'\n | 'completed'\n | 'errored'\n | 'cancelled'\n\nexport interface AIDevtoolsBridgeOptions<TSnapshot extends object> {\n hookId: string\n threadId?: string\n clientId: string\n metadata: AIDevtoolsClientMetadata\n getSnapshot: () => TSnapshot\n getTools?: () => Iterable<AnyClientTool>\n applyToolFixture?: (fixture: AIDevtoolsToolFixture) => void | Promise<void>\n}\n\ntype Unsubscribe = () => void\n\ninterface AIDevtoolsEvent<TPayload> {\n payload: TPayload\n}\n\ninterface ActiveDevtoolsBridge {\n deactivate: () => void\n dispose: () => void\n supersede?: () => void\n}\n\nconst activeBridgeRegistryKey = Symbol.for(\n 'tanstack.ai.devtools.activeBridgeByHookId',\n)\n\nfunction getActiveBridgeRegistry(): Map<string, ActiveDevtoolsBridge> {\n const global = globalThis as typeof globalThis & {\n [activeBridgeRegistryKey]?: Map<string, ActiveDevtoolsBridge>\n }\n const existing = global[activeBridgeRegistryKey]\n if (existing) return existing\n\n const registry = new Map<string, ActiveDevtoolsBridge>()\n global[activeBridgeRegistryKey] = registry\n return registry\n}\n\nexport class ClientDevtoolsBridge<TSnapshot extends object> {\n protected readonly options: AIDevtoolsBridgeOptions<TSnapshot>\n private readonly bridgeId: string\n private readonly unsubscribers: Array<Unsubscribe> = []\n private disposed = false\n private superseded = false\n private registered = false\n\n constructor(options: AIDevtoolsBridgeOptions<TSnapshot>) {\n this.options = options\n this.bridgeId = createBridgeId(options.hookId)\n }\n\n emitRegistered(): void {\n if (!this.prepareForMountEmit()) {\n return\n }\n this.registered = true\n emitAIDevtoolsEvent('hook:registered', {\n ...this.createEnvelope('hook:registered'),\n ...this.createMetadataPayload(),\n lifecycle: 'mounted',\n })\n }\n\n emitUpdated(): void {\n if (!this.prepareForEmit()) {\n return\n }\n emitAIDevtoolsEvent('hook:updated', {\n ...this.createEnvelope('hook:updated'),\n ...this.createMetadataPayload(),\n lifecycle: 'active',\n })\n }\n\n emitSnapshot(): void {\n if (!this.prepareForEmit()) {\n return\n }\n emitAIDevtoolsEvent('hook:state-snapshot', {\n ...this.createEnvelope('hook:state-snapshot'),\n ...this.createMetadataPayload(),\n // Wire envelope uses Record<string, unknown>; widen the typed snapshot\n // here so the typed-snapshot constraint above can stay narrow.\n // eslint-disable-next-line no-restricted-syntax -- TSnapshot extends object is structurally compatible but TS can't see the missing index signature\n state: this.options.getSnapshot() as unknown as Record<string, unknown>,\n })\n }\n\n emitToolsRegistered(): void {\n if (!this.prepareForEmit()) {\n return\n }\n const tools = this.options.getTools\n ? Array.from(this.options.getTools()).map((tool) => ({\n name: tool.name,\n description: tool.description,\n inputSchema: tool.inputSchema\n ? convertSchemaToJsonSchema(tool.inputSchema)\n : { type: 'object' },\n outputSchema: tool.outputSchema\n ? convertSchemaToJsonSchema(tool.outputSchema)\n : undefined,\n needsApproval: tool.needsApproval,\n metadata: tool.metadata,\n }))\n : []\n\n emitAIDevtoolsEvent('tools:registered', {\n ...this.createEnvelope('tools:registered'),\n ...this.createMetadataPayload(),\n tools,\n })\n }\n\n emitRunLifecycle(\n eventType: AIDevtoolsRunEventType,\n runId: string,\n status: AIDevtoolsRunStatus,\n options: { error?: string } = {},\n ): void {\n if (!this.prepareForEmit()) {\n return\n }\n emitAIDevtoolsEvent(eventType, {\n ...this.createEnvelope(eventType, 'client-state', { runId }),\n runId,\n status,\n ...(options.error ? { error: options.error } : {}),\n })\n }\n\n deactivate(): void {\n const activeBridgeByHookId = getActiveBridgeRegistry()\n if (activeBridgeByHookId.get(this.options.hookId) === this) {\n activeBridgeByHookId.delete(this.options.hookId)\n }\n\n for (const unsubscribe of this.unsubscribers.splice(0)) {\n unsubscribe()\n }\n }\n\n supersede(): void {\n if (this.disposed) {\n return\n }\n\n this.superseded = true\n this.disposed = true\n this.deactivate()\n }\n\n dispose(): void {\n if (this.disposed) {\n return\n }\n\n this.disposed = true\n if (!this.registered) {\n this.deactivate()\n return\n }\n\n const payload = {\n ...this.createEnvelope('hook:unregistered'),\n ...this.createMetadataPayload(),\n reason: 'disposed',\n } as const\n\n emitAIDevtoolsEvent('hook:unregistered', payload)\n\n this.deactivate()\n }\n\n private prepareForEmit(): boolean {\n if (this.disposed || this.superseded) {\n return false\n }\n this.activate()\n return true\n }\n\n private prepareForMountEmit(): boolean {\n if (this.superseded) {\n return false\n }\n\n if (this.disposed) {\n this.disposed = false\n this.registered = false\n }\n\n this.activate()\n return true\n }\n\n private activate(): void {\n if (this.disposed) {\n return\n }\n\n const activeBridgeByHookId = getActiveBridgeRegistry()\n const activeBridge = activeBridgeByHookId.get(this.options.hookId)\n if (activeBridge && activeBridge !== this) {\n if (typeof activeBridge.supersede === 'function') {\n activeBridge.supersede()\n } else {\n activeBridge.deactivate()\n }\n }\n activeBridgeByHookId.set(this.options.hookId, this)\n\n if (this.unsubscribers.length > 0) {\n return\n }\n\n this.unsubscribers.push(\n aiEventClient.on('devtools:request-state', (event) => {\n this.handleRequestState(event)\n }),\n )\n\n if (this.options.applyToolFixture) {\n this.unsubscribers.push(\n aiEventClient.on('devtools:tool-fixture:apply', (event) => {\n void this.handleToolFixtureApply(event)\n }),\n )\n }\n }\n\n private handleRequestState(\n event: AIDevtoolsEvent<{ targetHookId?: string }>,\n ): void {\n if (this.disposed || this.superseded) {\n return\n }\n\n const targetHookId = event.payload.targetHookId\n if (targetHookId && targetHookId !== this.options.hookId) {\n return\n }\n\n this.emitRegistered()\n this.emitToolsRegistered()\n this.emitSnapshot()\n }\n\n private async handleToolFixtureApply(\n event: AIDevtoolsEvent<AIDevtoolsToolFixture>,\n ): Promise<void> {\n const fixture = event.payload\n if (!this.matchesFixtureTarget(fixture)) {\n return\n }\n\n await this.options.applyToolFixture?.(fixture)\n }\n\n private matchesFixtureTarget(fixture: AIDevtoolsToolFixture): boolean {\n if (!fixture.hookId && !fixture.threadId) {\n return false\n }\n\n if (fixture.hookId) {\n return fixture.hookId === this.options.hookId\n }\n\n if (\n fixture.threadId &&\n (!this.options.threadId || fixture.threadId !== this.options.threadId)\n ) {\n return false\n }\n return true\n }\n\n private createEnvelope(\n eventType:\n | 'hook:registered'\n | 'hook:updated'\n | 'hook:unregistered'\n | 'hook:state-snapshot'\n | 'tools:registered'\n | AIDevtoolsRunEventType,\n visibility: AIDevtoolsEventVisibility = 'client-state',\n context: { runId?: string } = {},\n ) {\n return createAIDevtoolsEventEnvelope({\n eventType,\n source: 'client',\n visibility,\n clientId: this.options.clientId,\n hookId: this.options.hookId,\n correlationId: this.bridgeId,\n ...(this.options.threadId ? { threadId: this.options.threadId } : {}),\n ...(context.runId ? { runId: context.runId } : {}),\n timestamp: Date.now(),\n })\n }\n\n private createMetadataPayload() {\n return {\n hookId: this.options.hookId,\n hookName: this.options.metadata.hookName,\n ...(this.options.metadata.name\n ? { displayName: this.options.metadata.name }\n : {}),\n ...(this.options.metadata.outputKind\n ? { outputKind: this.options.metadata.outputKind }\n : {}),\n ...(this.options.metadata.framework\n ? { framework: this.options.metadata.framework }\n : {}),\n }\n }\n}\n\nlet bridgeIdSequence = 0\n\nfunction createBridgeId(hookId: string): string {\n const cryptoLike = (\n globalThis as {\n crypto?: {\n randomUUID?: () => string\n }\n }\n ).crypto\n\n if (cryptoLike?.randomUUID) {\n return `bridge:${hookId}:${cryptoLike.randomUUID()}`\n }\n\n bridgeIdSequence += 1\n return `bridge:${hookId}:${bridgeIdSequence}`\n}\n\n// Owns the chat-client devtools surface so the chat client itself stays a\n// pure transport. Fixture replay, per-run / per-stream event context, and\n// snapshot emission all live here; a no-op bridge can drop in for prod.\n\nexport interface ChatDevtoolsBridgeOptions extends AIDevtoolsBridgeOptions<AIDevtoolsChatSnapshot> {\n getMessages: () => Array<UIMessage>\n setMessages: (messages: Array<UIMessage>) => void\n addToolResult: (\n toolCallId: string,\n output: unknown,\n errorText?: string,\n ) => void\n generateId: (prefix: string) => string\n}\n\nexport class ChatDevtoolsBridge extends ClientDevtoolsBridge<AIDevtoolsChatSnapshot> {\n readonly events: ChatClientEventEmitter\n private readonly chatOptions: ChatDevtoolsBridgeOptions\n private currentRunId: string | null = null\n private currentRunThreadId: string | null = null\n private currentStreamId: string | null = null\n private lastStreamId: string | null = null\n private lastRunEventContext: ChatClientRunEventContext | undefined\n\n constructor(options: ChatDevtoolsBridgeOptions) {\n super({\n ...options,\n // Thunk defers `this.applyFixture` lookup until after `super` returns.\n applyToolFixture: (fixture) => this.applyFixture(fixture),\n })\n this.chatOptions = options\n // Auto-attaches run/thread context and auto-emits a snapshot after each\n // event so callers can keep using `this.events.X(...)` with no context arg.\n this.events = new ChatDevtoolsAwareEventEmitter(options.clientId, this)\n }\n\n // --- Stream / run context API -------------------------------------------\n\n setCurrentStreamId(streamId: string | null): void {\n this.currentStreamId = streamId\n if (streamId) {\n this.lastStreamId = streamId\n }\n }\n\n /**\n * Called by the auto-attaching emitter every time it sees a non-empty\n * streamId pass through. Lets devtools track the latest stream id\n * without the chat client wiring it up explicitly.\n */\n recordStreamId(streamId: string): void {\n if (streamId) this.lastStreamId = streamId\n }\n\n mountWithTools(initialMessageCount: number): void {\n this.events.clientCreated(initialMessageCount)\n this.emitRegistered()\n this.emitToolsRegistered()\n this.emitSnapshot()\n }\n\n notifyToolsChanged(): void {\n this.emitToolsRegistered()\n this.emitSnapshot()\n }\n\n getCurrentStreamId(): string | null {\n return this.currentStreamId\n }\n\n getLastStreamId(): string | null {\n return this.lastStreamId\n }\n\n resolveStreamId(): string {\n return (\n this.currentStreamId ??\n this.lastStreamId ??\n this.chatOptions.generateId('stream')\n )\n }\n\n // Called when the chat client has just generated a runId for outbound emits;\n // the matching RUN_STARTED chunk from the adapter lands later and\n // observeChunk keeps the same context.\n beginRun(runId: string, threadId: string): void {\n this.currentRunId = runId\n this.currentRunThreadId = threadId\n this.lastRunEventContext = { runId, threadId }\n }\n\n observeChunk(chunk: StreamChunk): void {\n if (chunk.type === 'RUN_STARTED') {\n this.beginRun(chunk.runId, chunk.threadId)\n return\n }\n\n if (chunk.type === 'RUN_FINISHED' || chunk.type === 'RUN_ERROR') {\n const runId =\n chunk.type === 'RUN_FINISHED'\n ? chunk.runId\n : (chunk as { runId?: string }).runId\n if (!runId || runId === this.currentRunId) {\n const context = this.getCurrentRunEventContext()\n if (context) {\n this.lastRunEventContext = context\n }\n this.currentRunId = null\n this.currentRunThreadId = null\n }\n }\n }\n\n getCurrentRunEventContext(): ChatClientRunEventContext | undefined {\n if (!this.currentRunId) return undefined\n return {\n threadId: this.currentRunThreadId ?? this.chatOptions.threadId ?? '',\n runId: this.currentRunId,\n }\n }\n\n getCurrentOrLastRunEventContext(): ChatClientRunEventContext | undefined {\n return this.getCurrentRunEventContext() ?? this.lastRunEventContext\n }\n\n findToolCallContext(toolCallId: string): ChatClientEventContext {\n const base: ChatClientEventContext = { toolCallId }\n const runContext = this.getCurrentRunEventContext()\n if (runContext) {\n return {\n threadId: runContext.threadId,\n runId: runContext.runId,\n toolCallId,\n }\n }\n if (this.chatOptions.threadId) {\n return { threadId: this.chatOptions.threadId, toolCallId }\n }\n return base\n }\n\n // --- Fixture replay ------------------------------------------------------\n\n /**\n * Entry point invoked when the devtools panel emits\n * `devtools:tool-fixture:apply`. The chat client never calls this\n * directly; it is wired through the base bridge's fixture subscription.\n */\n async applyFixture(fixture: AIDevtoolsToolFixture): Promise<void> {\n const messages = this.chatOptions.getMessages()\n const threadId = fixture.threadId ?? this.chatOptions.threadId ?? ''\n if (fixture.execute) {\n await this.executeFixture(fixture, messages, threadId)\n return\n }\n\n const replay = this.createReplayMessageFromFixture(fixture, messages)\n const { message, toolCallId } = replay\n const messageId = message.id\n\n this.events.messageAppended(message, undefined, {\n threadId,\n toolCallId,\n ...(fixture.runId ? { runId: fixture.runId } : {}),\n })\n this.chatOptions.setMessages([...messages, message])\n this.events.toolFixtureApplied({\n hookId: this.chatOptions.hookId,\n threadId,\n ...(fixture.runId ? { runId: fixture.runId } : {}),\n toolName: fixture.toolName,\n input: fixture.input,\n output: fixture.output,\n messageId,\n toolCallId,\n ...(fixture.execute !== undefined ? { execute: fixture.execute } : {}),\n ...(fixture.message ? { message: fixture.message } : {}),\n ...(fixture.errorText ? { errorText: fixture.errorText } : {}),\n })\n this.emitSnapshot()\n }\n\n private async executeFixture(\n fixture: AIDevtoolsToolFixture,\n messages: Array<UIMessage>,\n threadId: string,\n ): Promise<void> {\n const toolCallId = this.resolveFixtureToolCallId(\n fixture.toolCallId,\n messages,\n )\n const messageId = this.resolveFixtureMessageId(fixture.messageId, messages)\n const message: UIMessage = {\n id: messageId,\n role: 'assistant',\n parts: [\n {\n type: 'tool-call',\n id: toolCallId,\n name: fixture.toolName,\n arguments: stringifyFixtureValue(fixture.input),\n input: fixture.input,\n state: 'input-complete',\n },\n ],\n createdAt: new Date(),\n }\n\n this.events.messageAppended(message, undefined, {\n threadId,\n toolCallId,\n ...(fixture.runId ? { runId: fixture.runId } : {}),\n })\n this.chatOptions.setMessages([...messages, message])\n this.emitSnapshot()\n\n const clientTool = this.findClientTool(fixture.toolName)\n const executeFunc = clientTool?.execute\n if (!executeFunc) {\n console.warn(\n `[ai-devtools] tool fixture \"${fixture.toolName}\" requested execute=true but no client tool implementation is registered; replaying saved output instead.`,\n )\n this.addToolResultForFixture({\n fixture,\n messageId,\n toolCallId,\n threadId,\n output: fixture.output,\n errorText: fixture.errorText,\n })\n return\n }\n\n let output: unknown\n try {\n output = await executeFunc(fixture.input)\n } catch (error) {\n console.error(\n `[ai-devtools] tool fixture \"${fixture.toolName}\" execute threw`,\n error,\n )\n this.addToolResultForFixture({\n fixture,\n messageId,\n toolCallId,\n threadId,\n output: null,\n errorText:\n error instanceof Error\n ? `${error.name}: ${error.message}`\n : `Tool execution failed: ${String(error)}`,\n })\n return\n }\n this.addToolResultForFixture({\n fixture,\n messageId,\n toolCallId,\n threadId,\n output,\n })\n }\n\n private addToolResultForFixture(input: {\n fixture: AIDevtoolsToolFixture\n messageId: string\n toolCallId: string\n threadId: string\n output: unknown\n errorText?: string\n }): void {\n const state = input.errorText ? 'output-error' : 'output-available'\n this.events.toolResultAdded(\n input.toolCallId,\n input.fixture.toolName,\n input.output,\n state,\n {\n threadId: input.threadId,\n ...(input.fixture.runId ? { runId: input.fixture.runId } : {}),\n toolCallId: input.toolCallId,\n },\n )\n this.chatOptions.addToolResult(\n input.toolCallId,\n input.output,\n input.errorText,\n )\n this.events.toolFixtureApplied({\n hookId: this.chatOptions.hookId,\n threadId: input.threadId,\n ...(input.fixture.runId ? { runId: input.fixture.runId } : {}),\n toolName: input.fixture.toolName,\n input: input.fixture.input,\n output: input.output,\n execute: true,\n messageId: input.messageId,\n toolCallId: input.toolCallId,\n ...(input.errorText ? { errorText: input.errorText } : {}),\n })\n this.emitSnapshot()\n }\n\n private createReplayMessageFromFixture(\n fixture: AIDevtoolsToolFixture,\n messages: Array<UIMessage>,\n ): { message: UIMessage; toolCallId: string } {\n const cloned = this.cloneFixtureSourceMessage(fixture, messages)\n if (cloned) return cloned\n\n const toolCallId = this.resolveFixtureToolCallId(\n fixture.toolCallId,\n messages,\n )\n const messageId = this.resolveFixtureMessageId(fixture.messageId, messages)\n const state = fixture.errorText ? 'error' : 'complete'\n\n return {\n toolCallId,\n message: {\n id: messageId,\n role: 'assistant',\n parts: [\n {\n type: 'tool-call',\n id: toolCallId,\n name: fixture.toolName,\n arguments: stringifyFixtureValue(fixture.input),\n input: fixture.input,\n state: 'input-complete',\n output: fixture.output,\n },\n {\n type: 'tool-result',\n toolCallId,\n content: stringifyFixtureValue(fixture.output),\n state,\n ...(fixture.errorText ? { error: fixture.errorText } : {}),\n },\n ],\n createdAt: new Date(),\n },\n }\n }\n\n private cloneFixtureSourceMessage(\n fixture: AIDevtoolsToolFixture,\n messages: Array<UIMessage>,\n ): { message: UIMessage; toolCallId: string } | undefined {\n const sourceMessage = fixture.message\n if (!sourceMessage || !Array.isArray(sourceMessage.parts)) {\n return undefined\n }\n\n const toolCallIds = this.createFixtureToolCallIdMap(\n sourceMessage.parts,\n messages,\n )\n const parts = sourceMessage.parts\n .map((part) => cloneFixtureMessagePart(part, toolCallIds))\n .filter((part): part is MessagePart => Boolean(part))\n const mappedFixtureToolCallId = fixture.toolCallId\n ? toolCallIds.get(fixture.toolCallId)\n : undefined\n hydrateToolCallOutputs(parts, {\n ...(mappedFixtureToolCallId\n ? { mappedToolCallId: mappedFixtureToolCallId }\n : {}),\n output: fixture.output,\n })\n\n if (parts.length === 0) return undefined\n\n const toolCallId =\n (fixture.toolCallId ? toolCallIds.get(fixture.toolCallId) : undefined) ??\n firstToolCallId(parts)\n if (!toolCallId) return undefined\n\n return {\n toolCallId,\n message: {\n id: this.resolveFixtureMessageId(sourceMessage.id, messages),\n role: sourceMessage.role,\n parts,\n createdAt: new Date(),\n },\n }\n }\n\n private createFixtureToolCallIdMap(\n parts: Array<unknown>,\n messages: Array<UIMessage>,\n ): Map<string, string> {\n const ids = new Map<string, string>()\n for (const part of parts) {\n if (!isRecord(part) || part.type !== 'tool-call') continue\n if (typeof part.id !== 'string') continue\n ids.set(part.id, this.resolveFixtureToolCallId(part.id, messages))\n }\n return ids\n }\n\n private resolveFixtureMessageId(\n messageId: string | undefined,\n messages: Array<UIMessage>,\n ): string {\n if (messageId && !messages.some((message) => message.id === messageId)) {\n return messageId\n }\n return this.chatOptions.generateId('fixture-msg')\n }\n\n private resolveFixtureToolCallId(\n toolCallId: string | undefined,\n messages: Array<UIMessage>,\n ): string {\n if (toolCallId && !hasToolCallId(messages, toolCallId)) {\n return toolCallId\n }\n return this.chatOptions.generateId('fixture-tool-call')\n }\n\n private findClientTool(name: string): AnyClientTool | undefined {\n const tools = this.chatOptions.getTools?.()\n if (!tools) return undefined\n for (const tool of tools) {\n if (tool.name === name) return tool\n }\n return undefined\n }\n}\n\n// ---- Module-level fixture helpers (pure; share no state) -------------------\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null\n}\n\nfunction stringifyFixtureValue(value: unknown): string {\n if (typeof value === 'string') return value\n if (\n value === undefined ||\n typeof value === 'function' ||\n typeof value === 'symbol'\n ) {\n return String(value)\n }\n try {\n return JSON.stringify(value)\n } catch (error) {\n console.error(\n '[ai-devtools] failed to JSON.stringify fixture value; falling back to String(). Tool call arguments may be malformed.',\n { error, value },\n )\n return String(value)\n }\n}\n\nfunction parseFixtureResultContent(content: string): unknown {\n try {\n return JSON.parse(content)\n } catch (error) {\n console.error(\n '[ai-devtools] failed to JSON.parse fixture result content; replaying as raw string. Fixture payload may be corrupted.',\n { error, content },\n )\n return content\n }\n}\n\nfunction cloneFixtureMessagePart(\n part: unknown,\n toolCallIds: Map<string, string>,\n): MessagePart | undefined {\n if (!isRecord(part) || typeof part.type !== 'string') return undefined\n const cloned: Record<string, unknown> = { ...part }\n\n if (part.type === 'tool-call' && typeof part.id === 'string') {\n cloned.id = toolCallIds.get(part.id) ?? part.id\n }\n if (part.type === 'tool-result' && typeof part.toolCallId === 'string') {\n cloned.toolCallId = toolCallIds.get(part.toolCallId) ?? part.toolCallId\n }\n return cloned as MessagePart\n}\n\nfunction firstToolCallId(parts: Array<MessagePart>): string | undefined {\n const toolCall = parts.find((part) => part.type === 'tool-call')\n return toolCall?.type === 'tool-call' ? toolCall.id : undefined\n}\n\nfunction hydrateToolCallOutputs(\n parts: Array<MessagePart>,\n fixtureOutput: { mappedToolCallId?: string; output: unknown },\n): void {\n for (const part of parts) {\n if (part.type !== 'tool-result') continue\n const toolCall = parts.find(\n (candidate): candidate is ToolCallPart =>\n candidate.type === 'tool-call' &&\n candidate.id === part.toolCallId &&\n candidate.output === undefined,\n )\n if (toolCall) {\n toolCall.output = Array.isArray(part.content)\n ? part.content\n : parseFixtureResultContent(part.content)\n }\n }\n\n if (fixtureOutput.mappedToolCallId && fixtureOutput.output !== undefined) {\n const toolCall = parts.find(\n (candidate): candidate is ToolCallPart =>\n candidate.type === 'tool-call' &&\n candidate.id === fixtureOutput.mappedToolCallId &&\n candidate.output === undefined,\n )\n if (toolCall) {\n toolCall.output = fixtureOutput.output\n }\n }\n}\n\nfunction hasToolCallId(\n messages: Array<UIMessage>,\n toolCallId: string,\n): boolean {\n return messages.some((message) =>\n message.parts.some((part) => {\n if (part.type === 'tool-call') return part.id === toolCallId\n if (part.type === 'tool-result') return part.toolCallId === toolCallId\n return false\n }),\n )\n}\n\n// Devtools surface for GenerationClient / VideoGenerationClient. Owns per-run\n// history, active-run lifecycle, and snapshot emission; the generation client\n// pushes its core state in via the record* methods.\n\nexport interface AIDevtoolsGenerationSnapshotBase<TOutput> {\n input: unknown\n result: TOutput | null\n preview: AIDevtoolsGenerationPreview\n progress: AIDevtoolsGenerationProgress | null\n status: AIDevtoolsGenerationRunStatus\n isLoading: boolean\n activeRunId: string | null\n runs: Array<AIDevtoolsGenerationRunSnapshot<TOutput>>\n error?: string\n}\n\nexport interface GenerationDevtoolsBridgeOptions<TOutput> extends Omit<\n AIDevtoolsBridgeOptions<AIDevtoolsGenerationSnapshotBase<TOutput>>,\n 'getSnapshot'\n> {\n getCoreState: () => GenerationDevtoolsCoreState<TOutput>\n maxRuns?: number\n}\n\nexport interface GenerationDevtoolsCoreState<TOutput> {\n input: unknown\n result: TOutput | null\n progress: AIDevtoolsGenerationProgress | null\n status: AIDevtoolsGenerationRunStatus\n isLoading: boolean\n error?: string\n}\n\nexport interface GenerationRunPatch<TOutput> {\n input?: unknown\n result?: TOutput | null\n preview?: AIDevtoolsGenerationPreview\n progress?: AIDevtoolsGenerationProgress | null\n status?: AIDevtoolsGenerationRunStatus\n isLoading?: boolean\n completedAt?: number\n error?: string\n clearError?: boolean\n}\n\nexport class GenerationDevtoolsBridge<TOutput> extends ClientDevtoolsBridge<\n AIDevtoolsGenerationSnapshotBase<TOutput>\n> {\n protected activeRunId: string | null = null\n protected activeRunStarted = false\n protected devtoolsRuns: Array<AIDevtoolsGenerationRunSnapshot<TOutput>> = []\n protected readonly maxRuns: number\n protected readonly getCoreState: () => GenerationDevtoolsCoreState<TOutput>\n\n constructor(options: GenerationDevtoolsBridgeOptions<TOutput>) {\n super({\n ...options,\n getSnapshot: () => this.buildSnapshot(),\n })\n this.maxRuns = options.maxRuns ?? 20\n this.getCoreState = options.getCoreState\n }\n\n // --- Run lifecycle (called by GenerationClient) -----------------------\n\n beginRun(input: unknown): string {\n const runId = this.generateRunId()\n this.activeRunId = runId\n this.activeRunStarted = false\n this.upsertRun(runId, {\n input,\n result: null,\n preview: this.createPreview(null),\n progress: null,\n status: 'generating',\n isLoading: true,\n clearError: true,\n })\n return runId\n }\n\n ensureRunStarted(runId: string): void {\n if (this.activeRunStarted && this.activeRunId === runId) return\n\n if (\n !this.activeRunStarted &&\n this.activeRunId &&\n this.activeRunId !== runId\n ) {\n this.renameRun(this.activeRunId, runId)\n }\n\n this.activeRunId = runId\n this.activeRunStarted = true\n this.upsertRun(runId, {\n status: 'generating',\n isLoading: true,\n clearError: true,\n })\n this.emitRunLifecycle('run:started', runId, 'started')\n this.emitState()\n }\n\n finishRun(\n runId: string,\n eventType: 'run:completed' | 'run:errored' | 'run:cancelled',\n status: 'completed' | 'errored' | 'cancelled',\n error?: string,\n ): void {\n this.ensureRunStarted(runId)\n const completedAt = Date.now()\n const completedProgress =\n status === 'completed' ? this.completeProgress() : this.getProgress()\n const runStatus =\n status === 'completed'\n ? 'success'\n : status === 'errored'\n ? 'error'\n : 'cancelled'\n\n this.upsertRun(runId, {\n status: runStatus,\n isLoading: false,\n progress: completedProgress,\n completedAt,\n ...(error ? { error } : { clearError: true }),\n })\n\n if (this.activeRunId === runId) {\n this.activeRunId = null\n }\n this.activeRunStarted = false\n this.emitRunLifecycle(eventType, runId, status, {\n ...(error ? { error } : {}),\n })\n this.emitState()\n }\n\n getActiveRunId(): string | null {\n return this.activeRunId\n }\n\n /** Clear all per-run history. Called when the client `reset()`s. */\n resetRuns(): void {\n this.activeRunId = null\n this.activeRunStarted = false\n this.devtoolsRuns = []\n }\n\n /** Record state changes from the client and emit the matching snapshot. */\n recordResultChange(): void {\n this.updateActiveRun({\n result: this.getCoreState().result,\n preview: this.createPreview(this.getCoreState().result),\n clearError: true,\n })\n this.emitState()\n }\n\n recordLoadingChange(): void {\n this.updateActiveRun({ isLoading: this.getCoreState().isLoading })\n this.emitState()\n }\n\n recordErrorChange(error: Error | undefined): void {\n this.updateActiveRun(\n error ? { error: error.message } : { clearError: true },\n )\n this.emitState()\n }\n\n recordStatusChange(status: AIDevtoolsGenerationRunStatus): void {\n this.updateActiveRun({ status })\n this.emitState()\n }\n\n recordProgressChange(): void {\n this.updateActiveRun({ progress: this.getCoreState().progress })\n this.emitState()\n }\n\n /** Emit the latest snapshot without touching run state. */\n emitState(): void {\n this.emitUpdated()\n this.emitSnapshot()\n }\n\n // --- Internal ---------------------------------------------------------\n\n protected buildSnapshot(): AIDevtoolsGenerationSnapshotBase<TOutput> {\n const core = this.getCoreState()\n return {\n input: core.input,\n result: core.result,\n preview: this.createPreview(core.result),\n progress: core.progress,\n status: core.status,\n isLoading: core.isLoading,\n activeRunId: this.activeRunId,\n runs: this.devtoolsRuns,\n ...(core.error ? { error: core.error } : {}),\n }\n }\n\n protected updateActiveRun(patch: GenerationRunPatch<TOutput>): void {\n if (!this.activeRunId) return\n this.upsertRun(this.activeRunId, patch)\n }\n\n protected upsertRun(runId: string, patch: GenerationRunPatch<TOutput>): void {\n const now = Date.now()\n const index = this.devtoolsRuns.findIndex((run) => run.id === runId)\n const existing = index >= 0 ? this.devtoolsRuns[index] : undefined\n const next: AIDevtoolsGenerationRunSnapshot<TOutput> = existing\n ? { ...existing }\n : {\n id: runId,\n input: this.getCoreState().input,\n result: null,\n preview: this.createPreview(null),\n progress: null,\n status: 'idle',\n isLoading: false,\n startedAt: now,\n updatedAt: now,\n }\n\n if ('input' in patch) next.input = patch.input ?? null\n if ('result' in patch) next.result = patch.result ?? null\n if (patch.preview) next.preview = patch.preview\n if ('progress' in patch) next.progress = patch.progress ?? null\n if (patch.status) next.status = patch.status\n if ('isLoading' in patch) next.isLoading = patch.isLoading === true\n if (patch.completedAt !== undefined) next.completedAt = patch.completedAt\n if (patch.clearError) delete next.error\n if (patch.error !== undefined) next.error = patch.error\n next.updatedAt = now\n\n if (index >= 0) {\n this.devtoolsRuns = this.devtoolsRuns.map((run) =>\n run.id === runId ? next : run,\n )\n } else {\n this.devtoolsRuns = [...this.devtoolsRuns, next]\n }\n\n if (this.devtoolsRuns.length > this.maxRuns) {\n this.devtoolsRuns = this.devtoolsRuns.slice(-this.maxRuns)\n }\n }\n\n protected renameRun(previousRunId: string, nextRunId: string): void {\n if (previousRunId === nextRunId) return\n\n const existing = this.devtoolsRuns.find((run) => run.id === previousRunId)\n if (!existing) return\n\n const renamed = { ...existing, id: nextRunId, updatedAt: Date.now() }\n this.devtoolsRuns = this.devtoolsRuns\n .filter((run) => run.id !== nextRunId)\n .map((run) => (run.id === previousRunId ? renamed : run))\n }\n\n protected getProgress(): AIDevtoolsGenerationProgress | null {\n return this.getCoreState().progress\n }\n\n protected completeProgress(): AIDevtoolsGenerationProgress | null {\n const progress = this.getCoreState().progress\n if (!progress) return null\n return {\n value: 100,\n ...(progress.message ? { message: progress.message } : {}),\n }\n }\n\n protected createPreview(result: TOutput | null): AIDevtoolsGenerationPreview {\n return createAIDevtoolsGenerationPreview({\n outputKind: this.options.metadata.outputKind,\n result,\n })\n }\n\n protected generateRunId(): string {\n return `run-${Date.now()}-${Math.random().toString(36).substring(7)}`\n }\n}\n\n// Video-job specialization: snapshots also carry the job id and the latest\n// provider-reported video status so the panel can show streaming progress\n// before the final URL lands.\n\nexport interface AIDevtoolsVideoSnapshotBase<\n TOutput,\n> extends AIDevtoolsGenerationSnapshotBase<TOutput> {\n jobId: string | null\n videoStatus: unknown\n}\n\nexport interface VideoDevtoolsCoreState<\n TOutput,\n> extends GenerationDevtoolsCoreState<TOutput> {\n jobId: string | null\n videoStatus: unknown\n}\n\nexport interface VideoDevtoolsBridgeOptions<TOutput> extends Omit<\n GenerationDevtoolsBridgeOptions<TOutput>,\n 'getCoreState'\n> {\n getCoreState: () => VideoDevtoolsCoreState<TOutput>\n}\n\nexport interface VideoRunPatch<TOutput> extends GenerationRunPatch<TOutput> {\n jobId?: string | null\n videoStatus?: unknown\n}\n\nexport class VideoDevtoolsBridge<\n TOutput,\n> extends GenerationDevtoolsBridge<TOutput> {\n constructor(options: VideoDevtoolsBridgeOptions<TOutput>) {\n super(options)\n }\n\n recordJobIdChange(): void {\n this.updateActiveRun({\n jobId: (this.getCoreState() as VideoDevtoolsCoreState<TOutput>).jobId,\n } as VideoRunPatch<TOutput>)\n this.emitState()\n }\n\n recordVideoStatusChange(): void {\n const core = this.getCoreState() as VideoDevtoolsCoreState<TOutput>\n this.updateActiveRun({\n videoStatus: core.videoStatus,\n preview: this.createVideoPreview(core.result, core.videoStatus),\n } as VideoRunPatch<TOutput>)\n this.emitState()\n }\n\n protected override buildSnapshot(): AIDevtoolsVideoSnapshotBase<TOutput> {\n const core = this.getCoreState() as VideoDevtoolsCoreState<TOutput>\n return {\n input: core.input,\n result: core.result,\n preview: this.createVideoPreview(core.result, core.videoStatus),\n progress: core.progress,\n status: core.status,\n isLoading: core.isLoading,\n activeRunId: this.activeRunId,\n runs: this.devtoolsRuns,\n jobId: core.jobId,\n videoStatus: core.videoStatus,\n ...(core.error ? { error: core.error } : {}),\n }\n }\n\n protected override upsertRun(\n runId: string,\n patch: VideoRunPatch<TOutput>,\n ): void {\n super.upsertRun(runId, patch)\n if (!('jobId' in patch || 'videoStatus' in patch)) return\n\n const index = this.devtoolsRuns.findIndex((run) => run.id === runId)\n if (index < 0) return\n const target = this.devtoolsRuns[index]\n if (!target) return\n const merged: AIDevtoolsGenerationRunSnapshot<TOutput> = { ...target }\n if ('jobId' in patch) merged.jobId = patch.jobId ?? null\n if ('videoStatus' in patch) merged.videoStatus = patch.videoStatus ?? null\n this.devtoolsRuns = this.devtoolsRuns.map((run) =>\n run.id === runId ? merged : run,\n )\n }\n\n // Override so record* methods inherited from GenerationDevtoolsBridge\n // (e.g. recordResultChange) thread the latest videoStatus into the preview.\n protected override createPreview(\n result: TOutput | null,\n ): AIDevtoolsGenerationPreview {\n const core = this.getCoreState() as VideoDevtoolsCoreState<TOutput>\n return this.createVideoPreview(result, core.videoStatus)\n }\n\n private createVideoPreview(\n result: TOutput | null,\n videoStatus: unknown,\n ): AIDevtoolsGenerationPreview {\n return createAIDevtoolsGenerationPreview({\n outputKind: this.options.metadata.outputKind,\n result,\n videoStatus,\n })\n }\n}\n\n// Wraps the plain emitter so callers can do `this.events.X(...)` and get:\n// auto-attached run/thread context on every event that accepts one,\n// an auto-emitted snapshot after each event, and passive streamId tracking\n// so resolveStreamId() works without the chat client telling it.\nclass ChatDevtoolsAwareEventEmitter extends DefaultChatClientEventEmitter {\n constructor(\n clientId: string,\n private readonly helper: ChatDevtoolsBridge,\n ) {\n super(clientId)\n }\n\n private afterEmit(streamId?: string): void {\n if (streamId) this.helper.recordStreamId(streamId)\n this.helper.emitSnapshot()\n }\n\n // -- methods with run context --------------------------------------------\n\n override textUpdated(\n streamId: string,\n messageId: string,\n content: string,\n context?: ChatClientRunEventContext,\n ): void {\n super.textUpdated(\n streamId,\n messageId,\n content,\n context ?? this.helper.getCurrentRunEventContext(),\n )\n this.afterEmit(streamId)\n }\n\n override thinkingUpdated(\n streamId: string,\n messageId: string,\n content: string,\n delta?: string,\n context?: ChatClientRunEventContext,\n ): void {\n super.thinkingUpdated(\n streamId,\n messageId,\n content,\n delta,\n context ?? this.helper.getCurrentRunEventContext(),\n )\n this.afterEmit(streamId)\n }\n\n override messageAppended(\n uiMessage: Parameters<DefaultChatClientEventEmitter['messageAppended']>[0],\n streamId?: string,\n context?: ChatClientEventContext,\n ): void {\n super.messageAppended(\n uiMessage,\n streamId,\n context ?? this.helper.getCurrentRunEventContext(),\n )\n this.afterEmit(streamId)\n }\n\n override toolCallStateChanged(\n streamId: string,\n messageId: string,\n toolCallId: string,\n toolName: string,\n state: string,\n args: string,\n context?: ChatClientRunEventContext,\n ): void {\n super.toolCallStateChanged(\n streamId,\n messageId,\n toolCallId,\n toolName,\n state,\n args,\n context ?? this.helper.getCurrentRunEventContext(),\n )\n this.afterEmit(streamId)\n }\n\n override structuredOutputChanged(\n eventName: Parameters<\n DefaultChatClientEventEmitter['structuredOutputChanged']\n >[0],\n streamId: string,\n messageId: string,\n output: Parameters<\n DefaultChatClientEventEmitter['structuredOutputChanged']\n >[3],\n context?: ChatClientRunEventContext,\n ): void {\n super.structuredOutputChanged(\n eventName,\n streamId,\n messageId,\n output,\n context ?? this.helper.getCurrentOrLastRunEventContext(),\n )\n this.afterEmit(streamId)\n }\n\n override approvalRequested(\n streamId: string,\n messageId: string,\n toolCallId: string,\n toolName: string,\n input: unknown,\n approvalId: string,\n context?: ChatClientRunEventContext,\n ): void {\n super.approvalRequested(\n streamId,\n messageId,\n toolCallId,\n toolName,\n input,\n approvalId,\n context ?? this.helper.getCurrentOrLastRunEventContext(),\n )\n this.afterEmit(streamId)\n }\n\n override toolResultAdded(\n toolCallId: string,\n toolName: string,\n output: unknown,\n state: string,\n context?: ChatClientEventContext,\n ): void {\n super.toolResultAdded(\n toolCallId,\n toolName,\n output,\n state,\n context ?? this.helper.getCurrentRunEventContext(),\n )\n this.afterEmit()\n }\n\n override toolApprovalResponded(\n approvalId: string,\n toolCallId: string,\n approved: boolean,\n context?: ChatClientRunEventContext,\n ): void {\n super.toolApprovalResponded(\n approvalId,\n toolCallId,\n approved,\n context ?? this.helper.getCurrentRunEventContext(),\n )\n this.afterEmit()\n }\n\n // -- methods without context (just auto-emit snapshot) -------------------\n\n override clientCreated(initialMessageCount: number): void {\n super.clientCreated(initialMessageCount)\n this.afterEmit()\n }\n override loadingChanged(isLoading: boolean): void {\n super.loadingChanged(isLoading)\n this.afterEmit()\n }\n override errorChanged(error: string | null): void {\n super.errorChanged(error)\n this.afterEmit()\n }\n override reloaded(fromMessageIndex: number): void {\n super.reloaded(fromMessageIndex)\n this.afterEmit()\n }\n override stopped(): void {\n super.stopped()\n this.afterEmit()\n }\n override messagesCleared(): void {\n super.messagesCleared()\n this.afterEmit()\n }\n override messageSent(\n messageId: string,\n content: Parameters<DefaultChatClientEventEmitter['messageSent']>[1],\n ): void {\n super.messageSent(messageId, content)\n this.afterEmit()\n }\n override toolFixtureApplied(\n fixture: Parameters<DefaultChatClientEventEmitter['toolFixtureApplied']>[0],\n ): void {\n super.toolFixtureApplied(fixture)\n this.afterEmit()\n }\n}\n\nexport function createChatDevtoolsBridge(\n options: ChatDevtoolsBridgeOptions,\n): ChatDevtoolsBridge {\n return new ChatDevtoolsBridge(options)\n}\n\nexport function createGenerationDevtoolsBridge<TOutput>(\n options: GenerationDevtoolsBridgeOptions<TOutput>,\n): GenerationDevtoolsBridge<TOutput> {\n return new GenerationDevtoolsBridge<TOutput>(options)\n}\n\nexport function createVideoDevtoolsBridge<TOutput>(\n options: VideoDevtoolsBridgeOptions<TOutput>,\n): VideoDevtoolsBridge<TOutput> {\n return new VideoDevtoolsBridge<TOutput>(options)\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"devtools.js","sources":["../../src/devtools.ts"],"sourcesContent":["import {\n aiEventClient,\n createAIDevtoolsEventEnvelope,\n emitAIDevtoolsEvent,\n} from '@tanstack/ai-event-client'\nimport { convertSchemaToJsonSchema } from '@tanstack/ai/client'\nimport { DefaultChatClientEventEmitter } from './events'\nimport type { AnyClientTool, StreamChunk } from '@tanstack/ai/client'\nimport type { AIDevtoolsEventVisibility } from '@tanstack/ai-event-client'\nimport type {\n ChatClientEventContext,\n ChatClientEventEmitter,\n ChatClientRunEventContext,\n} from './events'\nimport type {\n ChatClientState,\n ConnectionStatus,\n MessagePart,\n QueuedMessage,\n ToolCallPart,\n UIMessage,\n} from './types'\n\nexport interface AIDevtoolsDisplayOptions {\n name?: string\n}\n\nexport interface AIDevtoolsClientMetadata extends AIDevtoolsDisplayOptions {\n framework?: string\n hookName: string\n outputKind?: 'chat' | 'text' | 'structured' | 'image' | 'video' | 'audio'\n}\n\nexport interface AIDevtoolsGenerationProgress {\n value: number\n message?: string\n}\n\nexport interface AIDevtoolsGenerationMediaItem {\n src: string\n sourceType: 'url' | 'base64'\n mimeType?: string\n format?: string\n duration?: number\n}\n\nexport interface AIDevtoolsGenerationVideoJob {\n jobId: string\n status?: string\n progress?: number\n error?: string\n}\n\nexport type AIDevtoolsGenerationPreview =\n | {\n kind: 'image'\n items: Array<AIDevtoolsGenerationMediaItem>\n }\n | {\n kind: 'audio'\n items: Array<AIDevtoolsGenerationMediaItem>\n }\n | {\n kind: 'video'\n items: Array<AIDevtoolsGenerationMediaItem>\n job?: AIDevtoolsGenerationVideoJob\n }\n | {\n kind: 'text'\n text: string\n }\n | {\n kind: 'structured'\n value: unknown\n }\n | {\n kind: 'empty'\n }\n\nexport type AIDevtoolsGenerationRunStatus =\n | 'idle'\n | 'generating'\n | 'success'\n | 'error'\n | 'cancelled'\n\nexport interface AIDevtoolsGenerationRunSnapshot<TOutput = unknown> {\n id: string\n input: unknown\n result: TOutput | null\n preview: AIDevtoolsGenerationPreview\n progress: AIDevtoolsGenerationProgress | null\n status: AIDevtoolsGenerationRunStatus\n isLoading: boolean\n startedAt: number\n updatedAt: number\n completedAt?: number\n error?: string\n jobId?: string | null\n videoStatus?: unknown\n}\n\nexport interface AIDevtoolsGenerationPreviewInput {\n outputKind?: AIDevtoolsClientMetadata['outputKind']\n result: unknown\n videoStatus?: unknown\n}\n\nexport interface AIDevtoolsChatSnapshot {\n [key: string]: unknown\n messages: Array<UIMessage>\n status: ChatClientState\n isLoading: boolean\n isSubscribed: boolean\n connectionStatus: ConnectionStatus\n sessionGenerating: boolean\n activeRunIds: Array<string>\n queue?: Array<QueuedMessage>\n error?: string\n}\n\nexport function createAIDevtoolsGenerationPreview(\n input: AIDevtoolsGenerationPreviewInput,\n): AIDevtoolsGenerationPreview {\n if (input.outputKind === 'image') {\n return imagePreviewFromResult(input.result)\n }\n\n if (input.outputKind === 'audio') {\n return audioPreviewFromResult(input.result)\n }\n\n if (input.outputKind === 'video') {\n return videoPreviewFromResult(input.result, input.videoStatus)\n }\n\n if (input.outputKind === 'text') {\n return textPreviewFromResult(input.result)\n }\n\n if (input.result === null || input.result === undefined) {\n return { kind: 'empty' }\n }\n\n return {\n kind: 'structured',\n value: input.result,\n }\n}\n\ntype UnknownRecord = { [key: string]: unknown }\n\nfunction imagePreviewFromResult(result: unknown): AIDevtoolsGenerationPreview {\n const record = asRecord(result)\n const images = Array.isArray(record?.images) ? record.images : []\n const items = images\n .map((image) => mediaItemFromSource(image, 'image/png'))\n .filter(isGenerationMediaItem)\n\n if (items.length === 0 && result !== null && result !== undefined) {\n const directItem = mediaItemFromSource(result, 'image/png')\n if (directItem) {\n items.push(directItem)\n }\n }\n\n return { kind: 'image', items }\n}\n\nfunction audioPreviewFromResult(result: unknown): AIDevtoolsGenerationPreview {\n const record = asRecord(result)\n const audio = record?.audio\n const resultContentType = stringField(record, 'contentType')\n const format = stringField(record, 'format')\n const mimeType = resultContentType ?? mimeTypeFromAudioFormat(format)\n\n const items: Array<AIDevtoolsGenerationMediaItem> = []\n const directItem =\n typeof audio === 'string'\n ? base64MediaItem(audio, mimeType, {\n format,\n duration: numberField(record, 'duration'),\n })\n : mediaItemFromSource(audio, mimeType, {\n format,\n })\n\n if (directItem) {\n items.push(directItem)\n }\n\n return { kind: 'audio', items }\n}\n\nfunction videoPreviewFromResult(\n result: unknown,\n videoStatus: unknown,\n): AIDevtoolsGenerationPreview {\n const resultRecord = asRecord(result)\n const statusRecord = asRecord(videoStatus)\n const item =\n mediaItemFromSource(result, 'video/mp4') ??\n mediaItemFromSource(videoStatus, 'video/mp4')\n const items = item ? [item] : []\n const job = videoJobFromStatus(statusRecord ?? resultRecord)\n\n return {\n kind: 'video',\n items,\n ...(job ? { job } : {}),\n }\n}\n\nfunction textPreviewFromResult(result: unknown): AIDevtoolsGenerationPreview {\n const record = asRecord(result)\n const text =\n stringField(record, 'text') ??\n stringField(record, 'summary') ??\n stringField(record, 'content') ??\n (typeof result === 'string' ? result : undefined)\n\n if (text !== undefined) {\n return { kind: 'text', text }\n }\n\n if (result === null || result === undefined) {\n return { kind: 'empty' }\n }\n\n return {\n kind: 'structured',\n value: result,\n }\n}\n\nfunction videoJobFromStatus(\n record: UnknownRecord | undefined,\n): AIDevtoolsGenerationVideoJob | undefined {\n const jobId = stringField(record, 'jobId')\n if (!jobId) return undefined\n\n return {\n jobId,\n ...(stringField(record, 'status')\n ? { status: stringField(record, 'status') }\n : {}),\n ...(numberField(record, 'progress') !== undefined\n ? { progress: numberField(record, 'progress') }\n : {}),\n ...(stringField(record, 'error')\n ? { error: stringField(record, 'error') }\n : {}),\n }\n}\n\nfunction mediaItemFromSource(\n value: unknown,\n defaultMimeType: string,\n extras: {\n format?: string\n duration?: number\n } = {},\n): AIDevtoolsGenerationMediaItem | undefined {\n const record = asRecord(value)\n if (!record) return undefined\n\n const explicitContentType =\n stringField(record, 'contentType') ?? stringField(record, 'mimeType')\n const duration = numberField(record, 'duration') ?? extras.duration\n const format = stringField(record, 'format') ?? extras.format\n const url = stringField(record, 'url')\n if (url) {\n return {\n src: url,\n sourceType: 'url',\n ...(explicitContentType ? { mimeType: explicitContentType } : {}),\n ...(format ? { format } : {}),\n ...(duration !== undefined ? { duration } : {}),\n }\n }\n\n const b64Json = stringField(record, 'b64Json')\n if (!b64Json) return undefined\n\n return base64MediaItem(b64Json, explicitContentType ?? defaultMimeType, {\n format,\n duration,\n })\n}\n\nfunction base64MediaItem(\n value: string,\n mimeType: string | undefined,\n extras: {\n format?: string\n duration?: number\n } = {},\n): AIDevtoolsGenerationMediaItem {\n const src = value.startsWith('data:')\n ? value\n : `data:${mimeType ?? 'application/octet-stream'};base64,${value}`\n\n return {\n src,\n sourceType: 'base64',\n ...(mimeType ? { mimeType } : {}),\n ...(extras.format ? { format: extras.format } : {}),\n ...(extras.duration !== undefined ? { duration: extras.duration } : {}),\n }\n}\n\nfunction mimeTypeFromAudioFormat(format: string | undefined): string {\n if (!format) return 'audio/mpeg'\n if (format === 'mp3') return 'audio/mpeg'\n return `audio/${format}`\n}\n\nfunction asRecord(value: unknown): UnknownRecord | undefined {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n return undefined\n }\n return value as UnknownRecord\n}\n\nfunction stringField(\n record: UnknownRecord | undefined,\n field: string,\n): string | undefined {\n const value = record?.[field]\n return typeof value === 'string' && value.length > 0 ? value : undefined\n}\n\nfunction numberField(\n record: UnknownRecord | undefined,\n field: string,\n): number | undefined {\n const value = record?.[field]\n return typeof value === 'number' ? value : undefined\n}\n\nfunction isGenerationMediaItem(\n value: AIDevtoolsGenerationMediaItem | undefined,\n): value is AIDevtoolsGenerationMediaItem {\n return Boolean(value)\n}\n\nexport interface AIDevtoolsToolFixture {\n fixtureId?: string\n hookId?: string\n threadId?: string\n runId?: string\n toolName: string\n input: unknown\n output: unknown\n execute?: boolean\n message?: {\n id: string\n role: UIMessage['role']\n parts: Array<unknown>\n createdAt?: number | string\n }\n toolCallId?: string\n messageId?: string\n errorText?: string\n}\n\ntype AIDevtoolsRunEventType =\n | 'run:created'\n | 'run:started'\n | 'run:updated'\n | 'run:completed'\n | 'run:errored'\n | 'run:cancelled'\n\ntype AIDevtoolsRunStatus =\n | 'created'\n | 'started'\n | 'updated'\n | 'completed'\n | 'errored'\n | 'cancelled'\n\nexport interface AIDevtoolsBridgeOptions<TSnapshot extends object> {\n hookId: string\n threadId?: string\n clientId: string\n metadata: AIDevtoolsClientMetadata\n getSnapshot: () => TSnapshot\n getTools?: () => Iterable<AnyClientTool>\n applyToolFixture?: (fixture: AIDevtoolsToolFixture) => void | Promise<void>\n}\n\ntype Unsubscribe = () => void\n\ninterface AIDevtoolsEvent<TPayload> {\n payload: TPayload\n}\n\ninterface ActiveDevtoolsBridge {\n deactivate: () => void\n dispose: () => void\n supersede?: () => void\n}\n\nconst activeBridgeRegistryKey = Symbol.for(\n 'tanstack.ai.devtools.activeBridgeByHookId',\n)\n\nfunction getActiveBridgeRegistry(): Map<string, ActiveDevtoolsBridge> {\n const global = globalThis as typeof globalThis & {\n [activeBridgeRegistryKey]?: Map<string, ActiveDevtoolsBridge>\n }\n const existing = global[activeBridgeRegistryKey]\n if (existing) return existing\n\n const registry = new Map<string, ActiveDevtoolsBridge>()\n global[activeBridgeRegistryKey] = registry\n return registry\n}\n\nexport class ClientDevtoolsBridge<TSnapshot extends object> {\n protected readonly options: AIDevtoolsBridgeOptions<TSnapshot>\n private readonly bridgeId: string\n private readonly unsubscribers: Array<Unsubscribe> = []\n private disposed = false\n private superseded = false\n private registered = false\n\n constructor(options: AIDevtoolsBridgeOptions<TSnapshot>) {\n this.options = options\n this.bridgeId = createBridgeId(options.hookId)\n }\n\n emitRegistered(): void {\n if (!this.prepareForMountEmit()) {\n return\n }\n this.registered = true\n emitAIDevtoolsEvent('hook:registered', {\n ...this.createEnvelope('hook:registered'),\n ...this.createMetadataPayload(),\n lifecycle: 'mounted',\n })\n }\n\n emitUpdated(): void {\n if (!this.prepareForEmit()) {\n return\n }\n emitAIDevtoolsEvent('hook:updated', {\n ...this.createEnvelope('hook:updated'),\n ...this.createMetadataPayload(),\n lifecycle: 'active',\n })\n }\n\n emitSnapshot(): void {\n if (!this.prepareForEmit()) {\n return\n }\n emitAIDevtoolsEvent('hook:state-snapshot', {\n ...this.createEnvelope('hook:state-snapshot'),\n ...this.createMetadataPayload(),\n // Wire envelope uses Record<string, unknown>; widen the typed snapshot\n // here so the typed-snapshot constraint above can stay narrow.\n // eslint-disable-next-line no-restricted-syntax -- TSnapshot extends object is structurally compatible but TS can't see the missing index signature\n state: this.options.getSnapshot() as unknown as Record<string, unknown>,\n })\n }\n\n emitToolsRegistered(): void {\n if (!this.prepareForEmit()) {\n return\n }\n const tools = this.options.getTools\n ? Array.from(this.options.getTools()).map((tool) => ({\n name: tool.name,\n description: tool.description,\n inputSchema: tool.inputSchema\n ? convertSchemaToJsonSchema(tool.inputSchema)\n : { type: 'object' },\n outputSchema: tool.outputSchema\n ? convertSchemaToJsonSchema(tool.outputSchema)\n : undefined,\n needsApproval: tool.needsApproval,\n metadata: tool.metadata,\n }))\n : []\n\n emitAIDevtoolsEvent('tools:registered', {\n ...this.createEnvelope('tools:registered'),\n ...this.createMetadataPayload(),\n tools,\n })\n }\n\n emitRunLifecycle(\n eventType: AIDevtoolsRunEventType,\n runId: string,\n status: AIDevtoolsRunStatus,\n options: { error?: string } = {},\n ): void {\n if (!this.prepareForEmit()) {\n return\n }\n emitAIDevtoolsEvent(eventType, {\n ...this.createEnvelope(eventType, 'client-state', { runId }),\n runId,\n status,\n ...(options.error ? { error: options.error } : {}),\n })\n }\n\n deactivate(): void {\n const activeBridgeByHookId = getActiveBridgeRegistry()\n if (activeBridgeByHookId.get(this.options.hookId) === this) {\n activeBridgeByHookId.delete(this.options.hookId)\n }\n\n for (const unsubscribe of this.unsubscribers.splice(0)) {\n unsubscribe()\n }\n }\n\n supersede(): void {\n if (this.disposed) {\n return\n }\n\n this.superseded = true\n this.disposed = true\n this.deactivate()\n }\n\n dispose(): void {\n if (this.disposed) {\n return\n }\n\n this.disposed = true\n if (!this.registered) {\n this.deactivate()\n return\n }\n\n const payload = {\n ...this.createEnvelope('hook:unregistered'),\n ...this.createMetadataPayload(),\n reason: 'disposed',\n } as const\n\n emitAIDevtoolsEvent('hook:unregistered', payload)\n\n this.deactivate()\n }\n\n private prepareForEmit(): boolean {\n if (this.disposed || this.superseded) {\n return false\n }\n this.activate()\n return true\n }\n\n private prepareForMountEmit(): boolean {\n if (this.superseded) {\n return false\n }\n\n if (this.disposed) {\n this.disposed = false\n this.registered = false\n }\n\n this.activate()\n return true\n }\n\n private activate(): void {\n if (this.disposed) {\n return\n }\n\n const activeBridgeByHookId = getActiveBridgeRegistry()\n const activeBridge = activeBridgeByHookId.get(this.options.hookId)\n if (activeBridge && activeBridge !== this) {\n if (typeof activeBridge.supersede === 'function') {\n activeBridge.supersede()\n } else {\n activeBridge.deactivate()\n }\n }\n activeBridgeByHookId.set(this.options.hookId, this)\n\n if (this.unsubscribers.length > 0) {\n return\n }\n\n this.unsubscribers.push(\n aiEventClient.on('devtools:request-state', (event) => {\n this.handleRequestState(event)\n }),\n )\n\n if (this.options.applyToolFixture) {\n this.unsubscribers.push(\n aiEventClient.on('devtools:tool-fixture:apply', (event) => {\n void this.handleToolFixtureApply(event)\n }),\n )\n }\n }\n\n private handleRequestState(\n event: AIDevtoolsEvent<{ targetHookId?: string }>,\n ): void {\n if (this.disposed || this.superseded) {\n return\n }\n\n const targetHookId = event.payload.targetHookId\n if (targetHookId && targetHookId !== this.options.hookId) {\n return\n }\n\n this.emitRegistered()\n this.emitToolsRegistered()\n this.emitSnapshot()\n }\n\n private async handleToolFixtureApply(\n event: AIDevtoolsEvent<AIDevtoolsToolFixture>,\n ): Promise<void> {\n const fixture = event.payload\n if (!this.matchesFixtureTarget(fixture)) {\n return\n }\n\n await this.options.applyToolFixture?.(fixture)\n }\n\n private matchesFixtureTarget(fixture: AIDevtoolsToolFixture): boolean {\n if (!fixture.hookId && !fixture.threadId) {\n return false\n }\n\n if (fixture.hookId) {\n return fixture.hookId === this.options.hookId\n }\n\n if (\n fixture.threadId &&\n (!this.options.threadId || fixture.threadId !== this.options.threadId)\n ) {\n return false\n }\n return true\n }\n\n private createEnvelope(\n eventType:\n | 'hook:registered'\n | 'hook:updated'\n | 'hook:unregistered'\n | 'hook:state-snapshot'\n | 'tools:registered'\n | AIDevtoolsRunEventType,\n visibility: AIDevtoolsEventVisibility = 'client-state',\n context: { runId?: string } = {},\n ) {\n return createAIDevtoolsEventEnvelope({\n eventType,\n source: 'client',\n visibility,\n clientId: this.options.clientId,\n hookId: this.options.hookId,\n correlationId: this.bridgeId,\n ...(this.options.threadId ? { threadId: this.options.threadId } : {}),\n ...(context.runId ? { runId: context.runId } : {}),\n timestamp: Date.now(),\n })\n }\n\n private createMetadataPayload() {\n return {\n hookId: this.options.hookId,\n hookName: this.options.metadata.hookName,\n ...(this.options.metadata.name\n ? { displayName: this.options.metadata.name }\n : {}),\n ...(this.options.metadata.outputKind\n ? { outputKind: this.options.metadata.outputKind }\n : {}),\n ...(this.options.metadata.framework\n ? { framework: this.options.metadata.framework }\n : {}),\n }\n }\n}\n\nlet bridgeIdSequence = 0\n\nfunction createBridgeId(hookId: string): string {\n const cryptoLike = (\n globalThis as {\n crypto?: {\n randomUUID?: () => string\n }\n }\n ).crypto\n\n if (cryptoLike?.randomUUID) {\n return `bridge:${hookId}:${cryptoLike.randomUUID()}`\n }\n\n bridgeIdSequence += 1\n return `bridge:${hookId}:${bridgeIdSequence}`\n}\n\n// Owns the chat-client devtools surface so the chat client itself stays a\n// pure transport. Fixture replay, per-run / per-stream event context, and\n// snapshot emission all live here; a no-op bridge can drop in for prod.\n\nexport interface ChatDevtoolsBridgeOptions extends AIDevtoolsBridgeOptions<AIDevtoolsChatSnapshot> {\n getMessages: () => Array<UIMessage>\n setMessages: (messages: Array<UIMessage>) => void\n addToolResult: (\n toolCallId: string,\n output: unknown,\n errorText?: string,\n ) => void\n generateId: (prefix: string) => string\n}\n\nexport class ChatDevtoolsBridge extends ClientDevtoolsBridge<AIDevtoolsChatSnapshot> {\n readonly events: ChatClientEventEmitter\n private readonly chatOptions: ChatDevtoolsBridgeOptions\n private currentRunId: string | null = null\n private currentRunThreadId: string | null = null\n private currentStreamId: string | null = null\n private lastStreamId: string | null = null\n private lastRunEventContext: ChatClientRunEventContext | undefined\n\n constructor(options: ChatDevtoolsBridgeOptions) {\n super({\n ...options,\n // Thunk defers `this.applyFixture` lookup until after `super` returns.\n applyToolFixture: (fixture) => this.applyFixture(fixture),\n })\n this.chatOptions = options\n // Auto-attaches run/thread context and auto-emits a snapshot after each\n // event so callers can keep using `this.events.X(...)` with no context arg.\n this.events = new ChatDevtoolsAwareEventEmitter(options.clientId, this)\n }\n\n // --- Stream / run context API -------------------------------------------\n\n setCurrentStreamId(streamId: string | null): void {\n this.currentStreamId = streamId\n if (streamId) {\n this.lastStreamId = streamId\n }\n }\n\n /**\n * Called by the auto-attaching emitter every time it sees a non-empty\n * streamId pass through. Lets devtools track the latest stream id\n * without the chat client wiring it up explicitly.\n */\n recordStreamId(streamId: string): void {\n if (streamId) this.lastStreamId = streamId\n }\n\n mountWithTools(initialMessageCount: number): void {\n this.events.clientCreated(initialMessageCount)\n this.emitRegistered()\n this.emitToolsRegistered()\n this.emitSnapshot()\n }\n\n notifyToolsChanged(): void {\n this.emitToolsRegistered()\n this.emitSnapshot()\n }\n\n getCurrentStreamId(): string | null {\n return this.currentStreamId\n }\n\n getLastStreamId(): string | null {\n return this.lastStreamId\n }\n\n resolveStreamId(): string {\n return (\n this.currentStreamId ??\n this.lastStreamId ??\n this.chatOptions.generateId('stream')\n )\n }\n\n // Called when the chat client has just generated a runId for outbound emits;\n // the matching RUN_STARTED chunk from the adapter lands later and\n // observeChunk keeps the same context.\n beginRun(runId: string, threadId: string): void {\n this.currentRunId = runId\n this.currentRunThreadId = threadId\n this.lastRunEventContext = { runId, threadId }\n }\n\n observeChunk(chunk: StreamChunk): void {\n if (chunk.type === 'RUN_STARTED') {\n this.beginRun(chunk.runId, chunk.threadId)\n return\n }\n\n if (chunk.type === 'RUN_FINISHED' || chunk.type === 'RUN_ERROR') {\n const runId =\n chunk.type === 'RUN_FINISHED'\n ? chunk.runId\n : (chunk as { runId?: string }).runId\n if (!runId || runId === this.currentRunId) {\n const context = this.getCurrentRunEventContext()\n if (context) {\n this.lastRunEventContext = context\n }\n this.currentRunId = null\n this.currentRunThreadId = null\n }\n }\n }\n\n getCurrentRunEventContext(): ChatClientRunEventContext | undefined {\n if (!this.currentRunId) return undefined\n return {\n threadId: this.currentRunThreadId ?? this.chatOptions.threadId ?? '',\n runId: this.currentRunId,\n }\n }\n\n getCurrentOrLastRunEventContext(): ChatClientRunEventContext | undefined {\n return this.getCurrentRunEventContext() ?? this.lastRunEventContext\n }\n\n findToolCallContext(toolCallId: string): ChatClientEventContext {\n const base: ChatClientEventContext = { toolCallId }\n const runContext = this.getCurrentRunEventContext()\n if (runContext) {\n return {\n threadId: runContext.threadId,\n runId: runContext.runId,\n toolCallId,\n }\n }\n if (this.chatOptions.threadId) {\n return { threadId: this.chatOptions.threadId, toolCallId }\n }\n return base\n }\n\n // --- Fixture replay ------------------------------------------------------\n\n /**\n * Entry point invoked when the devtools panel emits\n * `devtools:tool-fixture:apply`. The chat client never calls this\n * directly; it is wired through the base bridge's fixture subscription.\n */\n async applyFixture(fixture: AIDevtoolsToolFixture): Promise<void> {\n const messages = this.chatOptions.getMessages()\n const threadId = fixture.threadId ?? this.chatOptions.threadId ?? ''\n if (fixture.execute) {\n await this.executeFixture(fixture, messages, threadId)\n return\n }\n\n const replay = this.createReplayMessageFromFixture(fixture, messages)\n const { message, toolCallId } = replay\n const messageId = message.id\n\n this.events.messageAppended(message, undefined, {\n threadId,\n toolCallId,\n ...(fixture.runId ? { runId: fixture.runId } : {}),\n })\n this.chatOptions.setMessages([...messages, message])\n this.events.toolFixtureApplied({\n hookId: this.chatOptions.hookId,\n threadId,\n ...(fixture.runId ? { runId: fixture.runId } : {}),\n toolName: fixture.toolName,\n input: fixture.input,\n output: fixture.output,\n messageId,\n toolCallId,\n ...(fixture.execute !== undefined ? { execute: fixture.execute } : {}),\n ...(fixture.message ? { message: fixture.message } : {}),\n ...(fixture.errorText ? { errorText: fixture.errorText } : {}),\n })\n this.emitSnapshot()\n }\n\n private async executeFixture(\n fixture: AIDevtoolsToolFixture,\n messages: Array<UIMessage>,\n threadId: string,\n ): Promise<void> {\n const toolCallId = this.resolveFixtureToolCallId(\n fixture.toolCallId,\n messages,\n )\n const messageId = this.resolveFixtureMessageId(fixture.messageId, messages)\n const message: UIMessage = {\n id: messageId,\n role: 'assistant',\n parts: [\n {\n type: 'tool-call',\n id: toolCallId,\n name: fixture.toolName,\n arguments: stringifyFixtureValue(fixture.input),\n input: fixture.input,\n state: 'input-complete',\n },\n ],\n createdAt: new Date(),\n }\n\n this.events.messageAppended(message, undefined, {\n threadId,\n toolCallId,\n ...(fixture.runId ? { runId: fixture.runId } : {}),\n })\n this.chatOptions.setMessages([...messages, message])\n this.emitSnapshot()\n\n const clientTool = this.findClientTool(fixture.toolName)\n const executeFunc = clientTool?.execute\n if (!executeFunc) {\n console.warn(\n `[ai-devtools] tool fixture \"${fixture.toolName}\" requested execute=true but no client tool implementation is registered; replaying saved output instead.`,\n )\n this.addToolResultForFixture({\n fixture,\n messageId,\n toolCallId,\n threadId,\n output: fixture.output,\n errorText: fixture.errorText,\n })\n return\n }\n\n let output: unknown\n try {\n output = await executeFunc(fixture.input)\n } catch (error) {\n console.error(\n `[ai-devtools] tool fixture \"${fixture.toolName}\" execute threw`,\n error,\n )\n this.addToolResultForFixture({\n fixture,\n messageId,\n toolCallId,\n threadId,\n output: null,\n errorText:\n error instanceof Error\n ? `${error.name}: ${error.message}`\n : `Tool execution failed: ${String(error)}`,\n })\n return\n }\n this.addToolResultForFixture({\n fixture,\n messageId,\n toolCallId,\n threadId,\n output,\n })\n }\n\n private addToolResultForFixture(input: {\n fixture: AIDevtoolsToolFixture\n messageId: string\n toolCallId: string\n threadId: string\n output: unknown\n errorText?: string\n }): void {\n const state = input.errorText ? 'output-error' : 'output-available'\n this.events.toolResultAdded(\n input.toolCallId,\n input.fixture.toolName,\n input.output,\n state,\n {\n threadId: input.threadId,\n ...(input.fixture.runId ? { runId: input.fixture.runId } : {}),\n toolCallId: input.toolCallId,\n },\n )\n this.chatOptions.addToolResult(\n input.toolCallId,\n input.output,\n input.errorText,\n )\n this.events.toolFixtureApplied({\n hookId: this.chatOptions.hookId,\n threadId: input.threadId,\n ...(input.fixture.runId ? { runId: input.fixture.runId } : {}),\n toolName: input.fixture.toolName,\n input: input.fixture.input,\n output: input.output,\n execute: true,\n messageId: input.messageId,\n toolCallId: input.toolCallId,\n ...(input.errorText ? { errorText: input.errorText } : {}),\n })\n this.emitSnapshot()\n }\n\n private createReplayMessageFromFixture(\n fixture: AIDevtoolsToolFixture,\n messages: Array<UIMessage>,\n ): { message: UIMessage; toolCallId: string } {\n const cloned = this.cloneFixtureSourceMessage(fixture, messages)\n if (cloned) return cloned\n\n const toolCallId = this.resolveFixtureToolCallId(\n fixture.toolCallId,\n messages,\n )\n const messageId = this.resolveFixtureMessageId(fixture.messageId, messages)\n const state = fixture.errorText ? 'error' : 'complete'\n\n return {\n toolCallId,\n message: {\n id: messageId,\n role: 'assistant',\n parts: [\n {\n type: 'tool-call',\n id: toolCallId,\n name: fixture.toolName,\n arguments: stringifyFixtureValue(fixture.input),\n input: fixture.input,\n state: 'input-complete',\n output: fixture.output,\n },\n {\n type: 'tool-result',\n toolCallId,\n content: stringifyFixtureValue(fixture.output),\n state,\n ...(fixture.errorText ? { error: fixture.errorText } : {}),\n },\n ],\n createdAt: new Date(),\n },\n }\n }\n\n private cloneFixtureSourceMessage(\n fixture: AIDevtoolsToolFixture,\n messages: Array<UIMessage>,\n ): { message: UIMessage; toolCallId: string } | undefined {\n const sourceMessage = fixture.message\n if (!sourceMessage || !Array.isArray(sourceMessage.parts)) {\n return undefined\n }\n\n const toolCallIds = this.createFixtureToolCallIdMap(\n sourceMessage.parts,\n messages,\n )\n const parts = sourceMessage.parts\n .map((part) => cloneFixtureMessagePart(part, toolCallIds))\n .filter((part): part is MessagePart => Boolean(part))\n const mappedFixtureToolCallId = fixture.toolCallId\n ? toolCallIds.get(fixture.toolCallId)\n : undefined\n hydrateToolCallOutputs(parts, {\n ...(mappedFixtureToolCallId\n ? { mappedToolCallId: mappedFixtureToolCallId }\n : {}),\n output: fixture.output,\n })\n\n if (parts.length === 0) return undefined\n\n const toolCallId =\n (fixture.toolCallId ? toolCallIds.get(fixture.toolCallId) : undefined) ??\n firstToolCallId(parts)\n if (!toolCallId) return undefined\n\n return {\n toolCallId,\n message: {\n id: this.resolveFixtureMessageId(sourceMessage.id, messages),\n role: sourceMessage.role,\n parts,\n createdAt: new Date(),\n },\n }\n }\n\n private createFixtureToolCallIdMap(\n parts: Array<unknown>,\n messages: Array<UIMessage>,\n ): Map<string, string> {\n const ids = new Map<string, string>()\n for (const part of parts) {\n if (!isRecord(part) || part.type !== 'tool-call') continue\n if (typeof part.id !== 'string') continue\n ids.set(part.id, this.resolveFixtureToolCallId(part.id, messages))\n }\n return ids\n }\n\n private resolveFixtureMessageId(\n messageId: string | undefined,\n messages: Array<UIMessage>,\n ): string {\n if (messageId && !messages.some((message) => message.id === messageId)) {\n return messageId\n }\n return this.chatOptions.generateId('fixture-msg')\n }\n\n private resolveFixtureToolCallId(\n toolCallId: string | undefined,\n messages: Array<UIMessage>,\n ): string {\n if (toolCallId && !hasToolCallId(messages, toolCallId)) {\n return toolCallId\n }\n return this.chatOptions.generateId('fixture-tool-call')\n }\n\n private findClientTool(name: string): AnyClientTool | undefined {\n const tools = this.chatOptions.getTools?.()\n if (!tools) return undefined\n for (const tool of tools) {\n if (tool.name === name) return tool\n }\n return undefined\n }\n}\n\n// ---- Module-level fixture helpers (pure; share no state) -------------------\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null\n}\n\nfunction stringifyFixtureValue(value: unknown): string {\n if (typeof value === 'string') return value\n if (\n value === undefined ||\n typeof value === 'function' ||\n typeof value === 'symbol'\n ) {\n return String(value)\n }\n try {\n return JSON.stringify(value)\n } catch (error) {\n console.error(\n '[ai-devtools] failed to JSON.stringify fixture value; falling back to String(). Tool call arguments may be malformed.',\n { error, value },\n )\n return String(value)\n }\n}\n\nfunction parseFixtureResultContent(content: string): unknown {\n try {\n return JSON.parse(content)\n } catch (error) {\n console.error(\n '[ai-devtools] failed to JSON.parse fixture result content; replaying as raw string. Fixture payload may be corrupted.',\n { error, content },\n )\n return content\n }\n}\n\nfunction cloneFixtureMessagePart(\n part: unknown,\n toolCallIds: Map<string, string>,\n): MessagePart | undefined {\n if (!isRecord(part) || typeof part.type !== 'string') return undefined\n const cloned: Record<string, unknown> = { ...part }\n\n if (part.type === 'tool-call' && typeof part.id === 'string') {\n cloned.id = toolCallIds.get(part.id) ?? part.id\n }\n if (part.type === 'tool-result' && typeof part.toolCallId === 'string') {\n cloned.toolCallId = toolCallIds.get(part.toolCallId) ?? part.toolCallId\n }\n return cloned as MessagePart\n}\n\nfunction firstToolCallId(parts: Array<MessagePart>): string | undefined {\n const toolCall = parts.find((part) => part.type === 'tool-call')\n return toolCall?.type === 'tool-call' ? toolCall.id : undefined\n}\n\nfunction hydrateToolCallOutputs(\n parts: Array<MessagePart>,\n fixtureOutput: { mappedToolCallId?: string; output: unknown },\n): void {\n for (const part of parts) {\n if (part.type !== 'tool-result') continue\n const toolCall = parts.find(\n (candidate): candidate is ToolCallPart =>\n candidate.type === 'tool-call' &&\n candidate.id === part.toolCallId &&\n candidate.output === undefined,\n )\n if (toolCall) {\n toolCall.output = Array.isArray(part.content)\n ? part.content\n : parseFixtureResultContent(part.content)\n }\n }\n\n if (fixtureOutput.mappedToolCallId && fixtureOutput.output !== undefined) {\n const toolCall = parts.find(\n (candidate): candidate is ToolCallPart =>\n candidate.type === 'tool-call' &&\n candidate.id === fixtureOutput.mappedToolCallId &&\n candidate.output === undefined,\n )\n if (toolCall) {\n toolCall.output = fixtureOutput.output\n }\n }\n}\n\nfunction hasToolCallId(\n messages: Array<UIMessage>,\n toolCallId: string,\n): boolean {\n return messages.some((message) =>\n message.parts.some((part) => {\n if (part.type === 'tool-call') return part.id === toolCallId\n if (part.type === 'tool-result') return part.toolCallId === toolCallId\n return false\n }),\n )\n}\n\n// Devtools surface for GenerationClient / VideoGenerationClient. Owns per-run\n// history, active-run lifecycle, and snapshot emission; the generation client\n// pushes its core state in via the record* methods.\n\nexport interface AIDevtoolsGenerationSnapshotBase<TOutput> {\n input: unknown\n result: TOutput | null\n preview: AIDevtoolsGenerationPreview\n progress: AIDevtoolsGenerationProgress | null\n status: AIDevtoolsGenerationRunStatus\n isLoading: boolean\n activeRunId: string | null\n runs: Array<AIDevtoolsGenerationRunSnapshot<TOutput>>\n error?: string\n}\n\nexport interface GenerationDevtoolsBridgeOptions<TOutput> extends Omit<\n AIDevtoolsBridgeOptions<AIDevtoolsGenerationSnapshotBase<TOutput>>,\n 'getSnapshot'\n> {\n getCoreState: () => GenerationDevtoolsCoreState<TOutput>\n maxRuns?: number\n}\n\nexport interface GenerationDevtoolsCoreState<TOutput> {\n input: unknown\n result: TOutput | null\n progress: AIDevtoolsGenerationProgress | null\n status: AIDevtoolsGenerationRunStatus\n isLoading: boolean\n error?: string\n}\n\nexport interface GenerationRunPatch<TOutput> {\n input?: unknown\n result?: TOutput | null\n preview?: AIDevtoolsGenerationPreview\n progress?: AIDevtoolsGenerationProgress | null\n status?: AIDevtoolsGenerationRunStatus\n isLoading?: boolean\n completedAt?: number\n error?: string\n clearError?: boolean\n}\n\nexport class GenerationDevtoolsBridge<TOutput> extends ClientDevtoolsBridge<\n AIDevtoolsGenerationSnapshotBase<TOutput>\n> {\n protected activeRunId: string | null = null\n protected activeRunStarted = false\n protected devtoolsRuns: Array<AIDevtoolsGenerationRunSnapshot<TOutput>> = []\n protected readonly maxRuns: number\n protected readonly getCoreState: () => GenerationDevtoolsCoreState<TOutput>\n\n constructor(options: GenerationDevtoolsBridgeOptions<TOutput>) {\n super({\n ...options,\n getSnapshot: () => this.buildSnapshot(),\n })\n this.maxRuns = options.maxRuns ?? 20\n this.getCoreState = options.getCoreState\n }\n\n // --- Run lifecycle (called by GenerationClient) -----------------------\n\n beginRun(input: unknown): string {\n const runId = this.generateRunId()\n this.activeRunId = runId\n this.activeRunStarted = false\n this.upsertRun(runId, {\n input,\n result: null,\n preview: this.createPreview(null),\n progress: null,\n status: 'generating',\n isLoading: true,\n clearError: true,\n })\n return runId\n }\n\n ensureRunStarted(runId: string): void {\n if (this.activeRunStarted && this.activeRunId === runId) return\n\n if (\n !this.activeRunStarted &&\n this.activeRunId &&\n this.activeRunId !== runId\n ) {\n this.renameRun(this.activeRunId, runId)\n }\n\n this.activeRunId = runId\n this.activeRunStarted = true\n this.upsertRun(runId, {\n status: 'generating',\n isLoading: true,\n clearError: true,\n })\n this.emitRunLifecycle('run:started', runId, 'started')\n this.emitState()\n }\n\n finishRun(\n runId: string,\n eventType: 'run:completed' | 'run:errored' | 'run:cancelled',\n status: 'completed' | 'errored' | 'cancelled',\n error?: string,\n ): void {\n this.ensureRunStarted(runId)\n const completedAt = Date.now()\n const completedProgress =\n status === 'completed' ? this.completeProgress() : this.getProgress()\n const runStatus =\n status === 'completed'\n ? 'success'\n : status === 'errored'\n ? 'error'\n : 'cancelled'\n\n this.upsertRun(runId, {\n status: runStatus,\n isLoading: false,\n progress: completedProgress,\n completedAt,\n ...(error ? { error } : { clearError: true }),\n })\n\n if (this.activeRunId === runId) {\n this.activeRunId = null\n }\n this.activeRunStarted = false\n this.emitRunLifecycle(eventType, runId, status, {\n ...(error ? { error } : {}),\n })\n this.emitState()\n }\n\n getActiveRunId(): string | null {\n return this.activeRunId\n }\n\n /** Clear all per-run history. Called when the client `reset()`s. */\n resetRuns(): void {\n this.activeRunId = null\n this.activeRunStarted = false\n this.devtoolsRuns = []\n }\n\n /** Record state changes from the client and emit the matching snapshot. */\n recordResultChange(): void {\n this.updateActiveRun({\n result: this.getCoreState().result,\n preview: this.createPreview(this.getCoreState().result),\n clearError: true,\n })\n this.emitState()\n }\n\n recordLoadingChange(): void {\n this.updateActiveRun({ isLoading: this.getCoreState().isLoading })\n this.emitState()\n }\n\n recordErrorChange(error: Error | undefined): void {\n this.updateActiveRun(\n error ? { error: error.message } : { clearError: true },\n )\n this.emitState()\n }\n\n recordStatusChange(status: AIDevtoolsGenerationRunStatus): void {\n this.updateActiveRun({ status })\n this.emitState()\n }\n\n recordProgressChange(): void {\n this.updateActiveRun({ progress: this.getCoreState().progress })\n this.emitState()\n }\n\n /** Emit the latest snapshot without touching run state. */\n emitState(): void {\n this.emitUpdated()\n this.emitSnapshot()\n }\n\n // --- Internal ---------------------------------------------------------\n\n protected buildSnapshot(): AIDevtoolsGenerationSnapshotBase<TOutput> {\n const core = this.getCoreState()\n return {\n input: core.input,\n result: core.result,\n preview: this.createPreview(core.result),\n progress: core.progress,\n status: core.status,\n isLoading: core.isLoading,\n activeRunId: this.activeRunId,\n runs: this.devtoolsRuns,\n ...(core.error ? { error: core.error } : {}),\n }\n }\n\n protected updateActiveRun(patch: GenerationRunPatch<TOutput>): void {\n if (!this.activeRunId) return\n this.upsertRun(this.activeRunId, patch)\n }\n\n protected upsertRun(runId: string, patch: GenerationRunPatch<TOutput>): void {\n const now = Date.now()\n const index = this.devtoolsRuns.findIndex((run) => run.id === runId)\n const existing = index >= 0 ? this.devtoolsRuns[index] : undefined\n const next: AIDevtoolsGenerationRunSnapshot<TOutput> = existing\n ? { ...existing }\n : {\n id: runId,\n input: this.getCoreState().input,\n result: null,\n preview: this.createPreview(null),\n progress: null,\n status: 'idle',\n isLoading: false,\n startedAt: now,\n updatedAt: now,\n }\n\n if ('input' in patch) next.input = patch.input ?? null\n if ('result' in patch) next.result = patch.result ?? null\n if (patch.preview) next.preview = patch.preview\n if ('progress' in patch) next.progress = patch.progress ?? null\n if (patch.status) next.status = patch.status\n if ('isLoading' in patch) next.isLoading = patch.isLoading === true\n if (patch.completedAt !== undefined) next.completedAt = patch.completedAt\n if (patch.clearError) delete next.error\n if (patch.error !== undefined) next.error = patch.error\n next.updatedAt = now\n\n if (index >= 0) {\n this.devtoolsRuns = this.devtoolsRuns.map((run) =>\n run.id === runId ? next : run,\n )\n } else {\n this.devtoolsRuns = [...this.devtoolsRuns, next]\n }\n\n if (this.devtoolsRuns.length > this.maxRuns) {\n this.devtoolsRuns = this.devtoolsRuns.slice(-this.maxRuns)\n }\n }\n\n protected renameRun(previousRunId: string, nextRunId: string): void {\n if (previousRunId === nextRunId) return\n\n const existing = this.devtoolsRuns.find((run) => run.id === previousRunId)\n if (!existing) return\n\n const renamed = { ...existing, id: nextRunId, updatedAt: Date.now() }\n this.devtoolsRuns = this.devtoolsRuns\n .filter((run) => run.id !== nextRunId)\n .map((run) => (run.id === previousRunId ? renamed : run))\n }\n\n protected getProgress(): AIDevtoolsGenerationProgress | null {\n return this.getCoreState().progress\n }\n\n protected completeProgress(): AIDevtoolsGenerationProgress | null {\n const progress = this.getCoreState().progress\n if (!progress) return null\n return {\n value: 100,\n ...(progress.message ? { message: progress.message } : {}),\n }\n }\n\n protected createPreview(result: TOutput | null): AIDevtoolsGenerationPreview {\n return createAIDevtoolsGenerationPreview({\n outputKind: this.options.metadata.outputKind,\n result,\n })\n }\n\n protected generateRunId(): string {\n return `run-${Date.now()}-${Math.random().toString(36).substring(7)}`\n }\n}\n\n// Video-job specialization: snapshots also carry the job id and the latest\n// provider-reported video status so the panel can show streaming progress\n// before the final URL lands.\n\nexport interface AIDevtoolsVideoSnapshotBase<\n TOutput,\n> extends AIDevtoolsGenerationSnapshotBase<TOutput> {\n jobId: string | null\n videoStatus: unknown\n}\n\nexport interface VideoDevtoolsCoreState<\n TOutput,\n> extends GenerationDevtoolsCoreState<TOutput> {\n jobId: string | null\n videoStatus: unknown\n}\n\nexport interface VideoDevtoolsBridgeOptions<TOutput> extends Omit<\n GenerationDevtoolsBridgeOptions<TOutput>,\n 'getCoreState'\n> {\n getCoreState: () => VideoDevtoolsCoreState<TOutput>\n}\n\nexport interface VideoRunPatch<TOutput> extends GenerationRunPatch<TOutput> {\n jobId?: string | null\n videoStatus?: unknown\n}\n\nexport class VideoDevtoolsBridge<\n TOutput,\n> extends GenerationDevtoolsBridge<TOutput> {\n constructor(options: VideoDevtoolsBridgeOptions<TOutput>) {\n super(options)\n }\n\n recordJobIdChange(): void {\n this.updateActiveRun({\n jobId: (this.getCoreState() as VideoDevtoolsCoreState<TOutput>).jobId,\n } as VideoRunPatch<TOutput>)\n this.emitState()\n }\n\n recordVideoStatusChange(): void {\n const core = this.getCoreState() as VideoDevtoolsCoreState<TOutput>\n this.updateActiveRun({\n videoStatus: core.videoStatus,\n preview: this.createVideoPreview(core.result, core.videoStatus),\n } as VideoRunPatch<TOutput>)\n this.emitState()\n }\n\n protected override buildSnapshot(): AIDevtoolsVideoSnapshotBase<TOutput> {\n const core = this.getCoreState() as VideoDevtoolsCoreState<TOutput>\n return {\n input: core.input,\n result: core.result,\n preview: this.createVideoPreview(core.result, core.videoStatus),\n progress: core.progress,\n status: core.status,\n isLoading: core.isLoading,\n activeRunId: this.activeRunId,\n runs: this.devtoolsRuns,\n jobId: core.jobId,\n videoStatus: core.videoStatus,\n ...(core.error ? { error: core.error } : {}),\n }\n }\n\n protected override upsertRun(\n runId: string,\n patch: VideoRunPatch<TOutput>,\n ): void {\n super.upsertRun(runId, patch)\n if (!('jobId' in patch || 'videoStatus' in patch)) return\n\n const index = this.devtoolsRuns.findIndex((run) => run.id === runId)\n if (index < 0) return\n const target = this.devtoolsRuns[index]\n if (!target) return\n const merged: AIDevtoolsGenerationRunSnapshot<TOutput> = { ...target }\n if ('jobId' in patch) merged.jobId = patch.jobId ?? null\n if ('videoStatus' in patch) merged.videoStatus = patch.videoStatus ?? null\n this.devtoolsRuns = this.devtoolsRuns.map((run) =>\n run.id === runId ? merged : run,\n )\n }\n\n // Override so record* methods inherited from GenerationDevtoolsBridge\n // (e.g. recordResultChange) thread the latest videoStatus into the preview.\n protected override createPreview(\n result: TOutput | null,\n ): AIDevtoolsGenerationPreview {\n const core = this.getCoreState() as VideoDevtoolsCoreState<TOutput>\n return this.createVideoPreview(result, core.videoStatus)\n }\n\n private createVideoPreview(\n result: TOutput | null,\n videoStatus: unknown,\n ): AIDevtoolsGenerationPreview {\n return createAIDevtoolsGenerationPreview({\n outputKind: this.options.metadata.outputKind,\n result,\n videoStatus,\n })\n }\n}\n\n// Wraps the plain emitter so callers can do `this.events.X(...)` and get:\n// auto-attached run/thread context on every event that accepts one,\n// an auto-emitted snapshot after each event, and passive streamId tracking\n// so resolveStreamId() works without the chat client telling it.\nclass ChatDevtoolsAwareEventEmitter extends DefaultChatClientEventEmitter {\n constructor(\n clientId: string,\n private readonly helper: ChatDevtoolsBridge,\n ) {\n super(clientId)\n }\n\n private afterEmit(streamId?: string): void {\n if (streamId) this.helper.recordStreamId(streamId)\n this.helper.emitSnapshot()\n }\n\n // -- methods with run context --------------------------------------------\n\n override textUpdated(\n streamId: string,\n messageId: string,\n content: string,\n context?: ChatClientRunEventContext,\n ): void {\n super.textUpdated(\n streamId,\n messageId,\n content,\n context ?? this.helper.getCurrentRunEventContext(),\n )\n this.afterEmit(streamId)\n }\n\n override thinkingUpdated(\n streamId: string,\n messageId: string,\n content: string,\n delta?: string,\n context?: ChatClientRunEventContext,\n ): void {\n super.thinkingUpdated(\n streamId,\n messageId,\n content,\n delta,\n context ?? this.helper.getCurrentRunEventContext(),\n )\n this.afterEmit(streamId)\n }\n\n override messageAppended(\n uiMessage: Parameters<DefaultChatClientEventEmitter['messageAppended']>[0],\n streamId?: string,\n context?: ChatClientEventContext,\n ): void {\n super.messageAppended(\n uiMessage,\n streamId,\n context ?? this.helper.getCurrentRunEventContext(),\n )\n this.afterEmit(streamId)\n }\n\n override toolCallStateChanged(\n streamId: string,\n messageId: string,\n toolCallId: string,\n toolName: string,\n state: string,\n args: string,\n context?: ChatClientRunEventContext,\n ): void {\n super.toolCallStateChanged(\n streamId,\n messageId,\n toolCallId,\n toolName,\n state,\n args,\n context ?? this.helper.getCurrentRunEventContext(),\n )\n this.afterEmit(streamId)\n }\n\n override structuredOutputChanged(\n eventName: Parameters<\n DefaultChatClientEventEmitter['structuredOutputChanged']\n >[0],\n streamId: string,\n messageId: string,\n output: Parameters<\n DefaultChatClientEventEmitter['structuredOutputChanged']\n >[3],\n context?: ChatClientRunEventContext,\n ): void {\n super.structuredOutputChanged(\n eventName,\n streamId,\n messageId,\n output,\n context ?? this.helper.getCurrentOrLastRunEventContext(),\n )\n this.afterEmit(streamId)\n }\n\n override approvalRequested(\n streamId: string,\n messageId: string,\n toolCallId: string,\n toolName: string,\n input: unknown,\n approvalId: string,\n context?: ChatClientRunEventContext,\n ): void {\n super.approvalRequested(\n streamId,\n messageId,\n toolCallId,\n toolName,\n input,\n approvalId,\n context ?? this.helper.getCurrentOrLastRunEventContext(),\n )\n this.afterEmit(streamId)\n }\n\n override toolResultAdded(\n toolCallId: string,\n toolName: string,\n output: unknown,\n state: string,\n context?: ChatClientEventContext,\n ): void {\n super.toolResultAdded(\n toolCallId,\n toolName,\n output,\n state,\n context ?? this.helper.getCurrentRunEventContext(),\n )\n this.afterEmit()\n }\n\n override toolApprovalResponded(\n approvalId: string,\n toolCallId: string,\n approved: boolean,\n context?: ChatClientRunEventContext,\n ): void {\n super.toolApprovalResponded(\n approvalId,\n toolCallId,\n approved,\n context ?? this.helper.getCurrentRunEventContext(),\n )\n this.afterEmit()\n }\n\n // -- methods without context (just auto-emit snapshot) -------------------\n\n override clientCreated(initialMessageCount: number): void {\n super.clientCreated(initialMessageCount)\n this.afterEmit()\n }\n override loadingChanged(isLoading: boolean): void {\n super.loadingChanged(isLoading)\n this.afterEmit()\n }\n override errorChanged(error: string | null): void {\n super.errorChanged(error)\n this.afterEmit()\n }\n override reloaded(fromMessageIndex: number): void {\n super.reloaded(fromMessageIndex)\n this.afterEmit()\n }\n override stopped(): void {\n super.stopped()\n this.afterEmit()\n }\n override messagesCleared(): void {\n super.messagesCleared()\n this.afterEmit()\n }\n override messageSent(\n messageId: string,\n content: Parameters<DefaultChatClientEventEmitter['messageSent']>[1],\n ): void {\n super.messageSent(messageId, content)\n this.afterEmit()\n }\n override toolFixtureApplied(\n fixture: Parameters<DefaultChatClientEventEmitter['toolFixtureApplied']>[0],\n ): void {\n super.toolFixtureApplied(fixture)\n this.afterEmit()\n }\n}\n\nexport function createChatDevtoolsBridge(\n options: ChatDevtoolsBridgeOptions,\n): ChatDevtoolsBridge {\n return new ChatDevtoolsBridge(options)\n}\n\nexport function createGenerationDevtoolsBridge<TOutput>(\n options: GenerationDevtoolsBridgeOptions<TOutput>,\n): GenerationDevtoolsBridge<TOutput> {\n return new GenerationDevtoolsBridge<TOutput>(options)\n}\n\nexport function createVideoDevtoolsBridge<TOutput>(\n options: VideoDevtoolsBridgeOptions<TOutput>,\n): VideoDevtoolsBridge<TOutput> {\n return new VideoDevtoolsBridge<TOutput>(options)\n}\n"],"names":[],"mappings":"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"}
@@ -6,7 +6,7 @@ export type { McpAppBridge, CreateMcpAppBridgeOptions } from './mcp-app-bridge.j
6
6
  export { RealtimeClient } from './realtime-client.js';
7
7
  export { GenerationClient } from './generation-client.js';
8
8
  export { VideoGenerationClient } from './video-generation-client.js';
9
- export type { UIMessage, MessagePart, TextPart, ToolCallPart, ToolResultPart, ThinkingPart, StructuredOutputPart, ChatClientPersistence, ChatClientOptions, ClientContextOptionFromTools, ChatRequestBody, InferChatMessages, InferredClientContext, ChatClientState, ConnectionStatus, ChatFetcher, ChatFetcherInput, ChatFetcherOptions, ChatTransport, DistributedOmit, MultimodalContent, } from './types.js';
9
+ export type { UIMessage, MessagePart, TextPart, ToolCallPart, ToolResultPart, ThinkingPart, StructuredOutputPart, ChatClientPersistence, ChatClientOptions, ClientContextOptionFromTools, ChatRequestBody, InferChatMessages, InferredClientContext, ChatClientState, ConnectionStatus, ChatFetcher, ChatFetcherInput, ChatFetcherOptions, ChatTransport, DistributedOmit, MultimodalContent, QueuedMessage, WhenBusy, QueueBusyReason, QueueConfig, QueueStrategy, QueueOption, SendMessageOptions, } from './types.js';
10
10
  export type { InferGenerationOutput, InferGenerationOutputFromReturn, GenerationClientState, GenerationClientOptions, GenerationFetcher, GenerationFetcherOptions, GenerationTransport, VideoGenerationClientOptions, VideoStatusInfo, VideoGenerateResult, ImageGenerateInput, AudioGenerateInput, SpeechGenerateInput, TranscriptionGenerateInput, SummarizeGenerateInput, VideoGenerateInput, } from './generation-types.js';
11
11
  export { GENERATION_EVENTS } from './generation-types.js';
12
12
  export { UnsupportedResponseStreamError } from './response-stream.js';
@@ -1,4 +1,4 @@
1
- import { AudioVisualization, RealtimeMessage, RealtimeMode, RealtimeStatus } from '@tanstack/ai/client';
1
+ import { AudioVisualization, RealtimeMessage, RealtimeMode, RealtimeSessionConfig, RealtimeStatus } from '@tanstack/ai/client';
2
2
  import { RealtimeClientOptions, RealtimeStateChangeCallback } from './realtime-types.js';
3
3
  /**
4
4
  * Client for managing realtime voice conversations.
@@ -78,6 +78,11 @@ export declare class RealtimeClient {
78
78
  get pendingAssistantTranscript(): string | null;
79
79
  /** Get audio visualization data */
80
80
  get audio(): AudioVisualization | null;
81
+ /**
82
+ * Update the session configuration.
83
+ * This applies changes to the active connection and persists them for future reconnections.
84
+ */
85
+ updateSession(config: Partial<RealtimeSessionConfig>): void;
81
86
  /**
82
87
  * Subscribe to state changes.
83
88
  * @returns Unsubscribe function
@@ -191,6 +191,32 @@ class RealtimeClient {
191
191
  get audio() {
192
192
  return this.connection?.getAudioVisualization() ?? null;
193
193
  }
194
+ /**
195
+ * Update the session configuration.
196
+ * This applies changes to the active connection and persists them for future reconnections.
197
+ */
198
+ updateSession(config) {
199
+ const o = this.options;
200
+ if (config.instructions !== void 0) o.instructions = config.instructions;
201
+ if (config.voice !== void 0) o.voice = config.voice;
202
+ if (config.vadMode !== void 0) o.vadMode = config.vadMode;
203
+ if (config.outputModalities !== void 0) {
204
+ o.outputModalities = config.outputModalities;
205
+ }
206
+ if (config.temperature !== void 0) o.temperature = config.temperature;
207
+ if (config.maxOutputTokens !== void 0) {
208
+ o.maxOutputTokens = config.maxOutputTokens;
209
+ }
210
+ if (config.semanticEagerness !== void 0) {
211
+ o.semanticEagerness = config.semanticEagerness;
212
+ }
213
+ if (config.providerOptions !== void 0) {
214
+ o.providerOptions = config.providerOptions;
215
+ }
216
+ if (this.connection) {
217
+ this.applySessionConfig();
218
+ }
219
+ }
194
220
  // ============================================================================
195
221
  // State Subscription
196
222
  // ============================================================================
@@ -248,6 +274,7 @@ class RealtimeClient {
248
274
  try {
249
275
  this.token = await this.options.getToken();
250
276
  this.scheduleTokenRefresh();
277
+ this.connection?.updateToken?.(this.token);
251
278
  } catch (error) {
252
279
  const err = error instanceof Error ? error : new Error(String(error));
253
280
  this.updateState({ error: err });
@@ -359,6 +386,16 @@ class RealtimeClient {
359
386
  this.options.onError?.(error);
360
387
  })
361
388
  );
389
+ this.unsubscribers.push(
390
+ this.connection.on("go_away", ({ timeLeft }) => {
391
+ this.options.onGoAway?.(timeLeft);
392
+ })
393
+ );
394
+ this.unsubscribers.push(
395
+ this.connection.on("usage", (usage) => {
396
+ this.options.onUsage?.(usage);
397
+ })
398
+ );
362
399
  }
363
400
  applySessionConfig() {
364
401
  if (!this.connection) return;
@@ -376,10 +413,12 @@ class RealtimeClient {
376
413
  if (!hasConfig) return;
377
414
  const toolsConfig = tools ? Array.from(this.clientTools.values()).map((t) => {
378
415
  const inputSchema = t.inputSchema ? convertSchemaToJsonSchema(t.inputSchema) : void 0;
416
+ const outputSchema = t.outputSchema ? convertSchemaToJsonSchema(t.outputSchema) : void 0;
379
417
  return {
380
418
  name: t.name,
381
419
  description: t.description,
382
- ...inputSchema ? { inputSchema } : {}
420
+ ...inputSchema ? { inputSchema } : {},
421
+ ...outputSchema ? { outputSchema } : {}
383
422
  };
384
423
  }) : void 0;
385
424
  this.connection.updateSession({
@@ -1 +1 @@
1
- {"version":3,"file":"realtime-client.js","sources":["../../src/realtime-client.ts"],"sourcesContent":["import { convertSchemaToJsonSchema } from '@tanstack/ai/client'\nimport type {\n AnyClientTool,\n AudioVisualization,\n RealtimeMessage,\n RealtimeMode,\n RealtimeStatus,\n RealtimeToken,\n} from '@tanstack/ai/client'\nimport type {\n RealtimeClientOptions,\n RealtimeClientState,\n RealtimeConnection,\n RealtimeStateChangeCallback,\n} from './realtime-types'\n\n// Token refresh buffer - refresh 1 minute before expiry\nconst TOKEN_REFRESH_BUFFER_MS = 60_000\n\n/**\n * Client for managing realtime voice conversations.\n *\n * Handles connection lifecycle, audio I/O, message state,\n * and tool execution for realtime voice-to-voice AI interactions.\n *\n * @example\n * ```typescript\n * import { RealtimeClient } from '@tanstack/ai-client'\n * import { openaiRealtime } from '@tanstack/ai-openai'\n *\n * const client = new RealtimeClient({\n * getToken: () => fetch('/api/realtime-token').then(r => r.json()),\n * adapter: openaiRealtime(),\n * tools: [myTool.client(handler)],\n * onMessage: (msg) => console.log('Message:', msg),\n * })\n *\n * await client.connect()\n * ```\n */\nexport class RealtimeClient {\n private readonly options: RealtimeClientOptions\n private connection: RealtimeConnection | null = null\n private token: RealtimeToken | null = null\n private tokenRefreshTimeout: ReturnType<typeof setTimeout> | null = null\n private readonly clientTools: Map<string, AnyClientTool>\n private readonly stateChangeCallbacks: Set<RealtimeStateChangeCallback> =\n new Set()\n private unsubscribers: Array<() => void> = []\n\n private state: RealtimeClientState = {\n status: 'idle',\n mode: 'idle',\n messages: [],\n pendingUserTranscript: null,\n pendingAssistantTranscript: null,\n error: null,\n }\n\n constructor(options: RealtimeClientOptions) {\n this.options = {\n autoPlayback: true,\n autoCapture: true,\n vadMode: 'server',\n ...options,\n }\n\n // Build client tools map\n this.clientTools = new Map()\n if (options.tools) {\n for (const tool of options.tools) {\n this.clientTools.set(tool.name, tool)\n }\n }\n }\n\n // ============================================================================\n // Connection Lifecycle\n // ============================================================================\n\n /**\n * Connect to the realtime session.\n * Fetches a token and establishes the connection.\n */\n async connect(): Promise<void> {\n if (this.state.status === 'connected') {\n return\n }\n\n this.updateState({ status: 'connecting', error: null })\n\n try {\n // Fetch token from server\n this.token = await this.options.getToken()\n\n // Schedule token refresh\n this.scheduleTokenRefresh()\n\n // Connect via adapter (pass tools for providers like ElevenLabs that need them at connect time)\n const toolsList =\n this.clientTools.size > 0\n ? Array.from(this.clientTools.values())\n : undefined\n this.connection = await this.options.adapter.connect(\n this.token,\n toolsList,\n )\n\n // Subscribe to connection events\n this.subscribeToConnectionEvents()\n\n // Auto-configure session with client-provided settings\n this.applySessionConfig()\n\n // Start audio capture if configured\n if (this.options.autoCapture) {\n await this.connection.startAudioCapture()\n }\n\n this.updateState({ status: 'connected', mode: 'listening' })\n this.options.onConnect?.()\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error))\n this.updateState({ status: 'error', error: err })\n this.options.onError?.(err)\n throw err\n }\n }\n\n /**\n * Disconnect from the realtime session.\n */\n async disconnect(): Promise<void> {\n if (this.tokenRefreshTimeout) {\n clearTimeout(this.tokenRefreshTimeout)\n this.tokenRefreshTimeout = null\n }\n\n // Unsubscribe from all events\n for (const unsub of this.unsubscribers) {\n unsub()\n }\n this.unsubscribers = []\n\n if (this.connection) {\n await this.connection.disconnect()\n this.connection = null\n }\n\n this.token = null\n this.updateState({\n status: 'idle',\n mode: 'idle',\n pendingUserTranscript: null,\n pendingAssistantTranscript: null,\n })\n this.options.onDisconnect?.()\n }\n\n // ============================================================================\n // Voice Control\n // ============================================================================\n\n /**\n * Start listening for voice input.\n * Only needed when vadMode is 'manual'.\n */\n startListening(): void {\n if (!this.connection || this.state.status !== 'connected') {\n return\n }\n void this.connection.startAudioCapture()\n this.updateState({ mode: 'listening' })\n }\n\n /**\n * Stop listening for voice input.\n * Only needed when vadMode is 'manual'.\n */\n stopListening(): void {\n if (!this.connection) {\n return\n }\n this.connection.stopAudioCapture()\n this.updateState({ mode: 'idle' })\n }\n\n /**\n * Interrupt the current assistant response.\n */\n interrupt(): void {\n if (!this.connection) {\n return\n }\n this.connection.interrupt()\n }\n\n // ============================================================================\n // Text Input\n // ============================================================================\n\n /**\n * Send a text message instead of voice.\n */\n sendText(text: string): void {\n if (!this.connection || this.state.status !== 'connected') {\n return\n }\n\n // Add user message\n const userMessage: RealtimeMessage = {\n id: this.generateId(),\n role: 'user',\n timestamp: Date.now(),\n parts: [{ type: 'text', content: text }],\n }\n this.addMessage(userMessage)\n\n // Send to provider\n this.connection.sendText(text)\n }\n\n /**\n * Send an image to the conversation.\n * @param imageData - Base64-encoded image data or a URL\n * @param mimeType - MIME type of the image (e.g., 'image/png', 'image/jpeg')\n */\n sendImage(imageData: string, mimeType: string): void {\n if (!this.connection || this.state.status !== 'connected') {\n return\n }\n\n // Add user message with image part\n const userMessage: RealtimeMessage = {\n id: this.generateId(),\n role: 'user',\n timestamp: Date.now(),\n parts: [{ type: 'image', data: imageData, mimeType }],\n }\n this.addMessage(userMessage)\n\n // Send to provider\n this.connection.sendImage(imageData, mimeType)\n }\n\n // ============================================================================\n // State Access\n // ============================================================================\n\n /** Get current connection status */\n get status(): RealtimeStatus {\n return this.state.status\n }\n\n /** Get current mode */\n get mode(): RealtimeMode {\n return this.state.mode\n }\n\n /** Get conversation messages */\n get messages(): Array<RealtimeMessage> {\n return this.state.messages\n }\n\n /** Get current error, if any */\n get error(): Error | null {\n return this.state.error\n }\n\n /** Get pending user transcript (while user is speaking) */\n get pendingUserTranscript(): string | null {\n return this.state.pendingUserTranscript\n }\n\n /** Get pending assistant transcript (while assistant is speaking) */\n get pendingAssistantTranscript(): string | null {\n return this.state.pendingAssistantTranscript\n }\n\n /** Get audio visualization data */\n get audio(): AudioVisualization | null {\n return this.connection?.getAudioVisualization() ?? null\n }\n\n // ============================================================================\n // State Subscription\n // ============================================================================\n\n /**\n * Subscribe to state changes.\n * @returns Unsubscribe function\n */\n onStateChange(callback: RealtimeStateChangeCallback): () => void {\n this.stateChangeCallbacks.add(callback)\n return () => {\n this.stateChangeCallbacks.delete(callback)\n }\n }\n\n // ============================================================================\n // Cleanup\n // ============================================================================\n\n /**\n * Clean up resources.\n * Call this when disposing of the client.\n */\n destroy(): void {\n void this.disconnect()\n this.stateChangeCallbacks.clear()\n }\n\n // ============================================================================\n // Private Methods\n // ============================================================================\n\n private updateState(updates: Partial<RealtimeClientState>): void {\n this.state = { ...this.state, ...updates }\n\n // Notify callbacks\n for (const callback of this.stateChangeCallbacks) {\n callback(this.state)\n }\n\n // Notify specific callbacks\n if ('status' in updates && updates.status !== undefined) {\n this.options.onStatusChange?.(updates.status)\n }\n if ('mode' in updates && updates.mode !== undefined) {\n this.options.onModeChange?.(updates.mode)\n }\n }\n\n private addMessage(message: RealtimeMessage): void {\n this.updateState({\n messages: [...this.state.messages, message],\n })\n this.options.onMessage?.(message)\n }\n\n private scheduleTokenRefresh(): void {\n if (!this.token) return\n\n const timeUntilExpiry = this.token.expiresAt - Date.now()\n const refreshIn = Math.max(0, timeUntilExpiry - TOKEN_REFRESH_BUFFER_MS)\n\n this.tokenRefreshTimeout = setTimeout(() => {\n void this.refreshToken()\n }, refreshIn)\n }\n\n private async refreshToken(): Promise<void> {\n try {\n this.token = await this.options.getToken()\n this.scheduleTokenRefresh()\n // Note: Some providers may require reconnection with new token\n // This is handled by the adapter implementation\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error))\n this.updateState({ error: err })\n this.options.onError?.(err)\n }\n }\n\n private subscribeToConnectionEvents(): void {\n if (!this.connection) return\n\n // Status changes\n this.unsubscribers.push(\n this.connection.on('status_change', ({ status }) => {\n this.updateState({ status })\n }),\n )\n\n // Mode changes\n this.unsubscribers.push(\n this.connection.on('mode_change', ({ mode }) => {\n this.updateState({ mode })\n }),\n )\n\n // Transcripts (streaming)\n // User transcripts are added as messages when final (no separate message_complete for user input)\n // Assistant transcripts are streamed, final message comes via message_complete\n this.unsubscribers.push(\n this.connection.on('transcript', ({ role, transcript, isFinal }) => {\n if (role === 'user') {\n this.updateState({\n pendingUserTranscript: isFinal ? null : transcript,\n })\n // Add user message when transcript is finalized\n if (isFinal && transcript) {\n this.addMessage({\n id: this.generateId(),\n role: 'user',\n timestamp: Date.now(),\n parts: [{ type: 'audio', transcript, durationMs: 0 }],\n })\n }\n } else {\n // Assistant transcripts - just update pending, message_complete handles final\n this.updateState({\n pendingAssistantTranscript: isFinal ? null : transcript,\n })\n }\n }),\n )\n\n // Tool calls\n this.unsubscribers.push(\n this.connection.on('tool_call', ({ toolCallId, toolName, input }) => {\n if (!toolCallId) {\n console.error(\n '[RealtimeClient] tool_call missing toolCallId',\n toolName,\n )\n return\n }\n const tool = this.clientTools.get(toolName)\n const execute = tool?.execute\n if (execute) {\n void (async () => {\n try {\n const output = await execute(input)\n this.connection?.sendToolResult(\n toolCallId,\n typeof output === 'string' ? output : JSON.stringify(output),\n )\n } catch (error) {\n const errMsg =\n error instanceof Error ? error.message : String(error)\n this.connection?.sendToolResult(\n toolCallId,\n JSON.stringify({ error: errMsg }),\n )\n }\n })()\n } else {\n this.connection?.sendToolResult(\n toolCallId,\n JSON.stringify({\n error: `Unknown or non-executable tool: ${String(toolName)}`,\n }),\n )\n }\n }),\n )\n\n // Message complete\n this.unsubscribers.push(\n this.connection.on('message_complete', ({ message }) => {\n // Replace pending message with final version if needed\n const existingIndex = this.state.messages.findIndex(\n (m) => m.id === message.id,\n )\n if (existingIndex >= 0) {\n const newMessages = [...this.state.messages]\n newMessages[existingIndex] = message\n this.updateState({ messages: newMessages })\n } else {\n this.addMessage(message)\n }\n }),\n )\n\n // Interruption\n this.unsubscribers.push(\n this.connection.on('interrupted', ({ messageId }) => {\n if (messageId) {\n const newMessages = this.state.messages.map((m) =>\n m.id === messageId ? { ...m, interrupted: true } : m,\n )\n this.updateState({ messages: newMessages })\n }\n this.updateState({\n mode: 'listening',\n pendingAssistantTranscript: null,\n })\n this.options.onInterrupted?.()\n }),\n )\n\n // Errors\n this.unsubscribers.push(\n this.connection.on('error', ({ error }) => {\n this.updateState({ error })\n this.options.onError?.(error)\n }),\n )\n }\n\n private applySessionConfig(): void {\n if (!this.connection) return\n\n const {\n instructions,\n voice,\n vadMode,\n tools,\n outputModalities,\n temperature,\n maxOutputTokens,\n semanticEagerness,\n } = this.options\n const hasConfig =\n instructions ||\n voice ||\n vadMode ||\n (tools && tools.length > 0) ||\n outputModalities ||\n temperature !== undefined ||\n maxOutputTokens !== undefined ||\n semanticEagerness\n if (!hasConfig) return\n\n // `RealtimeToolConfig.inputSchema` is `Record<string, any>` (no\n // `undefined` under `exactOptionalPropertyTypes`). Conditionally spread\n // it so we don't pass `undefined` when the tool has no input schema.\n const toolsConfig = tools\n ? Array.from(this.clientTools.values()).map((t) => {\n const inputSchema = t.inputSchema\n ? convertSchemaToJsonSchema(t.inputSchema)\n : undefined\n return {\n name: t.name,\n description: t.description,\n ...(inputSchema ? { inputSchema } : {}),\n }\n })\n : undefined\n\n // `RealtimeSessionConfig` declares each field as `field?: T` (no\n // `undefined`). Spread each one conditionally so we don't violate\n // `exactOptionalPropertyTypes` when the source is `T | undefined`.\n this.connection.updateSession({\n ...(instructions !== undefined ? { instructions } : {}),\n ...(voice !== undefined ? { voice } : {}),\n ...(vadMode !== undefined ? { vadMode } : {}),\n ...(toolsConfig !== undefined ? { tools: toolsConfig } : {}),\n ...(outputModalities !== undefined ? { outputModalities } : {}),\n ...(temperature !== undefined ? { temperature } : {}),\n ...(maxOutputTokens !== undefined ? { maxOutputTokens } : {}),\n ...(semanticEagerness !== undefined ? { semanticEagerness } : {}),\n })\n }\n\n private generateId(): string {\n return `msg-${Date.now()}-${Math.random().toString(36).substring(7)}`\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"realtime-client.js","sources":["../../src/realtime-client.ts"],"sourcesContent":["import { convertSchemaToJsonSchema } from '@tanstack/ai/client'\nimport type {\n AnyClientTool,\n AudioVisualization,\n RealtimeMessage,\n RealtimeMode,\n RealtimeSessionConfig,\n RealtimeStatus,\n RealtimeToken,\n} from '@tanstack/ai/client'\nimport type {\n RealtimeClientOptions,\n RealtimeClientState,\n RealtimeConnection,\n RealtimeStateChangeCallback,\n} from './realtime-types'\n\n// Token refresh buffer - refresh 1 minute before expiry\nconst TOKEN_REFRESH_BUFFER_MS = 60_000\n\n/**\n * Client for managing realtime voice conversations.\n *\n * Handles connection lifecycle, audio I/O, message state,\n * and tool execution for realtime voice-to-voice AI interactions.\n *\n * @example\n * ```typescript\n * import { RealtimeClient } from '@tanstack/ai-client'\n * import { openaiRealtime } from '@tanstack/ai-openai'\n *\n * const client = new RealtimeClient({\n * getToken: () => fetch('/api/realtime-token').then(r => r.json()),\n * adapter: openaiRealtime(),\n * tools: [myTool.client(handler)],\n * onMessage: (msg) => console.log('Message:', msg),\n * })\n *\n * await client.connect()\n * ```\n */\nexport class RealtimeClient {\n private readonly options: RealtimeClientOptions\n private connection: RealtimeConnection | null = null\n private token: RealtimeToken | null = null\n private tokenRefreshTimeout: ReturnType<typeof setTimeout> | null = null\n private readonly clientTools: Map<string, AnyClientTool>\n private readonly stateChangeCallbacks: Set<RealtimeStateChangeCallback> =\n new Set()\n private unsubscribers: Array<() => void> = []\n\n private state: RealtimeClientState = {\n status: 'idle',\n mode: 'idle',\n messages: [],\n pendingUserTranscript: null,\n pendingAssistantTranscript: null,\n error: null,\n }\n\n constructor(options: RealtimeClientOptions) {\n this.options = {\n autoPlayback: true,\n autoCapture: true,\n vadMode: 'server',\n ...options,\n }\n\n // Build client tools map\n this.clientTools = new Map()\n if (options.tools) {\n for (const tool of options.tools) {\n this.clientTools.set(tool.name, tool)\n }\n }\n }\n\n // ============================================================================\n // Connection Lifecycle\n // ============================================================================\n\n /**\n * Connect to the realtime session.\n * Fetches a token and establishes the connection.\n */\n async connect(): Promise<void> {\n if (this.state.status === 'connected') {\n return\n }\n\n this.updateState({ status: 'connecting', error: null })\n\n try {\n // Fetch token from server\n this.token = await this.options.getToken()\n\n // Schedule token refresh\n this.scheduleTokenRefresh()\n\n // Connect via adapter (pass tools for providers like ElevenLabs that need them at connect time)\n const toolsList =\n this.clientTools.size > 0\n ? Array.from(this.clientTools.values())\n : undefined\n\n this.connection = await this.options.adapter.connect(\n this.token,\n toolsList,\n )\n\n // Subscribe to connection events\n this.subscribeToConnectionEvents()\n\n // Auto-configure session with client-provided settings\n this.applySessionConfig()\n\n // Start audio capture if configured\n if (this.options.autoCapture) {\n await this.connection.startAudioCapture()\n }\n\n this.updateState({ status: 'connected', mode: 'listening' })\n this.options.onConnect?.()\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error))\n this.updateState({ status: 'error', error: err })\n this.options.onError?.(err)\n throw err\n }\n }\n\n /**\n * Disconnect from the realtime session.\n */\n async disconnect(): Promise<void> {\n if (this.tokenRefreshTimeout) {\n clearTimeout(this.tokenRefreshTimeout)\n this.tokenRefreshTimeout = null\n }\n\n // Unsubscribe from all events\n for (const unsub of this.unsubscribers) {\n unsub()\n }\n this.unsubscribers = []\n\n if (this.connection) {\n await this.connection.disconnect()\n this.connection = null\n }\n\n this.token = null\n this.updateState({\n status: 'idle',\n mode: 'idle',\n pendingUserTranscript: null,\n pendingAssistantTranscript: null,\n })\n this.options.onDisconnect?.()\n }\n\n // ============================================================================\n // Voice Control\n // ============================================================================\n\n /**\n * Start listening for voice input.\n * Only needed when vadMode is 'manual'.\n */\n startListening(): void {\n if (!this.connection || this.state.status !== 'connected') {\n return\n }\n void this.connection.startAudioCapture()\n this.updateState({ mode: 'listening' })\n }\n\n /**\n * Stop listening for voice input.\n * Only needed when vadMode is 'manual'.\n */\n stopListening(): void {\n if (!this.connection) {\n return\n }\n this.connection.stopAudioCapture()\n this.updateState({ mode: 'idle' })\n }\n\n /**\n * Interrupt the current assistant response.\n */\n interrupt(): void {\n if (!this.connection) {\n return\n }\n this.connection.interrupt()\n }\n\n // ============================================================================\n // Text Input\n // ============================================================================\n\n /**\n * Send a text message instead of voice.\n */\n sendText(text: string): void {\n if (!this.connection || this.state.status !== 'connected') {\n return\n }\n\n // Add user message\n const userMessage: RealtimeMessage = {\n id: this.generateId(),\n role: 'user',\n timestamp: Date.now(),\n parts: [{ type: 'text', content: text }],\n }\n this.addMessage(userMessage)\n\n // Send to provider\n this.connection.sendText(text)\n }\n\n /**\n * Send an image to the conversation.\n * @param imageData - Base64-encoded image data or a URL\n * @param mimeType - MIME type of the image (e.g., 'image/png', 'image/jpeg')\n */\n sendImage(imageData: string, mimeType: string): void {\n if (!this.connection || this.state.status !== 'connected') {\n return\n }\n\n // Add user message with image part\n const userMessage: RealtimeMessage = {\n id: this.generateId(),\n role: 'user',\n timestamp: Date.now(),\n parts: [{ type: 'image', data: imageData, mimeType }],\n }\n this.addMessage(userMessage)\n\n // Send to provider\n this.connection.sendImage(imageData, mimeType)\n }\n\n // ============================================================================\n // State Access\n // ============================================================================\n\n /** Get current connection status */\n get status(): RealtimeStatus {\n return this.state.status\n }\n\n /** Get current mode */\n get mode(): RealtimeMode {\n return this.state.mode\n }\n\n /** Get conversation messages */\n get messages(): Array<RealtimeMessage> {\n return this.state.messages\n }\n\n /** Get current error, if any */\n get error(): Error | null {\n return this.state.error\n }\n\n /** Get pending user transcript (while user is speaking) */\n get pendingUserTranscript(): string | null {\n return this.state.pendingUserTranscript\n }\n\n /** Get pending assistant transcript (while assistant is speaking) */\n get pendingAssistantTranscript(): string | null {\n return this.state.pendingAssistantTranscript\n }\n\n /** Get audio visualization data */\n get audio(): AudioVisualization | null {\n return this.connection?.getAudioVisualization() ?? null\n }\n\n /**\n * Update the session configuration.\n * This applies changes to the active connection and persists them for future reconnections.\n */\n updateSession(config: Partial<RealtimeSessionConfig>): void {\n // Persist type-compatible fields so future (re)connections use the updated\n // config. `tools` is intentionally excluded: a session's tool configs are\n // serialized descriptors, whereas `options.tools` holds executable client\n // tools tracked separately via `clientTools`.\n const o = this.options\n if (config.instructions !== undefined) o.instructions = config.instructions\n if (config.voice !== undefined) o.voice = config.voice\n if (config.vadMode !== undefined) o.vadMode = config.vadMode\n if (config.outputModalities !== undefined) {\n o.outputModalities = config.outputModalities\n }\n if (config.temperature !== undefined) o.temperature = config.temperature\n if (config.maxOutputTokens !== undefined) {\n o.maxOutputTokens = config.maxOutputTokens\n }\n if (config.semanticEagerness !== undefined) {\n o.semanticEagerness = config.semanticEagerness\n }\n if (config.providerOptions !== undefined) {\n o.providerOptions = config.providerOptions\n }\n\n if (this.connection) {\n this.applySessionConfig()\n }\n }\n\n // ============================================================================\n // State Subscription\n // ============================================================================\n\n /**\n * Subscribe to state changes.\n * @returns Unsubscribe function\n */\n onStateChange(callback: RealtimeStateChangeCallback): () => void {\n this.stateChangeCallbacks.add(callback)\n return () => {\n this.stateChangeCallbacks.delete(callback)\n }\n }\n\n // ============================================================================\n // Cleanup\n // ============================================================================\n\n /**\n * Clean up resources.\n * Call this when disposing of the client.\n */\n destroy(): void {\n void this.disconnect()\n this.stateChangeCallbacks.clear()\n }\n\n // ============================================================================\n // Private Methods\n // ============================================================================\n\n private updateState(updates: Partial<RealtimeClientState>): void {\n this.state = { ...this.state, ...updates }\n\n // Notify callbacks\n for (const callback of this.stateChangeCallbacks) {\n callback(this.state)\n }\n\n // Notify specific callbacks\n if ('status' in updates && updates.status !== undefined) {\n this.options.onStatusChange?.(updates.status)\n }\n if ('mode' in updates && updates.mode !== undefined) {\n this.options.onModeChange?.(updates.mode)\n }\n }\n\n private addMessage(message: RealtimeMessage): void {\n this.updateState({\n messages: [...this.state.messages, message],\n })\n this.options.onMessage?.(message)\n }\n\n private scheduleTokenRefresh(): void {\n if (!this.token) return\n\n const timeUntilExpiry = this.token.expiresAt - Date.now()\n const refreshIn = Math.max(0, timeUntilExpiry - TOKEN_REFRESH_BUFFER_MS)\n\n this.tokenRefreshTimeout = setTimeout(() => {\n void this.refreshToken()\n }, refreshIn)\n }\n\n private async refreshToken(): Promise<void> {\n try {\n this.token = await this.options.getToken()\n this.scheduleTokenRefresh()\n this.connection?.updateToken?.(this.token)\n // Note: Some providers may require reconnection with new token\n // This is handled by the adapter implementation\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error))\n this.updateState({ error: err })\n this.options.onError?.(err)\n }\n }\n\n private subscribeToConnectionEvents(): void {\n if (!this.connection) return\n\n // Status changes\n this.unsubscribers.push(\n this.connection.on('status_change', ({ status }) => {\n this.updateState({ status })\n }),\n )\n\n // Mode changes\n this.unsubscribers.push(\n this.connection.on('mode_change', ({ mode }) => {\n this.updateState({ mode })\n }),\n )\n\n // Transcripts (streaming)\n // User transcripts are added as messages when final (no separate message_complete for user input)\n // Assistant transcripts are streamed, final message comes via message_complete\n this.unsubscribers.push(\n this.connection.on('transcript', ({ role, transcript, isFinal }) => {\n if (role === 'user') {\n this.updateState({\n pendingUserTranscript: isFinal ? null : transcript,\n })\n // Add user message when transcript is finalized\n if (isFinal && transcript) {\n this.addMessage({\n id: this.generateId(),\n role: 'user',\n timestamp: Date.now(),\n parts: [{ type: 'audio', transcript, durationMs: 0 }],\n })\n }\n } else {\n // Assistant transcripts - just update pending, message_complete handles final\n this.updateState({\n pendingAssistantTranscript: isFinal ? null : transcript,\n })\n }\n }),\n )\n\n // Tool calls\n this.unsubscribers.push(\n this.connection.on('tool_call', ({ toolCallId, toolName, input }) => {\n if (!toolCallId) {\n console.error(\n '[RealtimeClient] tool_call missing toolCallId',\n toolName,\n )\n return\n }\n const tool = this.clientTools.get(toolName)\n const execute = tool?.execute\n if (execute) {\n void (async () => {\n try {\n const output = await execute(input)\n this.connection?.sendToolResult(\n toolCallId,\n typeof output === 'string' ? output : JSON.stringify(output),\n )\n } catch (error) {\n const errMsg =\n error instanceof Error ? error.message : String(error)\n this.connection?.sendToolResult(\n toolCallId,\n JSON.stringify({ error: errMsg }),\n )\n }\n })()\n } else {\n this.connection?.sendToolResult(\n toolCallId,\n JSON.stringify({\n error: `Unknown or non-executable tool: ${String(toolName)}`,\n }),\n )\n }\n }),\n )\n\n // Message complete\n this.unsubscribers.push(\n this.connection.on('message_complete', ({ message }) => {\n // Replace pending message with final version if needed\n const existingIndex = this.state.messages.findIndex(\n (m) => m.id === message.id,\n )\n if (existingIndex >= 0) {\n const newMessages = [...this.state.messages]\n newMessages[existingIndex] = message\n this.updateState({ messages: newMessages })\n } else {\n this.addMessage(message)\n }\n }),\n )\n\n // Interruption\n this.unsubscribers.push(\n this.connection.on('interrupted', ({ messageId }) => {\n if (messageId) {\n const newMessages = this.state.messages.map((m) =>\n m.id === messageId ? { ...m, interrupted: true } : m,\n )\n this.updateState({ messages: newMessages })\n }\n this.updateState({\n mode: 'listening',\n pendingAssistantTranscript: null,\n })\n this.options.onInterrupted?.()\n }),\n )\n\n // Errors\n this.unsubscribers.push(\n this.connection.on('error', ({ error }) => {\n this.updateState({ error })\n this.options.onError?.(error)\n }),\n )\n\n this.unsubscribers.push(\n this.connection.on('go_away', ({ timeLeft }) => {\n this.options.onGoAway?.(timeLeft)\n }),\n )\n\n this.unsubscribers.push(\n this.connection.on('usage', (usage) => {\n this.options.onUsage?.(usage)\n }),\n )\n }\n\n private applySessionConfig(): void {\n if (!this.connection) return\n\n const {\n instructions,\n voice,\n vadMode,\n tools,\n outputModalities,\n temperature,\n maxOutputTokens,\n semanticEagerness,\n } = this.options\n const hasConfig =\n instructions ||\n voice ||\n vadMode ||\n (tools && tools.length > 0) ||\n outputModalities ||\n temperature !== undefined ||\n maxOutputTokens !== undefined ||\n semanticEagerness\n if (!hasConfig) return\n\n // `RealtimeToolConfig.inputSchema`/`outputSchema` are `Record<string, any>`\n // (no `undefined` under `exactOptionalPropertyTypes`). Conditionally spread\n // each so we don't pass `undefined` when the tool has no such schema.\n const toolsConfig = tools\n ? Array.from(this.clientTools.values()).map((t) => {\n const inputSchema = t.inputSchema\n ? convertSchemaToJsonSchema(t.inputSchema)\n : undefined\n const outputSchema = t.outputSchema\n ? convertSchemaToJsonSchema(t.outputSchema)\n : undefined\n return {\n name: t.name,\n description: t.description,\n ...(inputSchema ? { inputSchema } : {}),\n ...(outputSchema ? { outputSchema } : {}),\n }\n })\n : undefined\n\n // `RealtimeSessionConfig` declares each field as `field?: T` (no\n // `undefined`). Spread each one conditionally so we don't violate\n // `exactOptionalPropertyTypes` when the source is `T | undefined`.\n this.connection.updateSession({\n ...(instructions !== undefined ? { instructions } : {}),\n ...(voice !== undefined ? { voice } : {}),\n ...(vadMode !== undefined ? { vadMode } : {}),\n ...(toolsConfig !== undefined ? { tools: toolsConfig } : {}),\n ...(outputModalities !== undefined ? { outputModalities } : {}),\n ...(temperature !== undefined ? { temperature } : {}),\n ...(maxOutputTokens !== undefined ? { maxOutputTokens } : {}),\n ...(semanticEagerness !== undefined ? { semanticEagerness } : {}),\n })\n }\n\n private generateId(): string {\n return `msg-${Date.now()}-${Math.random().toString(36).substring(7)}`\n }\n}\n"],"names":[],"mappings":"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"}