@tanstack/ai-client 0.23.3 → 0.25.1

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","names":[],"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 {\n AIDevtoolsEventVisibility,\n MemoryScopeLite,\n} 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\n/**\n * Structural mirror of `MemoryStateEventValue` from `@tanstack/ai-memory` — the\n * payload of the `memory:state` CUSTOM chunk. Kept local so `ai-client` doesn't\n * depend on `ai-memory`; the memory middleware is the producer.\n */\ninterface MemoryStateEventValue {\n scope: MemoryScopeLite\n adapter: string\n query?: string\n recall?: {\n fragmentCount?: number\n hasTools?: boolean\n systemPromptChars?: number\n durationMs?: number\n }\n snapshot?: {\n takenAt: string\n data: unknown\n facts?: Array<{\n id: string\n text: string\n source?: string\n createdAt?: string\n }>\n }\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 // oxlint-disable-next-line eslint-js/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 this.onReplayState()\n }\n\n /**\n * Extension hook for subclasses to replay any additional cached state on a\n * `devtools:request-state` (i.e. when a panel opens). Called only after the\n * base guards (disposed/superseded/targetHookId) pass. No-op by default.\n */\n protected onReplayState(): void {}\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 // Fixture routing: `hookId` wins when present (latest bridge for that\n // registry key). `threadId` is the fallback for fixtures scoped only to a\n // conversation / generation slot without a hook id.\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 protected createEnvelope(\n eventType:\n | 'hook:registered'\n | 'hook:updated'\n | 'hook:unregistered'\n | 'hook:state-snapshot'\n | 'tools:registered'\n | 'memory:retrieve:started'\n | 'memory:retrieve:completed'\n | 'memory:snapshot'\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 /** Last transported `memory:state` value, replayed when a panel opens. */\n private lastMemoryStateValue: unknown = null\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 /**\n * Record a transported `memory:state` value (the server memory middleware's\n * per-turn recall metrics + store snapshot). Called from the chat client's\n * `onCustomEvent` handler — the designated path for CUSTOM stream events —\n * NOT from `observeChunk`. Re-emits the browser `memory:*` events the devtools\n * store consumes, and caches the value so a panel opened later can replay it\n * (see {@link onReplayState}). Symmetric with the generation bridge's\n * `recordResultChange` / `recordProgressChange`.\n */\n recordMemoryState(rawValue: unknown): void {\n this.lastMemoryStateValue = rawValue\n this.emitMemoryState(rawValue)\n }\n\n /**\n * Re-emit the browser-side `memory:*` events from a transported\n * `memory:state` value. The devtools store consumes these to render the\n * Memory tab (operations timeline + live contents). The recall pair mirrors\n * the server middleware's own emits; the snapshot is included only when the\n * adapter supports introspection.\n */\n private emitMemoryState(rawValue: unknown): void {\n if (!rawValue || typeof rawValue !== 'object') return\n const value = rawValue as MemoryStateEventValue\n const scope = value.scope\n const adapter = value.adapter\n if (!scope || typeof adapter !== 'string') return\n const runContext = this.currentRunId ? { runId: this.currentRunId } : {}\n\n emitAIDevtoolsEvent('memory:retrieve:started', {\n ...this.createEnvelope(\n 'memory:retrieve:started',\n 'client-state',\n runContext,\n ),\n scope,\n adapter,\n query: value.query ?? '',\n })\n if (value.recall) {\n emitAIDevtoolsEvent('memory:retrieve:completed', {\n ...this.createEnvelope(\n 'memory:retrieve:completed',\n 'client-state',\n runContext,\n ),\n scope,\n adapter,\n fragmentCount: value.recall.fragmentCount ?? 0,\n hasTools: Boolean(value.recall.hasTools),\n systemPromptChars: value.recall.systemPromptChars ?? 0,\n durationMs: value.recall.durationMs ?? 0,\n })\n }\n if (value.snapshot) {\n emitAIDevtoolsEvent('memory:snapshot', {\n ...this.createEnvelope('memory:snapshot', 'client-state', runContext),\n scope,\n adapter,\n takenAt: value.snapshot.takenAt,\n data: value.snapshot.data,\n facts: value.snapshot.facts ?? [],\n })\n }\n }\n\n protected override onReplayState(): void {\n if (this.lastMemoryStateValue != null) {\n this.emitMemoryState(this.lastMemoryStateValue)\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"],"mappings":"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"}
1
+ {"version":3,"file":"devtools.js","names":[],"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 {\n AIDevtoolsEventVisibility,\n MemoryScopeLite,\n} 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\n/**\n * Structural mirror of `MemoryStateEventValue` from `@tanstack/ai-memory` — the\n * payload of the `memory:state` CUSTOM chunk. Kept local so `ai-client` doesn't\n * depend on `ai-memory`; the memory middleware is the producer.\n */\ninterface MemoryStateEventValue {\n scope: MemoryScopeLite\n adapter: string\n query?: string\n recall?: {\n fragmentCount?: number\n hasTools?: boolean\n systemPromptChars?: number\n durationMs?: number\n }\n snapshot?: {\n takenAt: string\n data: unknown\n facts?: Array<{\n id: string\n text: string\n source?: string\n createdAt?: string\n }>\n }\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 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 }\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 // oxlint-disable-next-line eslint-js/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 live = getActiveBridgeRegistry().get(this.options.hookId)\n if (live !== this) {\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 this.onReplayState()\n }\n\n /**\n * Extension hook for subclasses to replay any additional cached state on a\n * `devtools:request-state` (i.e. when a panel opens). Called only after the\n * base guards (disposed/superseded/targetHookId) pass. No-op by default.\n */\n protected onReplayState(): void {}\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 // Fixture routing: `hookId` wins when present (latest bridge for that\n // registry key). `threadId` is the fallback for fixtures scoped only to a\n // conversation / generation slot without a hook id.\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 protected createEnvelope(\n eventType:\n | 'hook:registered'\n | 'hook:updated'\n | 'hook:unregistered'\n | 'hook:state-snapshot'\n | 'tools:registered'\n | 'memory:retrieve:started'\n | 'memory:retrieve:completed'\n | 'memory:snapshot'\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 ...(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\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 /** Last transported `memory:state` value, replayed when a panel opens. */\n private lastMemoryStateValue: unknown = null\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 /**\n * Record a transported `memory:state` value (the server memory middleware's\n * per-turn recall metrics + store snapshot). Called from the chat client's\n * `onCustomEvent` handler — the designated path for CUSTOM stream events —\n * NOT from `observeChunk`. Re-emits the browser `memory:*` events the devtools\n * store consumes, and caches the value so a panel opened later can replay it\n * (see {@link onReplayState}). Symmetric with the generation bridge's\n * `recordResultChange` / `recordProgressChange`.\n */\n recordMemoryState(rawValue: unknown): void {\n this.lastMemoryStateValue = rawValue\n this.emitMemoryState(rawValue)\n }\n\n /**\n * Re-emit the browser-side `memory:*` events from a transported\n * `memory:state` value. The devtools store consumes these to render the\n * Memory tab (operations timeline + live contents). The recall pair mirrors\n * the server middleware's own emits; the snapshot is included only when the\n * adapter supports introspection.\n */\n private emitMemoryState(rawValue: unknown): void {\n if (!rawValue || typeof rawValue !== 'object') return\n const value = rawValue as MemoryStateEventValue\n const scope = value.scope\n const adapter = value.adapter\n if (!scope || typeof adapter !== 'string') return\n const runContext = this.currentRunId ? { runId: this.currentRunId } : {}\n\n emitAIDevtoolsEvent('memory:retrieve:started', {\n ...this.createEnvelope(\n 'memory:retrieve:started',\n 'client-state',\n runContext,\n ),\n scope,\n adapter,\n query: value.query ?? '',\n })\n if (value.recall) {\n emitAIDevtoolsEvent('memory:retrieve:completed', {\n ...this.createEnvelope(\n 'memory:retrieve:completed',\n 'client-state',\n runContext,\n ),\n scope,\n adapter,\n fragmentCount: value.recall.fragmentCount ?? 0,\n hasTools: Boolean(value.recall.hasTools),\n systemPromptChars: value.recall.systemPromptChars ?? 0,\n durationMs: value.recall.durationMs ?? 0,\n })\n }\n if (value.snapshot) {\n emitAIDevtoolsEvent('memory:snapshot', {\n ...this.createEnvelope('memory:snapshot', 'client-state', runContext),\n scope,\n adapter,\n takenAt: value.snapshot.takenAt,\n data: value.snapshot.data,\n facts: value.snapshot.facts ?? [],\n })\n }\n }\n\n protected override onReplayState(): void {\n if (this.lastMemoryStateValue != null) {\n this.emitMemoryState(this.lastMemoryStateValue)\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"],"mappings":"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"}
@@ -1,5 +1,4 @@
1
- import { ConnectConnectionAdapter } from './connection-adapters.js';
2
- import { GenerationClientOptions, GenerationClientState, GenerationFetcher, GenerationResumeSnapshot } from './generation-types.js';
1
+ import { GenerationClientOptions, GenerationClientState, GenerationPersistenceOptions, GenerationResumeSnapshot, GenerationTransport } from './generation-types.js';
3
2
  /**
4
3
  * A lightweight, generic client for one-shot generation tasks
5
4
  * (image, speech, transcription, summarize).
@@ -40,10 +39,10 @@ export declare class GenerationClient<TInput extends Record<string, any>, TResul
40
39
  private readonly fetcher;
41
40
  private readonly hydrateGenerationHandler;
42
41
  private readonly joinRunHandler;
43
- private readonly uniqueId;
42
+ private uniqueId;
44
43
  private readonly devtoolsMetadata;
45
44
  private readonly devtoolsBridge;
46
- private readonly threadId;
45
+ private threadId;
47
46
  private readonly persistenceScope;
48
47
  private readonly serverDriven;
49
48
  private body;
@@ -61,13 +60,7 @@ export declare class GenerationClient<TInput extends Record<string, any>, TResul
61
60
  private devtoolsMounted;
62
61
  private disposed;
63
62
  private serverHydrationStarted;
64
- constructor(options: GenerationClientOptions<TInput, TResult, TOutput> & ({
65
- connection: ConnectConnectionAdapter;
66
- fetcher?: never;
67
- } | {
68
- fetcher: GenerationFetcher<TInput, TResult>;
69
- connection?: never;
70
- }));
63
+ constructor(options: Omit<GenerationClientOptions<TInput, TResult, TOutput>, 'persistence' | 'threadId'> & GenerationPersistenceOptions & GenerationTransport<TInput, TResult>);
71
64
  private buildDevtoolsBridgeOptions;
72
65
  mountDevtools(): void;
73
66
  /**
@@ -116,6 +109,7 @@ export declare class GenerationClient<TInput extends Record<string, any>, TResul
116
109
  private setStatus;
117
110
  private setProgress;
118
111
  private createDevtoolsMetadata;
112
+ private ensureThreadId;
119
113
  private generateUniqueId;
120
114
  private createRunContext;
121
115
  private observeResumeSnapshot;
@@ -64,8 +64,8 @@ var GenerationClient = class {
64
64
  disposed = false;
65
65
  serverHydrationStarted = false;
66
66
  constructor(options) {
67
- this.uniqueId = options.threadId ?? options.id ?? this.generateUniqueId("generation");
68
- this.threadId = options.threadId ?? this.uniqueId;
67
+ this.threadId = options.threadId ?? "";
68
+ this.uniqueId = this.threadId;
69
69
  this.persistenceScope = options.threadId;
70
70
  this.connection = options.connection;
71
71
  this.fetcher = options.fetcher;
@@ -91,10 +91,17 @@ var GenerationClient = class {
91
91
  this.devtoolsBridge = (options.devtoolsBridgeFactory ?? createNoOpGenerationDevtoolsBridge)(this.buildDevtoolsBridgeOptions());
92
92
  }
93
93
  buildDevtoolsBridgeOptions() {
94
+ const client = this;
94
95
  return {
95
- hookId: this.uniqueId,
96
- clientId: this.uniqueId,
97
- threadId: this.threadId,
96
+ get hookId() {
97
+ return client.uniqueId;
98
+ },
99
+ get clientId() {
100
+ return client.uniqueId;
101
+ },
102
+ get threadId() {
103
+ return client.threadId;
104
+ },
98
105
  metadata: this.devtoolsMetadata,
99
106
  getCoreState: () => ({
100
107
  input: this.input,
@@ -107,6 +114,7 @@ var GenerationClient = class {
107
114
  };
108
115
  }
109
116
  mountDevtools() {
117
+ this.ensureThreadId();
110
118
  this.disposed = false;
111
119
  this.maybeHydrateFromServer();
112
120
  this.maybeResumeInFlight();
@@ -361,6 +369,11 @@ var GenerationClient = class {
361
369
  ...metadata?.name ? { name: metadata.name } : {}
362
370
  };
363
371
  }
372
+ ensureThreadId() {
373
+ if (!this.threadId) this.threadId = this.generateUniqueId("generation");
374
+ this.uniqueId = this.threadId;
375
+ return this.threadId;
376
+ }
364
377
  generateUniqueId(prefix) {
365
378
  return `${prefix}-${Date.now()}-${Math.random().toString(36).substring(7)}`;
366
379
  }