@tanstack/ai-client 0.29.0 → 0.29.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"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
+ {"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 CompactionMessagePreview,\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 SkillsStateEventValue {\n catalog?: Array<{ name: string; description: string }>\n activated?: Array<string>\n}\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\nfunction readCompactionBoundaryValue(rawValue: unknown): {\n before?: number\n after?: number\n messagesBefore?: number\n messagesAfter?: number\n reusedCheckpoint?: boolean\n maxTokens?: number\n strategyKey?: string\n durationMs?: number\n} {\n if (!rawValue || typeof rawValue !== 'object') return {}\n return {\n ...('before' in rawValue && typeof rawValue.before === 'number'\n ? { before: rawValue.before }\n : {}),\n ...('after' in rawValue && typeof rawValue.after === 'number'\n ? { after: rawValue.after }\n : {}),\n ...('messagesBefore' in rawValue &&\n typeof rawValue.messagesBefore === 'number'\n ? { messagesBefore: rawValue.messagesBefore }\n : {}),\n ...('messagesAfter' in rawValue &&\n typeof rawValue.messagesAfter === 'number'\n ? { messagesAfter: rawValue.messagesAfter }\n : {}),\n ...('reusedCheckpoint' in rawValue &&\n typeof rawValue.reusedCheckpoint === 'boolean'\n ? { reusedCheckpoint: rawValue.reusedCheckpoint }\n : {}),\n ...('maxTokens' in rawValue && typeof rawValue.maxTokens === 'number'\n ? { maxTokens: rawValue.maxTokens }\n : {}),\n ...('strategyKey' in rawValue && typeof rawValue.strategyKey === 'string'\n ? { strategyKey: rawValue.strategyKey }\n : {}),\n ...('durationMs' in rawValue && typeof rawValue.durationMs === 'number'\n ? { durationMs: rawValue.durationMs }\n : {}),\n }\n}\n\nfunction readPreviewList(\n value: unknown,\n): Array<CompactionMessagePreview> | undefined {\n if (!Array.isArray(value)) return undefined\n const previews: Array<CompactionMessagePreview> = []\n for (const item of value) {\n if (!item || typeof item !== 'object') continue\n if (!('role' in item) || !('tokens' in item) || !('text' in item)) continue\n if (\n typeof item.role !== 'string' ||\n typeof item.tokens !== 'number' ||\n typeof item.text !== 'string'\n ) {\n continue\n }\n previews.push({\n role: item.role,\n tokens: item.tokens,\n text: item.text,\n })\n }\n return previews\n}\n\nfunction readCompactionStateValue(rawValue: unknown): {\n before: number\n after: number\n messagesBefore: number\n messagesAfter: number\n reusedCheckpoint: boolean\n maxTokens?: number\n strategyKey?: string\n dropped?: Array<CompactionMessagePreview>\n result?: Array<CompactionMessagePreview>\n} | null {\n if (!rawValue || typeof rawValue !== 'object') return null\n if (\n !('before' in rawValue) ||\n !('after' in rawValue) ||\n !('messagesBefore' in rawValue) ||\n !('messagesAfter' in rawValue)\n ) {\n return null\n }\n if (\n typeof rawValue.before !== 'number' ||\n typeof rawValue.after !== 'number' ||\n typeof rawValue.messagesBefore !== 'number' ||\n typeof rawValue.messagesAfter !== 'number'\n ) {\n return null\n }\n const reusedCheckpoint =\n 'reusedCheckpoint' in rawValue && rawValue.reusedCheckpoint === true\n const maxTokens =\n 'maxTokens' in rawValue && typeof rawValue.maxTokens === 'number'\n ? rawValue.maxTokens\n : undefined\n const strategyKey =\n 'strategyKey' in rawValue && typeof rawValue.strategyKey === 'string'\n ? rawValue.strategyKey\n : undefined\n const dropped =\n 'dropped' in rawValue ? readPreviewList(rawValue.dropped) : undefined\n const result =\n 'result' in rawValue ? readPreviewList(rawValue.result) : undefined\n return {\n before: rawValue.before,\n after: rawValue.after,\n messagesBefore: rawValue.messagesBefore,\n messagesAfter: rawValue.messagesAfter,\n reusedCheckpoint,\n ...(maxTokens !== undefined ? { maxTokens } : {}),\n ...(strategyKey ? { strategyKey } : {}),\n ...(dropped ? { dropped } : {}),\n ...(result ? { result } : {}),\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\n/**\n * `{...options}` turns `get hookId()` into a data property. Chat/generation\n * clients mint `threadId` after construct (`ensureThreadId` on mount), so a\n * spread would freeze `hookId: ''` and DevTools could never select the hook.\n */\nfunction withLiveClientIdentity<TSnapshot extends object>(\n identity: Pick<\n AIDevtoolsBridgeOptions<TSnapshot>,\n | 'hookId'\n | 'clientId'\n | 'threadId'\n | 'metadata'\n | 'getTools'\n | 'applyToolFixture'\n >,\n rest: Pick<AIDevtoolsBridgeOptions<TSnapshot>, 'getSnapshot'> &\n Partial<\n Pick<AIDevtoolsBridgeOptions<TSnapshot>, 'getTools' | 'applyToolFixture'>\n >,\n): AIDevtoolsBridgeOptions<TSnapshot> {\n return {\n get hookId() {\n return identity.hookId\n },\n get clientId() {\n return identity.clientId\n },\n get threadId() {\n return identity.threadId\n },\n metadata: identity.metadata,\n getSnapshot: rest.getSnapshot,\n ...(rest.getTools || identity.getTools\n ? { getTools: rest.getTools ?? identity.getTools }\n : {}),\n ...(rest.applyToolFixture || identity.applyToolFixture\n ? {\n applyToolFixture: rest.applyToolFixture ?? identity.applyToolFixture,\n }\n : {}),\n }\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 | 'compaction:started'\n | 'compaction:state'\n | 'compaction:ended'\n | 'skills: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 /** Transported compaction CUSTOM events, replayed when a panel opens. */\n private readonly lastCompactionEvents: Array<{\n eventType: string\n value: unknown\n }> = []\n /** Last transported `skills:state` value, replayed when a panel opens. */\n private lastSkillsStateValue: unknown = null\n\n constructor(options: ChatDevtoolsBridgeOptions) {\n super(\n withLiveClientIdentity(options, {\n getSnapshot: options.getSnapshot,\n // Thunk defers `this.applyFixture` lookup until after `super` returns.\n applyToolFixture: (fixture) => this.applyFixture(fixture),\n }),\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(\n () => options.clientId,\n this,\n )\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 recordSkillsState(rawValue: unknown): void {\n this.lastSkillsStateValue = rawValue\n this.emitSkillsState(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 /**\n * Record a transported compaction CUSTOM event. Called from the chat\n * client's `onCustomEvent` handler so server-side compaction reaches the\n * browser DevTools panel.\n */\n recordCompactionEvent(eventType: string, rawValue: unknown): void {\n this.lastCompactionEvents.push({ eventType, value: rawValue })\n if (this.lastCompactionEvents.length > 60) {\n this.lastCompactionEvents.splice(0, this.lastCompactionEvents.length - 60)\n }\n this.emitCompactionEvent(eventType, rawValue)\n }\n\n recordCompactionState(rawValue: unknown): void {\n this.recordCompactionEvent('compaction:state', rawValue)\n }\n\n private emitCompactionEvent(eventType: string, rawValue: unknown): void {\n const runContext = this.currentRunId ? { runId: this.currentRunId } : {}\n if (eventType === 'compaction:started') {\n const value = readCompactionBoundaryValue(rawValue)\n emitAIDevtoolsEvent('compaction:started', {\n ...this.createEnvelope(\n 'compaction:started',\n 'client-state',\n runContext,\n ),\n ...value,\n })\n return\n }\n if (eventType === 'compaction:ended') {\n const value = readCompactionBoundaryValue(rawValue)\n emitAIDevtoolsEvent('compaction:ended', {\n ...this.createEnvelope('compaction:ended', 'client-state', runContext),\n ...value,\n })\n return\n }\n if (eventType === 'compaction:state') {\n const value = readCompactionStateValue(rawValue)\n if (!value) return\n emitAIDevtoolsEvent('compaction:state', {\n ...this.createEnvelope('compaction:state', 'client-state', runContext),\n ...value,\n })\n }\n }\n\n private emitSkillsState(rawValue: unknown): void {\n if (!rawValue || typeof rawValue !== 'object') return\n const value = rawValue as SkillsStateEventValue\n const catalog = Array.isArray(value.catalog) ? value.catalog : []\n const activated = Array.isArray(value.activated) ? value.activated : []\n const runContext = this.currentRunId ? { runId: this.currentRunId } : {}\n emitAIDevtoolsEvent('skills:snapshot', {\n ...this.createEnvelope('skills:snapshot', 'client-state', runContext),\n catalog,\n activated,\n })\n }\n\n protected override onReplayState(): void {\n if (this.lastMemoryStateValue != null) {\n this.emitMemoryState(this.lastMemoryStateValue)\n }\n for (const event of this.lastCompactionEvents) {\n this.emitCompactionEvent(event.eventType, event.value)\n }\n if (this.lastSkillsStateValue != null) {\n this.emitSkillsState(this.lastSkillsStateValue)\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 withLiveClientIdentity(options, {\n getSnapshot: () => this.buildSnapshot(),\n }),\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 private readonly getClientId: () => string,\n private readonly helper: ChatDevtoolsBridge,\n ) {\n super(getClientId())\n }\n\n protected override emitEvent(\n eventName: string,\n data?: Record<string, any>,\n ): void {\n this.clientId = this.getClientId()\n super.emitEvent(eventName, data)\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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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/ai-client",
3
- "version": "0.29.0",
3
+ "version": "0.29.2",
4
4
  "description": "Framework-agnostic headless client for TanStack AI chat, realtime sessions, streaming transports, and media generations.",
5
5
  "author": "Tanner Linsley",
6
6
  "license": "MIT",
@@ -53,8 +53,8 @@
53
53
  "src"
54
54
  ],
55
55
  "dependencies": {
56
- "@tanstack/ai": "^0.50.0",
57
- "@tanstack/ai-event-client": "^0.11.0",
56
+ "@tanstack/ai": "^0.52.0",
57
+ "@tanstack/ai-event-client": "^0.11.2",
58
58
  "@tanstack/ai-utils": "^0.4.0"
59
59
  },
60
60
  "devDependencies": {
@@ -164,6 +164,20 @@ function resolveTransport(transport: {
164
164
  throw new Error('ChatClient: either `connection` or `fetcher` is required.')
165
165
  }
166
166
 
167
+ function connectionDrainsOnSend(connection: ConnectionAdapter): boolean {
168
+ return 'connect' in connection
169
+ }
170
+
171
+ function isIntermediateToolTurn(chunk: StreamChunk): boolean {
172
+ if (chunk.type !== 'RUN_FINISHED') return false
173
+ if (chunk.outcome?.type === 'interrupt') return false
174
+ const extra = chunk as StreamChunk & { finishReason?: unknown }
175
+ if (extra.finishReason !== undefined) {
176
+ return extra.finishReason === 'tool_calls'
177
+ }
178
+ return tanstackMetadata(chunk)?.finishReason === 'tool_calls'
179
+ }
180
+
167
181
  export interface NormalizedQueueConfig {
168
182
  whenBusy: WhenBusy
169
183
  drain: 'fifo' | 'batch'
@@ -416,6 +430,12 @@ export class ChatClient<
416
430
  private continuationPending = false
417
431
  private subscriptionAbortController: AbortController | null = null
418
432
  private processingResolve: (() => void) | null = null
433
+ /**
434
+ * `connect()` adapters push the full HTTP body into the subscribe queue, then
435
+ * wait until that queue is idle. After `send()` returns, every chunk from this
436
+ * request has been processed. Subscribe/send sockets do not drain that way.
437
+ */
438
+ private connectionDrainsOnSend = false
419
439
  private errorReportedGeneration: number | null = null
420
440
  private streamGeneration = 0
421
441
  private continuationGeneration = 0
@@ -518,7 +538,9 @@ export class ChatClient<
518
538
  this.byokProvider = options.byokProvider
519
539
  this.context = options.context
520
540
  this.queueConfig = normalizeQueueOption(options.queue)
521
- this.connection = normalizeConnectionAdapter(resolveTransport(options))
541
+ const transport = resolveTransport(options)
542
+ this.connectionDrainsOnSend = connectionDrainsOnSend(transport)
543
+ this.connection = normalizeConnectionAdapter(transport)
522
544
 
523
545
  // Build client tools map
524
546
  this.clientToolsRef = { current: new Map() }
@@ -829,6 +851,16 @@ export class ChatClient<
829
851
  if (eventType === 'memory:state') {
830
852
  this.devtoolsBridge.recordMemoryState(data)
831
853
  }
854
+ if (
855
+ eventType === 'compaction:started' ||
856
+ eventType === 'compaction:state' ||
857
+ eventType === 'compaction:ended'
858
+ ) {
859
+ this.devtoolsBridge.recordCompactionEvent(eventType, data)
860
+ }
861
+ if (eventType === 'skills:state') {
862
+ this.devtoolsBridge.recordSkillsState(data)
863
+ }
832
864
  this.callbacksRef.current.onCustomEvent(eventType, data, context)
833
865
  },
834
866
  },
@@ -1140,7 +1172,9 @@ export class ChatClient<
1140
1172
  this.clearedStreamTracker.onSessionRunError()
1141
1173
  }
1142
1174
  this.setSessionGenerating(this.activeRunIds.size > 0)
1143
- if (options?.resolveProcessing !== false) {
1175
+ const skipProcessingResolve =
1176
+ chunk.type === 'RUN_FINISHED' && isIntermediateToolTurn(chunk)
1177
+ if (options?.resolveProcessing !== false && !skipProcessingResolve) {
1144
1178
  this.resolveProcessing()
1145
1179
  }
1146
1180
  }
@@ -2344,6 +2378,14 @@ export class ChatClient<
2344
2378
  return false
2345
2379
  }
2346
2380
 
2381
+ // connect() send() already waited until the subscribe queue was idle.
2382
+ // Kick the processing wait so a stream that ends on tool_calls (no
2383
+ // interrupt / stop) cannot hang. Subscribe/send sockets still wait for
2384
+ // a request-ending terminal below.
2385
+ if (this.connectionDrainsOnSend) {
2386
+ this.resolveProcessing()
2387
+ }
2388
+
2347
2389
  // Wait for subscription loop to finish processing all chunks
2348
2390
  await processingComplete
2349
2391
 
@@ -3045,12 +3087,12 @@ export class ChatClient<
3045
3087
  this.resetSessionGenerating()
3046
3088
  this.setIsSubscribed(false)
3047
3089
  this.setConnectionStatus('disconnected')
3048
- this.connection = normalizeConnectionAdapter(
3049
- resolveTransport({
3050
- connection: options.connection,
3051
- fetcher: options.fetcher,
3052
- }),
3053
- )
3090
+ const transport = resolveTransport({
3091
+ connection: options.connection,
3092
+ fetcher: options.fetcher,
3093
+ })
3094
+ this.connectionDrainsOnSend = connectionDrainsOnSend(transport)
3095
+ this.connection = normalizeConnectionAdapter(transport)
3054
3096
 
3055
3097
  if (wasSubscribed) {
3056
3098
  this.subscribe()
@@ -1055,6 +1055,28 @@ export function normalizeConnectionAdapter(
1055
1055
  }
1056
1056
  }
1057
1057
 
1058
+ async function waitUntilSubscriberIdle(
1059
+ abortSignal?: AbortSignal,
1060
+ ): Promise<void> {
1061
+ // Idle means the subscriber is waiting for the next chunk, so the
1062
+ // previous chunk has left processIncomingChunk. Empty waiters with an
1063
+ // empty buffer is in-flight delivery, not idle.
1064
+ const idle = () =>
1065
+ activeBuffer.length === 0 &&
1066
+ (activeWaiters.length > 0 || abortSignal?.aborted)
1067
+ for (let i = 0; i < 16 && !abortSignal?.aborted; i++) {
1068
+ if (idle()) return
1069
+ await Promise.resolve()
1070
+ }
1071
+ let macrotaskWaits = 0
1072
+ while (!abortSignal?.aborted) {
1073
+ if (idle()) return
1074
+ await new Promise<void>((resolve) => setTimeout(resolve, 0))
1075
+ macrotaskWaits++
1076
+ if (activeWaiters.length === 0 && macrotaskWaits >= 32) return
1077
+ }
1078
+ }
1079
+
1058
1080
  return {
1059
1081
  subscribe(abortSignal?: AbortSignal): AsyncIterable<StreamChunk> {
1060
1082
  // Transfer ownership to the latest subscriber so only one active
@@ -1162,6 +1184,7 @@ export function normalizeConnectionAdapter(
1162
1184
  }
1163
1185
  throw err
1164
1186
  }
1187
+ await waitUntilSubscriberIdle(abortSignal)
1165
1188
  },
1166
1189
  // Expose joinRun only when the underlying connection is resumable. Require
1167
1190
  // a real function — `'joinRun' in connection` is true for
@@ -87,6 +87,9 @@ export class NoOpChatDevtoolsBridge {
87
87
  }
88
88
  observeChunk(_chunk: StreamChunk): void {}
89
89
  recordMemoryState(_value: unknown): void {}
90
+ recordCompactionEvent(_eventType: string, _value: unknown): void {}
91
+ recordCompactionState(_value: unknown): void {}
92
+ recordSkillsState(_value: unknown): void {}
90
93
  beginRun(_runId: string, _threadId: string): void {}
91
94
  getCurrentRunEventContext(): ChatClientRunEventContext | undefined {
92
95
  return undefined