@tanstack/ai-client 0.21.0 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/chat-client.d.ts +96 -2
- package/dist/esm/chat-client.js +312 -13
- package/dist/esm/chat-client.js.map +1 -1
- package/dist/esm/devtools.d.ts +2 -1
- package/dist/esm/devtools.js.map +1 -1
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/types.d.ts +92 -0
- package/dist/esm/types.js.map +1 -1
- package/package.json +1 -1
- package/src/chat-client.ts +407 -17
- package/src/devtools.ts +2 -0
- package/src/index.ts +7 -0
- package/src/types.ts +99 -0
package/dist/esm/devtools.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"devtools.js","sources":["../../src/devtools.ts"],"sourcesContent":["import {\n aiEventClient,\n createAIDevtoolsEventEnvelope,\n emitAIDevtoolsEvent,\n} from '@tanstack/ai-event-client'\nimport { convertSchemaToJsonSchema } from '@tanstack/ai/client'\nimport { DefaultChatClientEventEmitter } from './events'\nimport type { AnyClientTool, StreamChunk } from '@tanstack/ai/client'\nimport type { AIDevtoolsEventVisibility } from '@tanstack/ai-event-client'\nimport type {\n ChatClientEventContext,\n ChatClientEventEmitter,\n ChatClientRunEventContext,\n} from './events'\nimport type {\n ChatClientState,\n ConnectionStatus,\n MessagePart,\n ToolCallPart,\n UIMessage,\n} from './types'\n\nexport interface AIDevtoolsDisplayOptions {\n name?: string\n}\n\nexport interface AIDevtoolsClientMetadata extends AIDevtoolsDisplayOptions {\n framework?: string\n hookName: string\n outputKind?: 'chat' | 'text' | 'structured' | 'image' | 'video' | 'audio'\n}\n\nexport interface AIDevtoolsGenerationProgress {\n value: number\n message?: string\n}\n\nexport interface AIDevtoolsGenerationMediaItem {\n src: string\n sourceType: 'url' | 'base64'\n mimeType?: string\n format?: string\n duration?: number\n}\n\nexport interface AIDevtoolsGenerationVideoJob {\n jobId: string\n status?: string\n progress?: number\n error?: string\n}\n\nexport type AIDevtoolsGenerationPreview =\n | {\n kind: 'image'\n items: Array<AIDevtoolsGenerationMediaItem>\n }\n | {\n kind: 'audio'\n items: Array<AIDevtoolsGenerationMediaItem>\n }\n | {\n kind: 'video'\n items: Array<AIDevtoolsGenerationMediaItem>\n job?: AIDevtoolsGenerationVideoJob\n }\n | {\n kind: 'text'\n text: string\n }\n | {\n kind: 'structured'\n value: unknown\n }\n | {\n kind: 'empty'\n }\n\nexport type AIDevtoolsGenerationRunStatus =\n | 'idle'\n | 'generating'\n | 'success'\n | 'error'\n | 'cancelled'\n\nexport interface AIDevtoolsGenerationRunSnapshot<TOutput = unknown> {\n id: string\n input: unknown\n result: TOutput | null\n preview: AIDevtoolsGenerationPreview\n progress: AIDevtoolsGenerationProgress | null\n status: AIDevtoolsGenerationRunStatus\n isLoading: boolean\n startedAt: number\n updatedAt: number\n completedAt?: number\n error?: string\n jobId?: string | null\n videoStatus?: unknown\n}\n\nexport interface AIDevtoolsGenerationPreviewInput {\n outputKind?: AIDevtoolsClientMetadata['outputKind']\n result: unknown\n videoStatus?: unknown\n}\n\nexport interface AIDevtoolsChatSnapshot {\n [key: string]: unknown\n messages: Array<UIMessage>\n status: ChatClientState\n isLoading: boolean\n isSubscribed: boolean\n connectionStatus: ConnectionStatus\n sessionGenerating: boolean\n activeRunIds: Array<string>\n error?: string\n}\n\nexport function createAIDevtoolsGenerationPreview(\n input: AIDevtoolsGenerationPreviewInput,\n): AIDevtoolsGenerationPreview {\n if (input.outputKind === 'image') {\n return imagePreviewFromResult(input.result)\n }\n\n if (input.outputKind === 'audio') {\n return audioPreviewFromResult(input.result)\n }\n\n if (input.outputKind === 'video') {\n return videoPreviewFromResult(input.result, input.videoStatus)\n }\n\n if (input.outputKind === 'text') {\n return textPreviewFromResult(input.result)\n }\n\n if (input.result === null || input.result === undefined) {\n return { kind: 'empty' }\n }\n\n return {\n kind: 'structured',\n value: input.result,\n }\n}\n\ntype UnknownRecord = { [key: string]: unknown }\n\nfunction imagePreviewFromResult(result: unknown): AIDevtoolsGenerationPreview {\n const record = asRecord(result)\n const images = Array.isArray(record?.images) ? record.images : []\n const items = images\n .map((image) => mediaItemFromSource(image, 'image/png'))\n .filter(isGenerationMediaItem)\n\n if (items.length === 0 && result !== null && result !== undefined) {\n const directItem = mediaItemFromSource(result, 'image/png')\n if (directItem) {\n items.push(directItem)\n }\n }\n\n return { kind: 'image', items }\n}\n\nfunction audioPreviewFromResult(result: unknown): AIDevtoolsGenerationPreview {\n const record = asRecord(result)\n const audio = record?.audio\n const resultContentType = stringField(record, 'contentType')\n const format = stringField(record, 'format')\n const mimeType = resultContentType ?? mimeTypeFromAudioFormat(format)\n\n const items: Array<AIDevtoolsGenerationMediaItem> = []\n const directItem =\n typeof audio === 'string'\n ? base64MediaItem(audio, mimeType, {\n format,\n duration: numberField(record, 'duration'),\n })\n : mediaItemFromSource(audio, mimeType, {\n format,\n })\n\n if (directItem) {\n items.push(directItem)\n }\n\n return { kind: 'audio', items }\n}\n\nfunction videoPreviewFromResult(\n result: unknown,\n videoStatus: unknown,\n): AIDevtoolsGenerationPreview {\n const resultRecord = asRecord(result)\n const statusRecord = asRecord(videoStatus)\n const item =\n mediaItemFromSource(result, 'video/mp4') ??\n mediaItemFromSource(videoStatus, 'video/mp4')\n const items = item ? [item] : []\n const job = videoJobFromStatus(statusRecord ?? resultRecord)\n\n return {\n kind: 'video',\n items,\n ...(job ? { job } : {}),\n }\n}\n\nfunction textPreviewFromResult(result: unknown): AIDevtoolsGenerationPreview {\n const record = asRecord(result)\n const text =\n stringField(record, 'text') ??\n stringField(record, 'summary') ??\n stringField(record, 'content') ??\n (typeof result === 'string' ? result : undefined)\n\n if (text !== undefined) {\n return { kind: 'text', text }\n }\n\n if (result === null || result === undefined) {\n return { kind: 'empty' }\n }\n\n return {\n kind: 'structured',\n value: result,\n }\n}\n\nfunction videoJobFromStatus(\n record: UnknownRecord | undefined,\n): AIDevtoolsGenerationVideoJob | undefined {\n const jobId = stringField(record, 'jobId')\n if (!jobId) return undefined\n\n return {\n jobId,\n ...(stringField(record, 'status')\n ? { status: stringField(record, 'status') }\n : {}),\n ...(numberField(record, 'progress') !== undefined\n ? { progress: numberField(record, 'progress') }\n : {}),\n ...(stringField(record, 'error')\n ? { error: stringField(record, 'error') }\n : {}),\n }\n}\n\nfunction mediaItemFromSource(\n value: unknown,\n defaultMimeType: string,\n extras: {\n format?: string\n duration?: number\n } = {},\n): AIDevtoolsGenerationMediaItem | undefined {\n const record = asRecord(value)\n if (!record) return undefined\n\n const explicitContentType =\n stringField(record, 'contentType') ?? stringField(record, 'mimeType')\n const duration = numberField(record, 'duration') ?? extras.duration\n const format = stringField(record, 'format') ?? extras.format\n const url = stringField(record, 'url')\n if (url) {\n return {\n src: url,\n sourceType: 'url',\n ...(explicitContentType ? { mimeType: explicitContentType } : {}),\n ...(format ? { format } : {}),\n ...(duration !== undefined ? { duration } : {}),\n }\n }\n\n const b64Json = stringField(record, 'b64Json')\n if (!b64Json) return undefined\n\n return base64MediaItem(b64Json, explicitContentType ?? defaultMimeType, {\n format,\n duration,\n })\n}\n\nfunction base64MediaItem(\n value: string,\n mimeType: string | undefined,\n extras: {\n format?: string\n duration?: number\n } = {},\n): AIDevtoolsGenerationMediaItem {\n const src = value.startsWith('data:')\n ? value\n : `data:${mimeType ?? 'application/octet-stream'};base64,${value}`\n\n return {\n src,\n sourceType: 'base64',\n ...(mimeType ? { mimeType } : {}),\n ...(extras.format ? { format: extras.format } : {}),\n ...(extras.duration !== undefined ? { duration: extras.duration } : {}),\n }\n}\n\nfunction mimeTypeFromAudioFormat(format: string | undefined): string {\n if (!format) return 'audio/mpeg'\n if (format === 'mp3') return 'audio/mpeg'\n return `audio/${format}`\n}\n\nfunction asRecord(value: unknown): UnknownRecord | undefined {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n return undefined\n }\n return value as UnknownRecord\n}\n\nfunction stringField(\n record: UnknownRecord | undefined,\n field: string,\n): string | undefined {\n const value = record?.[field]\n return typeof value === 'string' && value.length > 0 ? value : undefined\n}\n\nfunction numberField(\n record: UnknownRecord | undefined,\n field: string,\n): number | undefined {\n const value = record?.[field]\n return typeof value === 'number' ? value : undefined\n}\n\nfunction isGenerationMediaItem(\n value: AIDevtoolsGenerationMediaItem | undefined,\n): value is AIDevtoolsGenerationMediaItem {\n return Boolean(value)\n}\n\nexport interface AIDevtoolsToolFixture {\n fixtureId?: string\n hookId?: string\n threadId?: string\n runId?: string\n toolName: string\n input: unknown\n output: unknown\n execute?: boolean\n message?: {\n id: string\n role: UIMessage['role']\n parts: Array<unknown>\n createdAt?: number | string\n }\n toolCallId?: string\n messageId?: string\n errorText?: string\n}\n\ntype AIDevtoolsRunEventType =\n | 'run:created'\n | 'run:started'\n | 'run:updated'\n | 'run:completed'\n | 'run:errored'\n | 'run:cancelled'\n\ntype AIDevtoolsRunStatus =\n | 'created'\n | 'started'\n | 'updated'\n | 'completed'\n | 'errored'\n | 'cancelled'\n\nexport interface AIDevtoolsBridgeOptions<TSnapshot extends object> {\n hookId: string\n threadId?: string\n clientId: string\n metadata: AIDevtoolsClientMetadata\n getSnapshot: () => TSnapshot\n getTools?: () => Iterable<AnyClientTool>\n applyToolFixture?: (fixture: AIDevtoolsToolFixture) => void | Promise<void>\n}\n\ntype Unsubscribe = () => void\n\ninterface AIDevtoolsEvent<TPayload> {\n payload: TPayload\n}\n\ninterface ActiveDevtoolsBridge {\n deactivate: () => void\n dispose: () => void\n supersede?: () => void\n}\n\nconst activeBridgeRegistryKey = Symbol.for(\n 'tanstack.ai.devtools.activeBridgeByHookId',\n)\n\nfunction getActiveBridgeRegistry(): Map<string, ActiveDevtoolsBridge> {\n const global = globalThis as typeof globalThis & {\n [activeBridgeRegistryKey]?: Map<string, ActiveDevtoolsBridge>\n }\n const existing = global[activeBridgeRegistryKey]\n if (existing) return existing\n\n const registry = new Map<string, ActiveDevtoolsBridge>()\n global[activeBridgeRegistryKey] = registry\n return registry\n}\n\nexport class ClientDevtoolsBridge<TSnapshot extends object> {\n protected readonly options: AIDevtoolsBridgeOptions<TSnapshot>\n private readonly bridgeId: string\n private readonly unsubscribers: Array<Unsubscribe> = []\n private disposed = false\n private superseded = false\n private registered = false\n\n constructor(options: AIDevtoolsBridgeOptions<TSnapshot>) {\n this.options = options\n this.bridgeId = createBridgeId(options.hookId)\n }\n\n emitRegistered(): void {\n if (!this.prepareForMountEmit()) {\n return\n }\n this.registered = true\n emitAIDevtoolsEvent('hook:registered', {\n ...this.createEnvelope('hook:registered'),\n ...this.createMetadataPayload(),\n lifecycle: 'mounted',\n })\n }\n\n emitUpdated(): void {\n if (!this.prepareForEmit()) {\n return\n }\n emitAIDevtoolsEvent('hook:updated', {\n ...this.createEnvelope('hook:updated'),\n ...this.createMetadataPayload(),\n lifecycle: 'active',\n })\n }\n\n emitSnapshot(): void {\n if (!this.prepareForEmit()) {\n return\n }\n emitAIDevtoolsEvent('hook:state-snapshot', {\n ...this.createEnvelope('hook:state-snapshot'),\n ...this.createMetadataPayload(),\n // Wire envelope uses Record<string, unknown>; widen the typed snapshot\n // here so the typed-snapshot constraint above can stay narrow.\n // eslint-disable-next-line no-restricted-syntax -- TSnapshot extends object is structurally compatible but TS can't see the missing index signature\n state: this.options.getSnapshot() as unknown as Record<string, unknown>,\n })\n }\n\n emitToolsRegistered(): void {\n if (!this.prepareForEmit()) {\n return\n }\n const tools = this.options.getTools\n ? Array.from(this.options.getTools()).map((tool) => ({\n name: tool.name,\n description: tool.description,\n inputSchema: tool.inputSchema\n ? convertSchemaToJsonSchema(tool.inputSchema)\n : { type: 'object' },\n outputSchema: tool.outputSchema\n ? convertSchemaToJsonSchema(tool.outputSchema)\n : undefined,\n needsApproval: tool.needsApproval,\n metadata: tool.metadata,\n }))\n : []\n\n emitAIDevtoolsEvent('tools:registered', {\n ...this.createEnvelope('tools:registered'),\n ...this.createMetadataPayload(),\n tools,\n })\n }\n\n emitRunLifecycle(\n eventType: AIDevtoolsRunEventType,\n runId: string,\n status: AIDevtoolsRunStatus,\n options: { error?: string } = {},\n ): void {\n if (!this.prepareForEmit()) {\n return\n }\n emitAIDevtoolsEvent(eventType, {\n ...this.createEnvelope(eventType, 'client-state', { runId }),\n runId,\n status,\n ...(options.error ? { error: options.error } : {}),\n })\n }\n\n deactivate(): void {\n const activeBridgeByHookId = getActiveBridgeRegistry()\n if (activeBridgeByHookId.get(this.options.hookId) === this) {\n activeBridgeByHookId.delete(this.options.hookId)\n }\n\n for (const unsubscribe of this.unsubscribers.splice(0)) {\n unsubscribe()\n }\n }\n\n supersede(): void {\n if (this.disposed) {\n return\n }\n\n this.superseded = true\n this.disposed = true\n this.deactivate()\n }\n\n dispose(): void {\n if (this.disposed) {\n return\n }\n\n this.disposed = true\n if (!this.registered) {\n this.deactivate()\n return\n }\n\n const payload = {\n ...this.createEnvelope('hook:unregistered'),\n ...this.createMetadataPayload(),\n reason: 'disposed',\n } as const\n\n emitAIDevtoolsEvent('hook:unregistered', payload)\n\n this.deactivate()\n }\n\n private prepareForEmit(): boolean {\n if (this.disposed || this.superseded) {\n return false\n }\n this.activate()\n return true\n }\n\n private prepareForMountEmit(): boolean {\n if (this.superseded) {\n return false\n }\n\n if (this.disposed) {\n this.disposed = false\n this.registered = false\n }\n\n this.activate()\n return true\n }\n\n private activate(): void {\n if (this.disposed) {\n return\n }\n\n const activeBridgeByHookId = getActiveBridgeRegistry()\n const activeBridge = activeBridgeByHookId.get(this.options.hookId)\n if (activeBridge && activeBridge !== this) {\n if (typeof activeBridge.supersede === 'function') {\n activeBridge.supersede()\n } else {\n activeBridge.deactivate()\n }\n }\n activeBridgeByHookId.set(this.options.hookId, this)\n\n if (this.unsubscribers.length > 0) {\n return\n }\n\n this.unsubscribers.push(\n aiEventClient.on('devtools:request-state', (event) => {\n this.handleRequestState(event)\n }),\n )\n\n if (this.options.applyToolFixture) {\n this.unsubscribers.push(\n aiEventClient.on('devtools:tool-fixture:apply', (event) => {\n void this.handleToolFixtureApply(event)\n }),\n )\n }\n }\n\n private handleRequestState(\n event: AIDevtoolsEvent<{ targetHookId?: string }>,\n ): void {\n if (this.disposed || this.superseded) {\n return\n }\n\n const targetHookId = event.payload.targetHookId\n if (targetHookId && targetHookId !== this.options.hookId) {\n return\n }\n\n this.emitRegistered()\n this.emitToolsRegistered()\n this.emitSnapshot()\n }\n\n private async handleToolFixtureApply(\n event: AIDevtoolsEvent<AIDevtoolsToolFixture>,\n ): Promise<void> {\n const fixture = event.payload\n if (!this.matchesFixtureTarget(fixture)) {\n return\n }\n\n await this.options.applyToolFixture?.(fixture)\n }\n\n private matchesFixtureTarget(fixture: AIDevtoolsToolFixture): boolean {\n if (!fixture.hookId && !fixture.threadId) {\n return false\n }\n\n if (fixture.hookId) {\n return fixture.hookId === this.options.hookId\n }\n\n if (\n fixture.threadId &&\n (!this.options.threadId || fixture.threadId !== this.options.threadId)\n ) {\n return false\n }\n return true\n }\n\n private createEnvelope(\n eventType:\n | 'hook:registered'\n | 'hook:updated'\n | 'hook:unregistered'\n | 'hook:state-snapshot'\n | 'tools:registered'\n | AIDevtoolsRunEventType,\n visibility: AIDevtoolsEventVisibility = 'client-state',\n context: { runId?: string } = {},\n ) {\n return createAIDevtoolsEventEnvelope({\n eventType,\n source: 'client',\n visibility,\n clientId: this.options.clientId,\n hookId: this.options.hookId,\n correlationId: this.bridgeId,\n ...(this.options.threadId ? { threadId: this.options.threadId } : {}),\n ...(context.runId ? { runId: context.runId } : {}),\n timestamp: Date.now(),\n })\n }\n\n private createMetadataPayload() {\n return {\n hookId: this.options.hookId,\n hookName: this.options.metadata.hookName,\n ...(this.options.metadata.name\n ? { displayName: this.options.metadata.name }\n : {}),\n ...(this.options.metadata.outputKind\n ? { outputKind: this.options.metadata.outputKind }\n : {}),\n ...(this.options.metadata.framework\n ? { framework: this.options.metadata.framework }\n : {}),\n }\n }\n}\n\nlet bridgeIdSequence = 0\n\nfunction createBridgeId(hookId: string): string {\n const cryptoLike = (\n globalThis as {\n crypto?: {\n randomUUID?: () => string\n }\n }\n ).crypto\n\n if (cryptoLike?.randomUUID) {\n return `bridge:${hookId}:${cryptoLike.randomUUID()}`\n }\n\n bridgeIdSequence += 1\n return `bridge:${hookId}:${bridgeIdSequence}`\n}\n\n// Owns the chat-client devtools surface so the chat client itself stays a\n// pure transport. Fixture replay, per-run / per-stream event context, and\n// snapshot emission all live here; a no-op bridge can drop in for prod.\n\nexport interface ChatDevtoolsBridgeOptions extends AIDevtoolsBridgeOptions<AIDevtoolsChatSnapshot> {\n getMessages: () => Array<UIMessage>\n setMessages: (messages: Array<UIMessage>) => void\n addToolResult: (\n toolCallId: string,\n output: unknown,\n errorText?: string,\n ) => void\n generateId: (prefix: string) => string\n}\n\nexport class ChatDevtoolsBridge extends ClientDevtoolsBridge<AIDevtoolsChatSnapshot> {\n readonly events: ChatClientEventEmitter\n private readonly chatOptions: ChatDevtoolsBridgeOptions\n private currentRunId: string | null = null\n private currentRunThreadId: string | null = null\n private currentStreamId: string | null = null\n private lastStreamId: string | null = null\n private lastRunEventContext: ChatClientRunEventContext | undefined\n\n constructor(options: ChatDevtoolsBridgeOptions) {\n super({\n ...options,\n // Thunk defers `this.applyFixture` lookup until after `super` returns.\n applyToolFixture: (fixture) => this.applyFixture(fixture),\n })\n this.chatOptions = options\n // Auto-attaches run/thread context and auto-emits a snapshot after each\n // event so callers can keep using `this.events.X(...)` with no context arg.\n this.events = new ChatDevtoolsAwareEventEmitter(options.clientId, this)\n }\n\n // --- Stream / run context API -------------------------------------------\n\n setCurrentStreamId(streamId: string | null): void {\n this.currentStreamId = streamId\n if (streamId) {\n this.lastStreamId = streamId\n }\n }\n\n /**\n * Called by the auto-attaching emitter every time it sees a non-empty\n * streamId pass through. Lets devtools track the latest stream id\n * without the chat client wiring it up explicitly.\n */\n recordStreamId(streamId: string): void {\n if (streamId) this.lastStreamId = streamId\n }\n\n mountWithTools(initialMessageCount: number): void {\n this.events.clientCreated(initialMessageCount)\n this.emitRegistered()\n this.emitToolsRegistered()\n this.emitSnapshot()\n }\n\n notifyToolsChanged(): void {\n this.emitToolsRegistered()\n this.emitSnapshot()\n }\n\n getCurrentStreamId(): string | null {\n return this.currentStreamId\n }\n\n getLastStreamId(): string | null {\n return this.lastStreamId\n }\n\n resolveStreamId(): string {\n return (\n this.currentStreamId ??\n this.lastStreamId ??\n this.chatOptions.generateId('stream')\n )\n }\n\n // Called when the chat client has just generated a runId for outbound emits;\n // the matching RUN_STARTED chunk from the adapter lands later and\n // observeChunk keeps the same context.\n beginRun(runId: string, threadId: string): void {\n this.currentRunId = runId\n this.currentRunThreadId = threadId\n this.lastRunEventContext = { runId, threadId }\n }\n\n observeChunk(chunk: StreamChunk): void {\n if (chunk.type === 'RUN_STARTED') {\n this.beginRun(chunk.runId, chunk.threadId)\n return\n }\n\n if (chunk.type === 'RUN_FINISHED' || chunk.type === 'RUN_ERROR') {\n const runId =\n chunk.type === 'RUN_FINISHED'\n ? chunk.runId\n : (chunk as { runId?: string }).runId\n if (!runId || runId === this.currentRunId) {\n const context = this.getCurrentRunEventContext()\n if (context) {\n this.lastRunEventContext = context\n }\n this.currentRunId = null\n this.currentRunThreadId = null\n }\n }\n }\n\n getCurrentRunEventContext(): ChatClientRunEventContext | undefined {\n if (!this.currentRunId) return undefined\n return {\n threadId: this.currentRunThreadId ?? this.chatOptions.threadId ?? '',\n runId: this.currentRunId,\n }\n }\n\n getCurrentOrLastRunEventContext(): ChatClientRunEventContext | undefined {\n return this.getCurrentRunEventContext() ?? this.lastRunEventContext\n }\n\n findToolCallContext(toolCallId: string): ChatClientEventContext {\n const base: ChatClientEventContext = { toolCallId }\n const runContext = this.getCurrentRunEventContext()\n if (runContext) {\n return {\n threadId: runContext.threadId,\n runId: runContext.runId,\n toolCallId,\n }\n }\n if (this.chatOptions.threadId) {\n return { threadId: this.chatOptions.threadId, toolCallId }\n }\n return base\n }\n\n // --- Fixture replay ------------------------------------------------------\n\n /**\n * Entry point invoked when the devtools panel emits\n * `devtools:tool-fixture:apply`. The chat client never calls this\n * directly; it is wired through the base bridge's fixture subscription.\n */\n async applyFixture(fixture: AIDevtoolsToolFixture): Promise<void> {\n const messages = this.chatOptions.getMessages()\n const threadId = fixture.threadId ?? this.chatOptions.threadId ?? ''\n if (fixture.execute) {\n await this.executeFixture(fixture, messages, threadId)\n return\n }\n\n const replay = this.createReplayMessageFromFixture(fixture, messages)\n const { message, toolCallId } = replay\n const messageId = message.id\n\n this.events.messageAppended(message, undefined, {\n threadId,\n toolCallId,\n ...(fixture.runId ? { runId: fixture.runId } : {}),\n })\n this.chatOptions.setMessages([...messages, message])\n this.events.toolFixtureApplied({\n hookId: this.chatOptions.hookId,\n threadId,\n ...(fixture.runId ? { runId: fixture.runId } : {}),\n toolName: fixture.toolName,\n input: fixture.input,\n output: fixture.output,\n messageId,\n toolCallId,\n ...(fixture.execute !== undefined ? { execute: fixture.execute } : {}),\n ...(fixture.message ? { message: fixture.message } : {}),\n ...(fixture.errorText ? { errorText: fixture.errorText } : {}),\n })\n this.emitSnapshot()\n }\n\n private async executeFixture(\n fixture: AIDevtoolsToolFixture,\n messages: Array<UIMessage>,\n threadId: string,\n ): Promise<void> {\n const toolCallId = this.resolveFixtureToolCallId(\n fixture.toolCallId,\n messages,\n )\n const messageId = this.resolveFixtureMessageId(fixture.messageId, messages)\n const message: UIMessage = {\n id: messageId,\n role: 'assistant',\n parts: [\n {\n type: 'tool-call',\n id: toolCallId,\n name: fixture.toolName,\n arguments: stringifyFixtureValue(fixture.input),\n input: fixture.input,\n state: 'input-complete',\n },\n ],\n createdAt: new Date(),\n }\n\n this.events.messageAppended(message, undefined, {\n threadId,\n toolCallId,\n ...(fixture.runId ? { runId: fixture.runId } : {}),\n })\n this.chatOptions.setMessages([...messages, message])\n this.emitSnapshot()\n\n const clientTool = this.findClientTool(fixture.toolName)\n const executeFunc = clientTool?.execute\n if (!executeFunc) {\n console.warn(\n `[ai-devtools] tool fixture \"${fixture.toolName}\" requested execute=true but no client tool implementation is registered; replaying saved output instead.`,\n )\n this.addToolResultForFixture({\n fixture,\n messageId,\n toolCallId,\n threadId,\n output: fixture.output,\n errorText: fixture.errorText,\n })\n return\n }\n\n let output: unknown\n try {\n output = await executeFunc(fixture.input)\n } catch (error) {\n console.error(\n `[ai-devtools] tool fixture \"${fixture.toolName}\" execute threw`,\n error,\n )\n this.addToolResultForFixture({\n fixture,\n messageId,\n toolCallId,\n threadId,\n output: null,\n errorText:\n error instanceof Error\n ? `${error.name}: ${error.message}`\n : `Tool execution failed: ${String(error)}`,\n })\n return\n }\n this.addToolResultForFixture({\n fixture,\n messageId,\n toolCallId,\n threadId,\n output,\n })\n }\n\n private addToolResultForFixture(input: {\n fixture: AIDevtoolsToolFixture\n messageId: string\n toolCallId: string\n threadId: string\n output: unknown\n errorText?: string\n }): void {\n const state = input.errorText ? 'output-error' : 'output-available'\n this.events.toolResultAdded(\n input.toolCallId,\n input.fixture.toolName,\n input.output,\n state,\n {\n threadId: input.threadId,\n ...(input.fixture.runId ? { runId: input.fixture.runId } : {}),\n toolCallId: input.toolCallId,\n },\n )\n this.chatOptions.addToolResult(\n input.toolCallId,\n input.output,\n input.errorText,\n )\n this.events.toolFixtureApplied({\n hookId: this.chatOptions.hookId,\n threadId: input.threadId,\n ...(input.fixture.runId ? { runId: input.fixture.runId } : {}),\n toolName: input.fixture.toolName,\n input: input.fixture.input,\n output: input.output,\n execute: true,\n messageId: input.messageId,\n toolCallId: input.toolCallId,\n ...(input.errorText ? { errorText: input.errorText } : {}),\n })\n this.emitSnapshot()\n }\n\n private createReplayMessageFromFixture(\n fixture: AIDevtoolsToolFixture,\n messages: Array<UIMessage>,\n ): { message: UIMessage; toolCallId: string } {\n const cloned = this.cloneFixtureSourceMessage(fixture, messages)\n if (cloned) return cloned\n\n const toolCallId = this.resolveFixtureToolCallId(\n fixture.toolCallId,\n messages,\n )\n const messageId = this.resolveFixtureMessageId(fixture.messageId, messages)\n const state = fixture.errorText ? 'error' : 'complete'\n\n return {\n toolCallId,\n message: {\n id: messageId,\n role: 'assistant',\n parts: [\n {\n type: 'tool-call',\n id: toolCallId,\n name: fixture.toolName,\n arguments: stringifyFixtureValue(fixture.input),\n input: fixture.input,\n state: 'input-complete',\n output: fixture.output,\n },\n {\n type: 'tool-result',\n toolCallId,\n content: stringifyFixtureValue(fixture.output),\n state,\n ...(fixture.errorText ? { error: fixture.errorText } : {}),\n },\n ],\n createdAt: new Date(),\n },\n }\n }\n\n private cloneFixtureSourceMessage(\n fixture: AIDevtoolsToolFixture,\n messages: Array<UIMessage>,\n ): { message: UIMessage; toolCallId: string } | undefined {\n const sourceMessage = fixture.message\n if (!sourceMessage || !Array.isArray(sourceMessage.parts)) {\n return undefined\n }\n\n const toolCallIds = this.createFixtureToolCallIdMap(\n sourceMessage.parts,\n messages,\n )\n const parts = sourceMessage.parts\n .map((part) => cloneFixtureMessagePart(part, toolCallIds))\n .filter((part): part is MessagePart => Boolean(part))\n const mappedFixtureToolCallId = fixture.toolCallId\n ? toolCallIds.get(fixture.toolCallId)\n : undefined\n hydrateToolCallOutputs(parts, {\n ...(mappedFixtureToolCallId\n ? { mappedToolCallId: mappedFixtureToolCallId }\n : {}),\n output: fixture.output,\n })\n\n if (parts.length === 0) return undefined\n\n const toolCallId =\n (fixture.toolCallId ? toolCallIds.get(fixture.toolCallId) : undefined) ??\n firstToolCallId(parts)\n if (!toolCallId) return undefined\n\n return {\n toolCallId,\n message: {\n id: this.resolveFixtureMessageId(sourceMessage.id, messages),\n role: sourceMessage.role,\n parts,\n createdAt: new Date(),\n },\n }\n }\n\n private createFixtureToolCallIdMap(\n parts: Array<unknown>,\n messages: Array<UIMessage>,\n ): Map<string, string> {\n const ids = new Map<string, string>()\n for (const part of parts) {\n if (!isRecord(part) || part.type !== 'tool-call') continue\n if (typeof part.id !== 'string') continue\n ids.set(part.id, this.resolveFixtureToolCallId(part.id, messages))\n }\n return ids\n }\n\n private resolveFixtureMessageId(\n messageId: string | undefined,\n messages: Array<UIMessage>,\n ): string {\n if (messageId && !messages.some((message) => message.id === messageId)) {\n return messageId\n }\n return this.chatOptions.generateId('fixture-msg')\n }\n\n private resolveFixtureToolCallId(\n toolCallId: string | undefined,\n messages: Array<UIMessage>,\n ): string {\n if (toolCallId && !hasToolCallId(messages, toolCallId)) {\n return toolCallId\n }\n return this.chatOptions.generateId('fixture-tool-call')\n }\n\n private findClientTool(name: string): AnyClientTool | undefined {\n const tools = this.chatOptions.getTools?.()\n if (!tools) return undefined\n for (const tool of tools) {\n if (tool.name === name) return tool\n }\n return undefined\n }\n}\n\n// ---- Module-level fixture helpers (pure; share no state) -------------------\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null\n}\n\nfunction stringifyFixtureValue(value: unknown): string {\n if (typeof value === 'string') return value\n if (\n value === undefined ||\n typeof value === 'function' ||\n typeof value === 'symbol'\n ) {\n return String(value)\n }\n try {\n return JSON.stringify(value)\n } catch (error) {\n console.error(\n '[ai-devtools] failed to JSON.stringify fixture value; falling back to String(). Tool call arguments may be malformed.',\n { error, value },\n )\n return String(value)\n }\n}\n\nfunction parseFixtureResultContent(content: string): unknown {\n try {\n return JSON.parse(content)\n } catch (error) {\n console.error(\n '[ai-devtools] failed to JSON.parse fixture result content; replaying as raw string. Fixture payload may be corrupted.',\n { error, content },\n )\n return content\n }\n}\n\nfunction cloneFixtureMessagePart(\n part: unknown,\n toolCallIds: Map<string, string>,\n): MessagePart | undefined {\n if (!isRecord(part) || typeof part.type !== 'string') return undefined\n const cloned: Record<string, unknown> = { ...part }\n\n if (part.type === 'tool-call' && typeof part.id === 'string') {\n cloned.id = toolCallIds.get(part.id) ?? part.id\n }\n if (part.type === 'tool-result' && typeof part.toolCallId === 'string') {\n cloned.toolCallId = toolCallIds.get(part.toolCallId) ?? part.toolCallId\n }\n return cloned as MessagePart\n}\n\nfunction firstToolCallId(parts: Array<MessagePart>): string | undefined {\n const toolCall = parts.find((part) => part.type === 'tool-call')\n return toolCall?.type === 'tool-call' ? toolCall.id : undefined\n}\n\nfunction hydrateToolCallOutputs(\n parts: Array<MessagePart>,\n fixtureOutput: { mappedToolCallId?: string; output: unknown },\n): void {\n for (const part of parts) {\n if (part.type !== 'tool-result') continue\n const toolCall = parts.find(\n (candidate): candidate is ToolCallPart =>\n candidate.type === 'tool-call' &&\n candidate.id === part.toolCallId &&\n candidate.output === undefined,\n )\n if (toolCall) {\n toolCall.output = Array.isArray(part.content)\n ? part.content\n : parseFixtureResultContent(part.content)\n }\n }\n\n if (fixtureOutput.mappedToolCallId && fixtureOutput.output !== undefined) {\n const toolCall = parts.find(\n (candidate): candidate is ToolCallPart =>\n candidate.type === 'tool-call' &&\n candidate.id === fixtureOutput.mappedToolCallId &&\n candidate.output === undefined,\n )\n if (toolCall) {\n toolCall.output = fixtureOutput.output\n }\n }\n}\n\nfunction hasToolCallId(\n messages: Array<UIMessage>,\n toolCallId: string,\n): boolean {\n return messages.some((message) =>\n message.parts.some((part) => {\n if (part.type === 'tool-call') return part.id === toolCallId\n if (part.type === 'tool-result') return part.toolCallId === toolCallId\n return false\n }),\n )\n}\n\n// Devtools surface for GenerationClient / VideoGenerationClient. Owns per-run\n// history, active-run lifecycle, and snapshot emission; the generation client\n// pushes its core state in via the record* methods.\n\nexport interface AIDevtoolsGenerationSnapshotBase<TOutput> {\n input: unknown\n result: TOutput | null\n preview: AIDevtoolsGenerationPreview\n progress: AIDevtoolsGenerationProgress | null\n status: AIDevtoolsGenerationRunStatus\n isLoading: boolean\n activeRunId: string | null\n runs: Array<AIDevtoolsGenerationRunSnapshot<TOutput>>\n error?: string\n}\n\nexport interface GenerationDevtoolsBridgeOptions<TOutput> extends Omit<\n AIDevtoolsBridgeOptions<AIDevtoolsGenerationSnapshotBase<TOutput>>,\n 'getSnapshot'\n> {\n getCoreState: () => GenerationDevtoolsCoreState<TOutput>\n maxRuns?: number\n}\n\nexport interface GenerationDevtoolsCoreState<TOutput> {\n input: unknown\n result: TOutput | null\n progress: AIDevtoolsGenerationProgress | null\n status: AIDevtoolsGenerationRunStatus\n isLoading: boolean\n error?: string\n}\n\nexport interface GenerationRunPatch<TOutput> {\n input?: unknown\n result?: TOutput | null\n preview?: AIDevtoolsGenerationPreview\n progress?: AIDevtoolsGenerationProgress | null\n status?: AIDevtoolsGenerationRunStatus\n isLoading?: boolean\n completedAt?: number\n error?: string\n clearError?: boolean\n}\n\nexport class GenerationDevtoolsBridge<TOutput> extends ClientDevtoolsBridge<\n AIDevtoolsGenerationSnapshotBase<TOutput>\n> {\n protected activeRunId: string | null = null\n protected activeRunStarted = false\n protected devtoolsRuns: Array<AIDevtoolsGenerationRunSnapshot<TOutput>> = []\n protected readonly maxRuns: number\n protected readonly getCoreState: () => GenerationDevtoolsCoreState<TOutput>\n\n constructor(options: GenerationDevtoolsBridgeOptions<TOutput>) {\n super({\n ...options,\n getSnapshot: () => this.buildSnapshot(),\n })\n this.maxRuns = options.maxRuns ?? 20\n this.getCoreState = options.getCoreState\n }\n\n // --- Run lifecycle (called by GenerationClient) -----------------------\n\n beginRun(input: unknown): string {\n const runId = this.generateRunId()\n this.activeRunId = runId\n this.activeRunStarted = false\n this.upsertRun(runId, {\n input,\n result: null,\n preview: this.createPreview(null),\n progress: null,\n status: 'generating',\n isLoading: true,\n clearError: true,\n })\n return runId\n }\n\n ensureRunStarted(runId: string): void {\n if (this.activeRunStarted && this.activeRunId === runId) return\n\n if (\n !this.activeRunStarted &&\n this.activeRunId &&\n this.activeRunId !== runId\n ) {\n this.renameRun(this.activeRunId, runId)\n }\n\n this.activeRunId = runId\n this.activeRunStarted = true\n this.upsertRun(runId, {\n status: 'generating',\n isLoading: true,\n clearError: true,\n })\n this.emitRunLifecycle('run:started', runId, 'started')\n this.emitState()\n }\n\n finishRun(\n runId: string,\n eventType: 'run:completed' | 'run:errored' | 'run:cancelled',\n status: 'completed' | 'errored' | 'cancelled',\n error?: string,\n ): void {\n this.ensureRunStarted(runId)\n const completedAt = Date.now()\n const completedProgress =\n status === 'completed' ? this.completeProgress() : this.getProgress()\n const runStatus =\n status === 'completed'\n ? 'success'\n : status === 'errored'\n ? 'error'\n : 'cancelled'\n\n this.upsertRun(runId, {\n status: runStatus,\n isLoading: false,\n progress: completedProgress,\n completedAt,\n ...(error ? { error } : { clearError: true }),\n })\n\n if (this.activeRunId === runId) {\n this.activeRunId = null\n }\n this.activeRunStarted = false\n this.emitRunLifecycle(eventType, runId, status, {\n ...(error ? { error } : {}),\n })\n this.emitState()\n }\n\n getActiveRunId(): string | null {\n return this.activeRunId\n }\n\n /** Clear all per-run history. Called when the client `reset()`s. */\n resetRuns(): void {\n this.activeRunId = null\n this.activeRunStarted = false\n this.devtoolsRuns = []\n }\n\n /** Record state changes from the client and emit the matching snapshot. */\n recordResultChange(): void {\n this.updateActiveRun({\n result: this.getCoreState().result,\n preview: this.createPreview(this.getCoreState().result),\n clearError: true,\n })\n this.emitState()\n }\n\n recordLoadingChange(): void {\n this.updateActiveRun({ isLoading: this.getCoreState().isLoading })\n this.emitState()\n }\n\n recordErrorChange(error: Error | undefined): void {\n this.updateActiveRun(\n error ? { error: error.message } : { clearError: true },\n )\n this.emitState()\n }\n\n recordStatusChange(status: AIDevtoolsGenerationRunStatus): void {\n this.updateActiveRun({ status })\n this.emitState()\n }\n\n recordProgressChange(): void {\n this.updateActiveRun({ progress: this.getCoreState().progress })\n this.emitState()\n }\n\n /** Emit the latest snapshot without touching run state. */\n emitState(): void {\n this.emitUpdated()\n this.emitSnapshot()\n }\n\n // --- Internal ---------------------------------------------------------\n\n protected buildSnapshot(): AIDevtoolsGenerationSnapshotBase<TOutput> {\n const core = this.getCoreState()\n return {\n input: core.input,\n result: core.result,\n preview: this.createPreview(core.result),\n progress: core.progress,\n status: core.status,\n isLoading: core.isLoading,\n activeRunId: this.activeRunId,\n runs: this.devtoolsRuns,\n ...(core.error ? { error: core.error } : {}),\n }\n }\n\n protected updateActiveRun(patch: GenerationRunPatch<TOutput>): void {\n if (!this.activeRunId) return\n this.upsertRun(this.activeRunId, patch)\n }\n\n protected upsertRun(runId: string, patch: GenerationRunPatch<TOutput>): void {\n const now = Date.now()\n const index = this.devtoolsRuns.findIndex((run) => run.id === runId)\n const existing = index >= 0 ? this.devtoolsRuns[index] : undefined\n const next: AIDevtoolsGenerationRunSnapshot<TOutput> = existing\n ? { ...existing }\n : {\n id: runId,\n input: this.getCoreState().input,\n result: null,\n preview: this.createPreview(null),\n progress: null,\n status: 'idle',\n isLoading: false,\n startedAt: now,\n updatedAt: now,\n }\n\n if ('input' in patch) next.input = patch.input ?? null\n if ('result' in patch) next.result = patch.result ?? null\n if (patch.preview) next.preview = patch.preview\n if ('progress' in patch) next.progress = patch.progress ?? null\n if (patch.status) next.status = patch.status\n if ('isLoading' in patch) next.isLoading = patch.isLoading === true\n if (patch.completedAt !== undefined) next.completedAt = patch.completedAt\n if (patch.clearError) delete next.error\n if (patch.error !== undefined) next.error = patch.error\n next.updatedAt = now\n\n if (index >= 0) {\n this.devtoolsRuns = this.devtoolsRuns.map((run) =>\n run.id === runId ? next : run,\n )\n } else {\n this.devtoolsRuns = [...this.devtoolsRuns, next]\n }\n\n if (this.devtoolsRuns.length > this.maxRuns) {\n this.devtoolsRuns = this.devtoolsRuns.slice(-this.maxRuns)\n }\n }\n\n protected renameRun(previousRunId: string, nextRunId: string): void {\n if (previousRunId === nextRunId) return\n\n const existing = this.devtoolsRuns.find((run) => run.id === previousRunId)\n if (!existing) return\n\n const renamed = { ...existing, id: nextRunId, updatedAt: Date.now() }\n this.devtoolsRuns = this.devtoolsRuns\n .filter((run) => run.id !== nextRunId)\n .map((run) => (run.id === previousRunId ? renamed : run))\n }\n\n protected getProgress(): AIDevtoolsGenerationProgress | null {\n return this.getCoreState().progress\n }\n\n protected completeProgress(): AIDevtoolsGenerationProgress | null {\n const progress = this.getCoreState().progress\n if (!progress) return null\n return {\n value: 100,\n ...(progress.message ? { message: progress.message } : {}),\n }\n }\n\n protected createPreview(result: TOutput | null): AIDevtoolsGenerationPreview {\n return createAIDevtoolsGenerationPreview({\n outputKind: this.options.metadata.outputKind,\n result,\n })\n }\n\n protected generateRunId(): string {\n return `run-${Date.now()}-${Math.random().toString(36).substring(7)}`\n }\n}\n\n// Video-job specialization: snapshots also carry the job id and the latest\n// provider-reported video status so the panel can show streaming progress\n// before the final URL lands.\n\nexport interface AIDevtoolsVideoSnapshotBase<\n TOutput,\n> extends AIDevtoolsGenerationSnapshotBase<TOutput> {\n jobId: string | null\n videoStatus: unknown\n}\n\nexport interface VideoDevtoolsCoreState<\n TOutput,\n> extends GenerationDevtoolsCoreState<TOutput> {\n jobId: string | null\n videoStatus: unknown\n}\n\nexport interface VideoDevtoolsBridgeOptions<TOutput> extends Omit<\n GenerationDevtoolsBridgeOptions<TOutput>,\n 'getCoreState'\n> {\n getCoreState: () => VideoDevtoolsCoreState<TOutput>\n}\n\nexport interface VideoRunPatch<TOutput> extends GenerationRunPatch<TOutput> {\n jobId?: string | null\n videoStatus?: unknown\n}\n\nexport class VideoDevtoolsBridge<\n TOutput,\n> extends GenerationDevtoolsBridge<TOutput> {\n constructor(options: VideoDevtoolsBridgeOptions<TOutput>) {\n super(options)\n }\n\n recordJobIdChange(): void {\n this.updateActiveRun({\n jobId: (this.getCoreState() as VideoDevtoolsCoreState<TOutput>).jobId,\n } as VideoRunPatch<TOutput>)\n this.emitState()\n }\n\n recordVideoStatusChange(): void {\n const core = this.getCoreState() as VideoDevtoolsCoreState<TOutput>\n this.updateActiveRun({\n videoStatus: core.videoStatus,\n preview: this.createVideoPreview(core.result, core.videoStatus),\n } as VideoRunPatch<TOutput>)\n this.emitState()\n }\n\n protected override buildSnapshot(): AIDevtoolsVideoSnapshotBase<TOutput> {\n const core = this.getCoreState() as VideoDevtoolsCoreState<TOutput>\n return {\n input: core.input,\n result: core.result,\n preview: this.createVideoPreview(core.result, core.videoStatus),\n progress: core.progress,\n status: core.status,\n isLoading: core.isLoading,\n activeRunId: this.activeRunId,\n runs: this.devtoolsRuns,\n jobId: core.jobId,\n videoStatus: core.videoStatus,\n ...(core.error ? { error: core.error } : {}),\n }\n }\n\n protected override upsertRun(\n runId: string,\n patch: VideoRunPatch<TOutput>,\n ): void {\n super.upsertRun(runId, patch)\n if (!('jobId' in patch || 'videoStatus' in patch)) return\n\n const index = this.devtoolsRuns.findIndex((run) => run.id === runId)\n if (index < 0) return\n const target = this.devtoolsRuns[index]\n if (!target) return\n const merged: AIDevtoolsGenerationRunSnapshot<TOutput> = { ...target }\n if ('jobId' in patch) merged.jobId = patch.jobId ?? null\n if ('videoStatus' in patch) merged.videoStatus = patch.videoStatus ?? null\n this.devtoolsRuns = this.devtoolsRuns.map((run) =>\n run.id === runId ? merged : run,\n )\n }\n\n // Override so record* methods inherited from GenerationDevtoolsBridge\n // (e.g. recordResultChange) thread the latest videoStatus into the preview.\n protected override createPreview(\n result: TOutput | null,\n ): AIDevtoolsGenerationPreview {\n const core = this.getCoreState() as VideoDevtoolsCoreState<TOutput>\n return this.createVideoPreview(result, core.videoStatus)\n }\n\n private createVideoPreview(\n result: TOutput | null,\n videoStatus: unknown,\n ): AIDevtoolsGenerationPreview {\n return createAIDevtoolsGenerationPreview({\n outputKind: this.options.metadata.outputKind,\n result,\n videoStatus,\n })\n }\n}\n\n// Wraps the plain emitter so callers can do `this.events.X(...)` and get:\n// auto-attached run/thread context on every event that accepts one,\n// an auto-emitted snapshot after each event, and passive streamId tracking\n// so resolveStreamId() works without the chat client telling it.\nclass ChatDevtoolsAwareEventEmitter extends DefaultChatClientEventEmitter {\n constructor(\n clientId: string,\n private readonly helper: ChatDevtoolsBridge,\n ) {\n super(clientId)\n }\n\n private afterEmit(streamId?: string): void {\n if (streamId) this.helper.recordStreamId(streamId)\n this.helper.emitSnapshot()\n }\n\n // -- methods with run context --------------------------------------------\n\n override textUpdated(\n streamId: string,\n messageId: string,\n content: string,\n context?: ChatClientRunEventContext,\n ): void {\n super.textUpdated(\n streamId,\n messageId,\n content,\n context ?? this.helper.getCurrentRunEventContext(),\n )\n this.afterEmit(streamId)\n }\n\n override thinkingUpdated(\n streamId: string,\n messageId: string,\n content: string,\n delta?: string,\n context?: ChatClientRunEventContext,\n ): void {\n super.thinkingUpdated(\n streamId,\n messageId,\n content,\n delta,\n context ?? this.helper.getCurrentRunEventContext(),\n )\n this.afterEmit(streamId)\n }\n\n override messageAppended(\n uiMessage: Parameters<DefaultChatClientEventEmitter['messageAppended']>[0],\n streamId?: string,\n context?: ChatClientEventContext,\n ): void {\n super.messageAppended(\n uiMessage,\n streamId,\n context ?? this.helper.getCurrentRunEventContext(),\n )\n this.afterEmit(streamId)\n }\n\n override toolCallStateChanged(\n streamId: string,\n messageId: string,\n toolCallId: string,\n toolName: string,\n state: string,\n args: string,\n context?: ChatClientRunEventContext,\n ): void {\n super.toolCallStateChanged(\n streamId,\n messageId,\n toolCallId,\n toolName,\n state,\n args,\n context ?? this.helper.getCurrentRunEventContext(),\n )\n this.afterEmit(streamId)\n }\n\n override structuredOutputChanged(\n eventName: Parameters<\n DefaultChatClientEventEmitter['structuredOutputChanged']\n >[0],\n streamId: string,\n messageId: string,\n output: Parameters<\n DefaultChatClientEventEmitter['structuredOutputChanged']\n >[3],\n context?: ChatClientRunEventContext,\n ): void {\n super.structuredOutputChanged(\n eventName,\n streamId,\n messageId,\n output,\n context ?? this.helper.getCurrentOrLastRunEventContext(),\n )\n this.afterEmit(streamId)\n }\n\n override approvalRequested(\n streamId: string,\n messageId: string,\n toolCallId: string,\n toolName: string,\n input: unknown,\n approvalId: string,\n context?: ChatClientRunEventContext,\n ): void {\n super.approvalRequested(\n streamId,\n messageId,\n toolCallId,\n toolName,\n input,\n approvalId,\n context ?? this.helper.getCurrentOrLastRunEventContext(),\n )\n this.afterEmit(streamId)\n }\n\n override toolResultAdded(\n toolCallId: string,\n toolName: string,\n output: unknown,\n state: string,\n context?: ChatClientEventContext,\n ): void {\n super.toolResultAdded(\n toolCallId,\n toolName,\n output,\n state,\n context ?? this.helper.getCurrentRunEventContext(),\n )\n this.afterEmit()\n }\n\n override toolApprovalResponded(\n approvalId: string,\n toolCallId: string,\n approved: boolean,\n context?: ChatClientRunEventContext,\n ): void {\n super.toolApprovalResponded(\n approvalId,\n toolCallId,\n approved,\n context ?? this.helper.getCurrentRunEventContext(),\n )\n this.afterEmit()\n }\n\n // -- methods without context (just auto-emit snapshot) -------------------\n\n override clientCreated(initialMessageCount: number): void {\n super.clientCreated(initialMessageCount)\n this.afterEmit()\n }\n override loadingChanged(isLoading: boolean): void {\n super.loadingChanged(isLoading)\n this.afterEmit()\n }\n override errorChanged(error: string | null): void {\n super.errorChanged(error)\n this.afterEmit()\n }\n override reloaded(fromMessageIndex: number): void {\n super.reloaded(fromMessageIndex)\n this.afterEmit()\n }\n override stopped(): void {\n super.stopped()\n this.afterEmit()\n }\n override messagesCleared(): void {\n super.messagesCleared()\n this.afterEmit()\n }\n override messageSent(\n messageId: string,\n content: Parameters<DefaultChatClientEventEmitter['messageSent']>[1],\n ): void {\n super.messageSent(messageId, content)\n this.afterEmit()\n }\n override toolFixtureApplied(\n fixture: Parameters<DefaultChatClientEventEmitter['toolFixtureApplied']>[0],\n ): void {\n super.toolFixtureApplied(fixture)\n this.afterEmit()\n }\n}\n\nexport function createChatDevtoolsBridge(\n options: ChatDevtoolsBridgeOptions,\n): ChatDevtoolsBridge {\n return new ChatDevtoolsBridge(options)\n}\n\nexport function createGenerationDevtoolsBridge<TOutput>(\n options: GenerationDevtoolsBridgeOptions<TOutput>,\n): GenerationDevtoolsBridge<TOutput> {\n return new GenerationDevtoolsBridge<TOutput>(options)\n}\n\nexport function createVideoDevtoolsBridge<TOutput>(\n options: VideoDevtoolsBridgeOptions<TOutput>,\n): VideoDevtoolsBridge<TOutput> {\n return new VideoDevtoolsBridge<TOutput>(options)\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"devtools.js","sources":["../../src/devtools.ts"],"sourcesContent":["import {\n aiEventClient,\n createAIDevtoolsEventEnvelope,\n emitAIDevtoolsEvent,\n} from '@tanstack/ai-event-client'\nimport { convertSchemaToJsonSchema } from '@tanstack/ai/client'\nimport { DefaultChatClientEventEmitter } from './events'\nimport type { AnyClientTool, StreamChunk } from '@tanstack/ai/client'\nimport type { AIDevtoolsEventVisibility } from '@tanstack/ai-event-client'\nimport type {\n ChatClientEventContext,\n ChatClientEventEmitter,\n ChatClientRunEventContext,\n} from './events'\nimport type {\n ChatClientState,\n ConnectionStatus,\n MessagePart,\n QueuedMessage,\n ToolCallPart,\n UIMessage,\n} from './types'\n\nexport interface AIDevtoolsDisplayOptions {\n name?: string\n}\n\nexport interface AIDevtoolsClientMetadata extends AIDevtoolsDisplayOptions {\n framework?: string\n hookName: string\n outputKind?: 'chat' | 'text' | 'structured' | 'image' | 'video' | 'audio'\n}\n\nexport interface AIDevtoolsGenerationProgress {\n value: number\n message?: string\n}\n\nexport interface AIDevtoolsGenerationMediaItem {\n src: string\n sourceType: 'url' | 'base64'\n mimeType?: string\n format?: string\n duration?: number\n}\n\nexport interface AIDevtoolsGenerationVideoJob {\n jobId: string\n status?: string\n progress?: number\n error?: string\n}\n\nexport type AIDevtoolsGenerationPreview =\n | {\n kind: 'image'\n items: Array<AIDevtoolsGenerationMediaItem>\n }\n | {\n kind: 'audio'\n items: Array<AIDevtoolsGenerationMediaItem>\n }\n | {\n kind: 'video'\n items: Array<AIDevtoolsGenerationMediaItem>\n job?: AIDevtoolsGenerationVideoJob\n }\n | {\n kind: 'text'\n text: string\n }\n | {\n kind: 'structured'\n value: unknown\n }\n | {\n kind: 'empty'\n }\n\nexport type AIDevtoolsGenerationRunStatus =\n | 'idle'\n | 'generating'\n | 'success'\n | 'error'\n | 'cancelled'\n\nexport interface AIDevtoolsGenerationRunSnapshot<TOutput = unknown> {\n id: string\n input: unknown\n result: TOutput | null\n preview: AIDevtoolsGenerationPreview\n progress: AIDevtoolsGenerationProgress | null\n status: AIDevtoolsGenerationRunStatus\n isLoading: boolean\n startedAt: number\n updatedAt: number\n completedAt?: number\n error?: string\n jobId?: string | null\n videoStatus?: unknown\n}\n\nexport interface AIDevtoolsGenerationPreviewInput {\n outputKind?: AIDevtoolsClientMetadata['outputKind']\n result: unknown\n videoStatus?: unknown\n}\n\nexport interface AIDevtoolsChatSnapshot {\n [key: string]: unknown\n messages: Array<UIMessage>\n status: ChatClientState\n isLoading: boolean\n isSubscribed: boolean\n connectionStatus: ConnectionStatus\n sessionGenerating: boolean\n activeRunIds: Array<string>\n queue?: Array<QueuedMessage>\n error?: string\n}\n\nexport function createAIDevtoolsGenerationPreview(\n input: AIDevtoolsGenerationPreviewInput,\n): AIDevtoolsGenerationPreview {\n if (input.outputKind === 'image') {\n return imagePreviewFromResult(input.result)\n }\n\n if (input.outputKind === 'audio') {\n return audioPreviewFromResult(input.result)\n }\n\n if (input.outputKind === 'video') {\n return videoPreviewFromResult(input.result, input.videoStatus)\n }\n\n if (input.outputKind === 'text') {\n return textPreviewFromResult(input.result)\n }\n\n if (input.result === null || input.result === undefined) {\n return { kind: 'empty' }\n }\n\n return {\n kind: 'structured',\n value: input.result,\n }\n}\n\ntype UnknownRecord = { [key: string]: unknown }\n\nfunction imagePreviewFromResult(result: unknown): AIDevtoolsGenerationPreview {\n const record = asRecord(result)\n const images = Array.isArray(record?.images) ? record.images : []\n const items = images\n .map((image) => mediaItemFromSource(image, 'image/png'))\n .filter(isGenerationMediaItem)\n\n if (items.length === 0 && result !== null && result !== undefined) {\n const directItem = mediaItemFromSource(result, 'image/png')\n if (directItem) {\n items.push(directItem)\n }\n }\n\n return { kind: 'image', items }\n}\n\nfunction audioPreviewFromResult(result: unknown): AIDevtoolsGenerationPreview {\n const record = asRecord(result)\n const audio = record?.audio\n const resultContentType = stringField(record, 'contentType')\n const format = stringField(record, 'format')\n const mimeType = resultContentType ?? mimeTypeFromAudioFormat(format)\n\n const items: Array<AIDevtoolsGenerationMediaItem> = []\n const directItem =\n typeof audio === 'string'\n ? base64MediaItem(audio, mimeType, {\n format,\n duration: numberField(record, 'duration'),\n })\n : mediaItemFromSource(audio, mimeType, {\n format,\n })\n\n if (directItem) {\n items.push(directItem)\n }\n\n return { kind: 'audio', items }\n}\n\nfunction videoPreviewFromResult(\n result: unknown,\n videoStatus: unknown,\n): AIDevtoolsGenerationPreview {\n const resultRecord = asRecord(result)\n const statusRecord = asRecord(videoStatus)\n const item =\n mediaItemFromSource(result, 'video/mp4') ??\n mediaItemFromSource(videoStatus, 'video/mp4')\n const items = item ? [item] : []\n const job = videoJobFromStatus(statusRecord ?? resultRecord)\n\n return {\n kind: 'video',\n items,\n ...(job ? { job } : {}),\n }\n}\n\nfunction textPreviewFromResult(result: unknown): AIDevtoolsGenerationPreview {\n const record = asRecord(result)\n const text =\n stringField(record, 'text') ??\n stringField(record, 'summary') ??\n stringField(record, 'content') ??\n (typeof result === 'string' ? result : undefined)\n\n if (text !== undefined) {\n return { kind: 'text', text }\n }\n\n if (result === null || result === undefined) {\n return { kind: 'empty' }\n }\n\n return {\n kind: 'structured',\n value: result,\n }\n}\n\nfunction videoJobFromStatus(\n record: UnknownRecord | undefined,\n): AIDevtoolsGenerationVideoJob | undefined {\n const jobId = stringField(record, 'jobId')\n if (!jobId) return undefined\n\n return {\n jobId,\n ...(stringField(record, 'status')\n ? { status: stringField(record, 'status') }\n : {}),\n ...(numberField(record, 'progress') !== undefined\n ? { progress: numberField(record, 'progress') }\n : {}),\n ...(stringField(record, 'error')\n ? { error: stringField(record, 'error') }\n : {}),\n }\n}\n\nfunction mediaItemFromSource(\n value: unknown,\n defaultMimeType: string,\n extras: {\n format?: string\n duration?: number\n } = {},\n): AIDevtoolsGenerationMediaItem | undefined {\n const record = asRecord(value)\n if (!record) return undefined\n\n const explicitContentType =\n stringField(record, 'contentType') ?? stringField(record, 'mimeType')\n const duration = numberField(record, 'duration') ?? extras.duration\n const format = stringField(record, 'format') ?? extras.format\n const url = stringField(record, 'url')\n if (url) {\n return {\n src: url,\n sourceType: 'url',\n ...(explicitContentType ? { mimeType: explicitContentType } : {}),\n ...(format ? { format } : {}),\n ...(duration !== undefined ? { duration } : {}),\n }\n }\n\n const b64Json = stringField(record, 'b64Json')\n if (!b64Json) return undefined\n\n return base64MediaItem(b64Json, explicitContentType ?? defaultMimeType, {\n format,\n duration,\n })\n}\n\nfunction base64MediaItem(\n value: string,\n mimeType: string | undefined,\n extras: {\n format?: string\n duration?: number\n } = {},\n): AIDevtoolsGenerationMediaItem {\n const src = value.startsWith('data:')\n ? value\n : `data:${mimeType ?? 'application/octet-stream'};base64,${value}`\n\n return {\n src,\n sourceType: 'base64',\n ...(mimeType ? { mimeType } : {}),\n ...(extras.format ? { format: extras.format } : {}),\n ...(extras.duration !== undefined ? { duration: extras.duration } : {}),\n }\n}\n\nfunction mimeTypeFromAudioFormat(format: string | undefined): string {\n if (!format) return 'audio/mpeg'\n if (format === 'mp3') return 'audio/mpeg'\n return `audio/${format}`\n}\n\nfunction asRecord(value: unknown): UnknownRecord | undefined {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n return undefined\n }\n return value as UnknownRecord\n}\n\nfunction stringField(\n record: UnknownRecord | undefined,\n field: string,\n): string | undefined {\n const value = record?.[field]\n return typeof value === 'string' && value.length > 0 ? value : undefined\n}\n\nfunction numberField(\n record: UnknownRecord | undefined,\n field: string,\n): number | undefined {\n const value = record?.[field]\n return typeof value === 'number' ? value : undefined\n}\n\nfunction isGenerationMediaItem(\n value: AIDevtoolsGenerationMediaItem | undefined,\n): value is AIDevtoolsGenerationMediaItem {\n return Boolean(value)\n}\n\nexport interface AIDevtoolsToolFixture {\n fixtureId?: string\n hookId?: string\n threadId?: string\n runId?: string\n toolName: string\n input: unknown\n output: unknown\n execute?: boolean\n message?: {\n id: string\n role: UIMessage['role']\n parts: Array<unknown>\n createdAt?: number | string\n }\n toolCallId?: string\n messageId?: string\n errorText?: string\n}\n\ntype AIDevtoolsRunEventType =\n | 'run:created'\n | 'run:started'\n | 'run:updated'\n | 'run:completed'\n | 'run:errored'\n | 'run:cancelled'\n\ntype AIDevtoolsRunStatus =\n | 'created'\n | 'started'\n | 'updated'\n | 'completed'\n | 'errored'\n | 'cancelled'\n\nexport interface AIDevtoolsBridgeOptions<TSnapshot extends object> {\n hookId: string\n threadId?: string\n clientId: string\n metadata: AIDevtoolsClientMetadata\n getSnapshot: () => TSnapshot\n getTools?: () => Iterable<AnyClientTool>\n applyToolFixture?: (fixture: AIDevtoolsToolFixture) => void | Promise<void>\n}\n\ntype Unsubscribe = () => void\n\ninterface AIDevtoolsEvent<TPayload> {\n payload: TPayload\n}\n\ninterface ActiveDevtoolsBridge {\n deactivate: () => void\n dispose: () => void\n supersede?: () => void\n}\n\nconst activeBridgeRegistryKey = Symbol.for(\n 'tanstack.ai.devtools.activeBridgeByHookId',\n)\n\nfunction getActiveBridgeRegistry(): Map<string, ActiveDevtoolsBridge> {\n const global = globalThis as typeof globalThis & {\n [activeBridgeRegistryKey]?: Map<string, ActiveDevtoolsBridge>\n }\n const existing = global[activeBridgeRegistryKey]\n if (existing) return existing\n\n const registry = new Map<string, ActiveDevtoolsBridge>()\n global[activeBridgeRegistryKey] = registry\n return registry\n}\n\nexport class ClientDevtoolsBridge<TSnapshot extends object> {\n protected readonly options: AIDevtoolsBridgeOptions<TSnapshot>\n private readonly bridgeId: string\n private readonly unsubscribers: Array<Unsubscribe> = []\n private disposed = false\n private superseded = false\n private registered = false\n\n constructor(options: AIDevtoolsBridgeOptions<TSnapshot>) {\n this.options = options\n this.bridgeId = createBridgeId(options.hookId)\n }\n\n emitRegistered(): void {\n if (!this.prepareForMountEmit()) {\n return\n }\n this.registered = true\n emitAIDevtoolsEvent('hook:registered', {\n ...this.createEnvelope('hook:registered'),\n ...this.createMetadataPayload(),\n lifecycle: 'mounted',\n })\n }\n\n emitUpdated(): void {\n if (!this.prepareForEmit()) {\n return\n }\n emitAIDevtoolsEvent('hook:updated', {\n ...this.createEnvelope('hook:updated'),\n ...this.createMetadataPayload(),\n lifecycle: 'active',\n })\n }\n\n emitSnapshot(): void {\n if (!this.prepareForEmit()) {\n return\n }\n emitAIDevtoolsEvent('hook:state-snapshot', {\n ...this.createEnvelope('hook:state-snapshot'),\n ...this.createMetadataPayload(),\n // Wire envelope uses Record<string, unknown>; widen the typed snapshot\n // here so the typed-snapshot constraint above can stay narrow.\n // eslint-disable-next-line no-restricted-syntax -- TSnapshot extends object is structurally compatible but TS can't see the missing index signature\n state: this.options.getSnapshot() as unknown as Record<string, unknown>,\n })\n }\n\n emitToolsRegistered(): void {\n if (!this.prepareForEmit()) {\n return\n }\n const tools = this.options.getTools\n ? Array.from(this.options.getTools()).map((tool) => ({\n name: tool.name,\n description: tool.description,\n inputSchema: tool.inputSchema\n ? convertSchemaToJsonSchema(tool.inputSchema)\n : { type: 'object' },\n outputSchema: tool.outputSchema\n ? convertSchemaToJsonSchema(tool.outputSchema)\n : undefined,\n needsApproval: tool.needsApproval,\n metadata: tool.metadata,\n }))\n : []\n\n emitAIDevtoolsEvent('tools:registered', {\n ...this.createEnvelope('tools:registered'),\n ...this.createMetadataPayload(),\n tools,\n })\n }\n\n emitRunLifecycle(\n eventType: AIDevtoolsRunEventType,\n runId: string,\n status: AIDevtoolsRunStatus,\n options: { error?: string } = {},\n ): void {\n if (!this.prepareForEmit()) {\n return\n }\n emitAIDevtoolsEvent(eventType, {\n ...this.createEnvelope(eventType, 'client-state', { runId }),\n runId,\n status,\n ...(options.error ? { error: options.error } : {}),\n })\n }\n\n deactivate(): void {\n const activeBridgeByHookId = getActiveBridgeRegistry()\n if (activeBridgeByHookId.get(this.options.hookId) === this) {\n activeBridgeByHookId.delete(this.options.hookId)\n }\n\n for (const unsubscribe of this.unsubscribers.splice(0)) {\n unsubscribe()\n }\n }\n\n supersede(): void {\n if (this.disposed) {\n return\n }\n\n this.superseded = true\n this.disposed = true\n this.deactivate()\n }\n\n dispose(): void {\n if (this.disposed) {\n return\n }\n\n this.disposed = true\n if (!this.registered) {\n this.deactivate()\n return\n }\n\n const payload = {\n ...this.createEnvelope('hook:unregistered'),\n ...this.createMetadataPayload(),\n reason: 'disposed',\n } as const\n\n emitAIDevtoolsEvent('hook:unregistered', payload)\n\n this.deactivate()\n }\n\n private prepareForEmit(): boolean {\n if (this.disposed || this.superseded) {\n return false\n }\n this.activate()\n return true\n }\n\n private prepareForMountEmit(): boolean {\n if (this.superseded) {\n return false\n }\n\n if (this.disposed) {\n this.disposed = false\n this.registered = false\n }\n\n this.activate()\n return true\n }\n\n private activate(): void {\n if (this.disposed) {\n return\n }\n\n const activeBridgeByHookId = getActiveBridgeRegistry()\n const activeBridge = activeBridgeByHookId.get(this.options.hookId)\n if (activeBridge && activeBridge !== this) {\n if (typeof activeBridge.supersede === 'function') {\n activeBridge.supersede()\n } else {\n activeBridge.deactivate()\n }\n }\n activeBridgeByHookId.set(this.options.hookId, this)\n\n if (this.unsubscribers.length > 0) {\n return\n }\n\n this.unsubscribers.push(\n aiEventClient.on('devtools:request-state', (event) => {\n this.handleRequestState(event)\n }),\n )\n\n if (this.options.applyToolFixture) {\n this.unsubscribers.push(\n aiEventClient.on('devtools:tool-fixture:apply', (event) => {\n void this.handleToolFixtureApply(event)\n }),\n )\n }\n }\n\n private handleRequestState(\n event: AIDevtoolsEvent<{ targetHookId?: string }>,\n ): void {\n if (this.disposed || this.superseded) {\n return\n }\n\n const targetHookId = event.payload.targetHookId\n if (targetHookId && targetHookId !== this.options.hookId) {\n return\n }\n\n this.emitRegistered()\n this.emitToolsRegistered()\n this.emitSnapshot()\n }\n\n private async handleToolFixtureApply(\n event: AIDevtoolsEvent<AIDevtoolsToolFixture>,\n ): Promise<void> {\n const fixture = event.payload\n if (!this.matchesFixtureTarget(fixture)) {\n return\n }\n\n await this.options.applyToolFixture?.(fixture)\n }\n\n private matchesFixtureTarget(fixture: AIDevtoolsToolFixture): boolean {\n if (!fixture.hookId && !fixture.threadId) {\n return false\n }\n\n if (fixture.hookId) {\n return fixture.hookId === this.options.hookId\n }\n\n if (\n fixture.threadId &&\n (!this.options.threadId || fixture.threadId !== this.options.threadId)\n ) {\n return false\n }\n return true\n }\n\n private createEnvelope(\n eventType:\n | 'hook:registered'\n | 'hook:updated'\n | 'hook:unregistered'\n | 'hook:state-snapshot'\n | 'tools:registered'\n | AIDevtoolsRunEventType,\n visibility: AIDevtoolsEventVisibility = 'client-state',\n context: { runId?: string } = {},\n ) {\n return createAIDevtoolsEventEnvelope({\n eventType,\n source: 'client',\n visibility,\n clientId: this.options.clientId,\n hookId: this.options.hookId,\n correlationId: this.bridgeId,\n ...(this.options.threadId ? { threadId: this.options.threadId } : {}),\n ...(context.runId ? { runId: context.runId } : {}),\n timestamp: Date.now(),\n })\n }\n\n private createMetadataPayload() {\n return {\n hookId: this.options.hookId,\n hookName: this.options.metadata.hookName,\n ...(this.options.metadata.name\n ? { displayName: this.options.metadata.name }\n : {}),\n ...(this.options.metadata.outputKind\n ? { outputKind: this.options.metadata.outputKind }\n : {}),\n ...(this.options.metadata.framework\n ? { framework: this.options.metadata.framework }\n : {}),\n }\n }\n}\n\nlet bridgeIdSequence = 0\n\nfunction createBridgeId(hookId: string): string {\n const cryptoLike = (\n globalThis as {\n crypto?: {\n randomUUID?: () => string\n }\n }\n ).crypto\n\n if (cryptoLike?.randomUUID) {\n return `bridge:${hookId}:${cryptoLike.randomUUID()}`\n }\n\n bridgeIdSequence += 1\n return `bridge:${hookId}:${bridgeIdSequence}`\n}\n\n// Owns the chat-client devtools surface so the chat client itself stays a\n// pure transport. Fixture replay, per-run / per-stream event context, and\n// snapshot emission all live here; a no-op bridge can drop in for prod.\n\nexport interface ChatDevtoolsBridgeOptions extends AIDevtoolsBridgeOptions<AIDevtoolsChatSnapshot> {\n getMessages: () => Array<UIMessage>\n setMessages: (messages: Array<UIMessage>) => void\n addToolResult: (\n toolCallId: string,\n output: unknown,\n errorText?: string,\n ) => void\n generateId: (prefix: string) => string\n}\n\nexport class ChatDevtoolsBridge extends ClientDevtoolsBridge<AIDevtoolsChatSnapshot> {\n readonly events: ChatClientEventEmitter\n private readonly chatOptions: ChatDevtoolsBridgeOptions\n private currentRunId: string | null = null\n private currentRunThreadId: string | null = null\n private currentStreamId: string | null = null\n private lastStreamId: string | null = null\n private lastRunEventContext: ChatClientRunEventContext | undefined\n\n constructor(options: ChatDevtoolsBridgeOptions) {\n super({\n ...options,\n // Thunk defers `this.applyFixture` lookup until after `super` returns.\n applyToolFixture: (fixture) => this.applyFixture(fixture),\n })\n this.chatOptions = options\n // Auto-attaches run/thread context and auto-emits a snapshot after each\n // event so callers can keep using `this.events.X(...)` with no context arg.\n this.events = new ChatDevtoolsAwareEventEmitter(options.clientId, this)\n }\n\n // --- Stream / run context API -------------------------------------------\n\n setCurrentStreamId(streamId: string | null): void {\n this.currentStreamId = streamId\n if (streamId) {\n this.lastStreamId = streamId\n }\n }\n\n /**\n * Called by the auto-attaching emitter every time it sees a non-empty\n * streamId pass through. Lets devtools track the latest stream id\n * without the chat client wiring it up explicitly.\n */\n recordStreamId(streamId: string): void {\n if (streamId) this.lastStreamId = streamId\n }\n\n mountWithTools(initialMessageCount: number): void {\n this.events.clientCreated(initialMessageCount)\n this.emitRegistered()\n this.emitToolsRegistered()\n this.emitSnapshot()\n }\n\n notifyToolsChanged(): void {\n this.emitToolsRegistered()\n this.emitSnapshot()\n }\n\n getCurrentStreamId(): string | null {\n return this.currentStreamId\n }\n\n getLastStreamId(): string | null {\n return this.lastStreamId\n }\n\n resolveStreamId(): string {\n return (\n this.currentStreamId ??\n this.lastStreamId ??\n this.chatOptions.generateId('stream')\n )\n }\n\n // Called when the chat client has just generated a runId for outbound emits;\n // the matching RUN_STARTED chunk from the adapter lands later and\n // observeChunk keeps the same context.\n beginRun(runId: string, threadId: string): void {\n this.currentRunId = runId\n this.currentRunThreadId = threadId\n this.lastRunEventContext = { runId, threadId }\n }\n\n observeChunk(chunk: StreamChunk): void {\n if (chunk.type === 'RUN_STARTED') {\n this.beginRun(chunk.runId, chunk.threadId)\n return\n }\n\n if (chunk.type === 'RUN_FINISHED' || chunk.type === 'RUN_ERROR') {\n const runId =\n chunk.type === 'RUN_FINISHED'\n ? chunk.runId\n : (chunk as { runId?: string }).runId\n if (!runId || runId === this.currentRunId) {\n const context = this.getCurrentRunEventContext()\n if (context) {\n this.lastRunEventContext = context\n }\n this.currentRunId = null\n this.currentRunThreadId = null\n }\n }\n }\n\n getCurrentRunEventContext(): ChatClientRunEventContext | undefined {\n if (!this.currentRunId) return undefined\n return {\n threadId: this.currentRunThreadId ?? this.chatOptions.threadId ?? '',\n runId: this.currentRunId,\n }\n }\n\n getCurrentOrLastRunEventContext(): ChatClientRunEventContext | undefined {\n return this.getCurrentRunEventContext() ?? this.lastRunEventContext\n }\n\n findToolCallContext(toolCallId: string): ChatClientEventContext {\n const base: ChatClientEventContext = { toolCallId }\n const runContext = this.getCurrentRunEventContext()\n if (runContext) {\n return {\n threadId: runContext.threadId,\n runId: runContext.runId,\n toolCallId,\n }\n }\n if (this.chatOptions.threadId) {\n return { threadId: this.chatOptions.threadId, toolCallId }\n }\n return base\n }\n\n // --- Fixture replay ------------------------------------------------------\n\n /**\n * Entry point invoked when the devtools panel emits\n * `devtools:tool-fixture:apply`. The chat client never calls this\n * directly; it is wired through the base bridge's fixture subscription.\n */\n async applyFixture(fixture: AIDevtoolsToolFixture): Promise<void> {\n const messages = this.chatOptions.getMessages()\n const threadId = fixture.threadId ?? this.chatOptions.threadId ?? ''\n if (fixture.execute) {\n await this.executeFixture(fixture, messages, threadId)\n return\n }\n\n const replay = this.createReplayMessageFromFixture(fixture, messages)\n const { message, toolCallId } = replay\n const messageId = message.id\n\n this.events.messageAppended(message, undefined, {\n threadId,\n toolCallId,\n ...(fixture.runId ? { runId: fixture.runId } : {}),\n })\n this.chatOptions.setMessages([...messages, message])\n this.events.toolFixtureApplied({\n hookId: this.chatOptions.hookId,\n threadId,\n ...(fixture.runId ? { runId: fixture.runId } : {}),\n toolName: fixture.toolName,\n input: fixture.input,\n output: fixture.output,\n messageId,\n toolCallId,\n ...(fixture.execute !== undefined ? { execute: fixture.execute } : {}),\n ...(fixture.message ? { message: fixture.message } : {}),\n ...(fixture.errorText ? { errorText: fixture.errorText } : {}),\n })\n this.emitSnapshot()\n }\n\n private async executeFixture(\n fixture: AIDevtoolsToolFixture,\n messages: Array<UIMessage>,\n threadId: string,\n ): Promise<void> {\n const toolCallId = this.resolveFixtureToolCallId(\n fixture.toolCallId,\n messages,\n )\n const messageId = this.resolveFixtureMessageId(fixture.messageId, messages)\n const message: UIMessage = {\n id: messageId,\n role: 'assistant',\n parts: [\n {\n type: 'tool-call',\n id: toolCallId,\n name: fixture.toolName,\n arguments: stringifyFixtureValue(fixture.input),\n input: fixture.input,\n state: 'input-complete',\n },\n ],\n createdAt: new Date(),\n }\n\n this.events.messageAppended(message, undefined, {\n threadId,\n toolCallId,\n ...(fixture.runId ? { runId: fixture.runId } : {}),\n })\n this.chatOptions.setMessages([...messages, message])\n this.emitSnapshot()\n\n const clientTool = this.findClientTool(fixture.toolName)\n const executeFunc = clientTool?.execute\n if (!executeFunc) {\n console.warn(\n `[ai-devtools] tool fixture \"${fixture.toolName}\" requested execute=true but no client tool implementation is registered; replaying saved output instead.`,\n )\n this.addToolResultForFixture({\n fixture,\n messageId,\n toolCallId,\n threadId,\n output: fixture.output,\n errorText: fixture.errorText,\n })\n return\n }\n\n let output: unknown\n try {\n output = await executeFunc(fixture.input)\n } catch (error) {\n console.error(\n `[ai-devtools] tool fixture \"${fixture.toolName}\" execute threw`,\n error,\n )\n this.addToolResultForFixture({\n fixture,\n messageId,\n toolCallId,\n threadId,\n output: null,\n errorText:\n error instanceof Error\n ? `${error.name}: ${error.message}`\n : `Tool execution failed: ${String(error)}`,\n })\n return\n }\n this.addToolResultForFixture({\n fixture,\n messageId,\n toolCallId,\n threadId,\n output,\n })\n }\n\n private addToolResultForFixture(input: {\n fixture: AIDevtoolsToolFixture\n messageId: string\n toolCallId: string\n threadId: string\n output: unknown\n errorText?: string\n }): void {\n const state = input.errorText ? 'output-error' : 'output-available'\n this.events.toolResultAdded(\n input.toolCallId,\n input.fixture.toolName,\n input.output,\n state,\n {\n threadId: input.threadId,\n ...(input.fixture.runId ? { runId: input.fixture.runId } : {}),\n toolCallId: input.toolCallId,\n },\n )\n this.chatOptions.addToolResult(\n input.toolCallId,\n input.output,\n input.errorText,\n )\n this.events.toolFixtureApplied({\n hookId: this.chatOptions.hookId,\n threadId: input.threadId,\n ...(input.fixture.runId ? { runId: input.fixture.runId } : {}),\n toolName: input.fixture.toolName,\n input: input.fixture.input,\n output: input.output,\n execute: true,\n messageId: input.messageId,\n toolCallId: input.toolCallId,\n ...(input.errorText ? { errorText: input.errorText } : {}),\n })\n this.emitSnapshot()\n }\n\n private createReplayMessageFromFixture(\n fixture: AIDevtoolsToolFixture,\n messages: Array<UIMessage>,\n ): { message: UIMessage; toolCallId: string } {\n const cloned = this.cloneFixtureSourceMessage(fixture, messages)\n if (cloned) return cloned\n\n const toolCallId = this.resolveFixtureToolCallId(\n fixture.toolCallId,\n messages,\n )\n const messageId = this.resolveFixtureMessageId(fixture.messageId, messages)\n const state = fixture.errorText ? 'error' : 'complete'\n\n return {\n toolCallId,\n message: {\n id: messageId,\n role: 'assistant',\n parts: [\n {\n type: 'tool-call',\n id: toolCallId,\n name: fixture.toolName,\n arguments: stringifyFixtureValue(fixture.input),\n input: fixture.input,\n state: 'input-complete',\n output: fixture.output,\n },\n {\n type: 'tool-result',\n toolCallId,\n content: stringifyFixtureValue(fixture.output),\n state,\n ...(fixture.errorText ? { error: fixture.errorText } : {}),\n },\n ],\n createdAt: new Date(),\n },\n }\n }\n\n private cloneFixtureSourceMessage(\n fixture: AIDevtoolsToolFixture,\n messages: Array<UIMessage>,\n ): { message: UIMessage; toolCallId: string } | undefined {\n const sourceMessage = fixture.message\n if (!sourceMessage || !Array.isArray(sourceMessage.parts)) {\n return undefined\n }\n\n const toolCallIds = this.createFixtureToolCallIdMap(\n sourceMessage.parts,\n messages,\n )\n const parts = sourceMessage.parts\n .map((part) => cloneFixtureMessagePart(part, toolCallIds))\n .filter((part): part is MessagePart => Boolean(part))\n const mappedFixtureToolCallId = fixture.toolCallId\n ? toolCallIds.get(fixture.toolCallId)\n : undefined\n hydrateToolCallOutputs(parts, {\n ...(mappedFixtureToolCallId\n ? { mappedToolCallId: mappedFixtureToolCallId }\n : {}),\n output: fixture.output,\n })\n\n if (parts.length === 0) return undefined\n\n const toolCallId =\n (fixture.toolCallId ? toolCallIds.get(fixture.toolCallId) : undefined) ??\n firstToolCallId(parts)\n if (!toolCallId) return undefined\n\n return {\n toolCallId,\n message: {\n id: this.resolveFixtureMessageId(sourceMessage.id, messages),\n role: sourceMessage.role,\n parts,\n createdAt: new Date(),\n },\n }\n }\n\n private createFixtureToolCallIdMap(\n parts: Array<unknown>,\n messages: Array<UIMessage>,\n ): Map<string, string> {\n const ids = new Map<string, string>()\n for (const part of parts) {\n if (!isRecord(part) || part.type !== 'tool-call') continue\n if (typeof part.id !== 'string') continue\n ids.set(part.id, this.resolveFixtureToolCallId(part.id, messages))\n }\n return ids\n }\n\n private resolveFixtureMessageId(\n messageId: string | undefined,\n messages: Array<UIMessage>,\n ): string {\n if (messageId && !messages.some((message) => message.id === messageId)) {\n return messageId\n }\n return this.chatOptions.generateId('fixture-msg')\n }\n\n private resolveFixtureToolCallId(\n toolCallId: string | undefined,\n messages: Array<UIMessage>,\n ): string {\n if (toolCallId && !hasToolCallId(messages, toolCallId)) {\n return toolCallId\n }\n return this.chatOptions.generateId('fixture-tool-call')\n }\n\n private findClientTool(name: string): AnyClientTool | undefined {\n const tools = this.chatOptions.getTools?.()\n if (!tools) return undefined\n for (const tool of tools) {\n if (tool.name === name) return tool\n }\n return undefined\n }\n}\n\n// ---- Module-level fixture helpers (pure; share no state) -------------------\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null\n}\n\nfunction stringifyFixtureValue(value: unknown): string {\n if (typeof value === 'string') return value\n if (\n value === undefined ||\n typeof value === 'function' ||\n typeof value === 'symbol'\n ) {\n return String(value)\n }\n try {\n return JSON.stringify(value)\n } catch (error) {\n console.error(\n '[ai-devtools] failed to JSON.stringify fixture value; falling back to String(). Tool call arguments may be malformed.',\n { error, value },\n )\n return String(value)\n }\n}\n\nfunction parseFixtureResultContent(content: string): unknown {\n try {\n return JSON.parse(content)\n } catch (error) {\n console.error(\n '[ai-devtools] failed to JSON.parse fixture result content; replaying as raw string. Fixture payload may be corrupted.',\n { error, content },\n )\n return content\n }\n}\n\nfunction cloneFixtureMessagePart(\n part: unknown,\n toolCallIds: Map<string, string>,\n): MessagePart | undefined {\n if (!isRecord(part) || typeof part.type !== 'string') return undefined\n const cloned: Record<string, unknown> = { ...part }\n\n if (part.type === 'tool-call' && typeof part.id === 'string') {\n cloned.id = toolCallIds.get(part.id) ?? part.id\n }\n if (part.type === 'tool-result' && typeof part.toolCallId === 'string') {\n cloned.toolCallId = toolCallIds.get(part.toolCallId) ?? part.toolCallId\n }\n return cloned as MessagePart\n}\n\nfunction firstToolCallId(parts: Array<MessagePart>): string | undefined {\n const toolCall = parts.find((part) => part.type === 'tool-call')\n return toolCall?.type === 'tool-call' ? toolCall.id : undefined\n}\n\nfunction hydrateToolCallOutputs(\n parts: Array<MessagePart>,\n fixtureOutput: { mappedToolCallId?: string; output: unknown },\n): void {\n for (const part of parts) {\n if (part.type !== 'tool-result') continue\n const toolCall = parts.find(\n (candidate): candidate is ToolCallPart =>\n candidate.type === 'tool-call' &&\n candidate.id === part.toolCallId &&\n candidate.output === undefined,\n )\n if (toolCall) {\n toolCall.output = Array.isArray(part.content)\n ? part.content\n : parseFixtureResultContent(part.content)\n }\n }\n\n if (fixtureOutput.mappedToolCallId && fixtureOutput.output !== undefined) {\n const toolCall = parts.find(\n (candidate): candidate is ToolCallPart =>\n candidate.type === 'tool-call' &&\n candidate.id === fixtureOutput.mappedToolCallId &&\n candidate.output === undefined,\n )\n if (toolCall) {\n toolCall.output = fixtureOutput.output\n }\n }\n}\n\nfunction hasToolCallId(\n messages: Array<UIMessage>,\n toolCallId: string,\n): boolean {\n return messages.some((message) =>\n message.parts.some((part) => {\n if (part.type === 'tool-call') return part.id === toolCallId\n if (part.type === 'tool-result') return part.toolCallId === toolCallId\n return false\n }),\n )\n}\n\n// Devtools surface for GenerationClient / VideoGenerationClient. Owns per-run\n// history, active-run lifecycle, and snapshot emission; the generation client\n// pushes its core state in via the record* methods.\n\nexport interface AIDevtoolsGenerationSnapshotBase<TOutput> {\n input: unknown\n result: TOutput | null\n preview: AIDevtoolsGenerationPreview\n progress: AIDevtoolsGenerationProgress | null\n status: AIDevtoolsGenerationRunStatus\n isLoading: boolean\n activeRunId: string | null\n runs: Array<AIDevtoolsGenerationRunSnapshot<TOutput>>\n error?: string\n}\n\nexport interface GenerationDevtoolsBridgeOptions<TOutput> extends Omit<\n AIDevtoolsBridgeOptions<AIDevtoolsGenerationSnapshotBase<TOutput>>,\n 'getSnapshot'\n> {\n getCoreState: () => GenerationDevtoolsCoreState<TOutput>\n maxRuns?: number\n}\n\nexport interface GenerationDevtoolsCoreState<TOutput> {\n input: unknown\n result: TOutput | null\n progress: AIDevtoolsGenerationProgress | null\n status: AIDevtoolsGenerationRunStatus\n isLoading: boolean\n error?: string\n}\n\nexport interface GenerationRunPatch<TOutput> {\n input?: unknown\n result?: TOutput | null\n preview?: AIDevtoolsGenerationPreview\n progress?: AIDevtoolsGenerationProgress | null\n status?: AIDevtoolsGenerationRunStatus\n isLoading?: boolean\n completedAt?: number\n error?: string\n clearError?: boolean\n}\n\nexport class GenerationDevtoolsBridge<TOutput> extends ClientDevtoolsBridge<\n AIDevtoolsGenerationSnapshotBase<TOutput>\n> {\n protected activeRunId: string | null = null\n protected activeRunStarted = false\n protected devtoolsRuns: Array<AIDevtoolsGenerationRunSnapshot<TOutput>> = []\n protected readonly maxRuns: number\n protected readonly getCoreState: () => GenerationDevtoolsCoreState<TOutput>\n\n constructor(options: GenerationDevtoolsBridgeOptions<TOutput>) {\n super({\n ...options,\n getSnapshot: () => this.buildSnapshot(),\n })\n this.maxRuns = options.maxRuns ?? 20\n this.getCoreState = options.getCoreState\n }\n\n // --- Run lifecycle (called by GenerationClient) -----------------------\n\n beginRun(input: unknown): string {\n const runId = this.generateRunId()\n this.activeRunId = runId\n this.activeRunStarted = false\n this.upsertRun(runId, {\n input,\n result: null,\n preview: this.createPreview(null),\n progress: null,\n status: 'generating',\n isLoading: true,\n clearError: true,\n })\n return runId\n }\n\n ensureRunStarted(runId: string): void {\n if (this.activeRunStarted && this.activeRunId === runId) return\n\n if (\n !this.activeRunStarted &&\n this.activeRunId &&\n this.activeRunId !== runId\n ) {\n this.renameRun(this.activeRunId, runId)\n }\n\n this.activeRunId = runId\n this.activeRunStarted = true\n this.upsertRun(runId, {\n status: 'generating',\n isLoading: true,\n clearError: true,\n })\n this.emitRunLifecycle('run:started', runId, 'started')\n this.emitState()\n }\n\n finishRun(\n runId: string,\n eventType: 'run:completed' | 'run:errored' | 'run:cancelled',\n status: 'completed' | 'errored' | 'cancelled',\n error?: string,\n ): void {\n this.ensureRunStarted(runId)\n const completedAt = Date.now()\n const completedProgress =\n status === 'completed' ? this.completeProgress() : this.getProgress()\n const runStatus =\n status === 'completed'\n ? 'success'\n : status === 'errored'\n ? 'error'\n : 'cancelled'\n\n this.upsertRun(runId, {\n status: runStatus,\n isLoading: false,\n progress: completedProgress,\n completedAt,\n ...(error ? { error } : { clearError: true }),\n })\n\n if (this.activeRunId === runId) {\n this.activeRunId = null\n }\n this.activeRunStarted = false\n this.emitRunLifecycle(eventType, runId, status, {\n ...(error ? { error } : {}),\n })\n this.emitState()\n }\n\n getActiveRunId(): string | null {\n return this.activeRunId\n }\n\n /** Clear all per-run history. Called when the client `reset()`s. */\n resetRuns(): void {\n this.activeRunId = null\n this.activeRunStarted = false\n this.devtoolsRuns = []\n }\n\n /** Record state changes from the client and emit the matching snapshot. */\n recordResultChange(): void {\n this.updateActiveRun({\n result: this.getCoreState().result,\n preview: this.createPreview(this.getCoreState().result),\n clearError: true,\n })\n this.emitState()\n }\n\n recordLoadingChange(): void {\n this.updateActiveRun({ isLoading: this.getCoreState().isLoading })\n this.emitState()\n }\n\n recordErrorChange(error: Error | undefined): void {\n this.updateActiveRun(\n error ? { error: error.message } : { clearError: true },\n )\n this.emitState()\n }\n\n recordStatusChange(status: AIDevtoolsGenerationRunStatus): void {\n this.updateActiveRun({ status })\n this.emitState()\n }\n\n recordProgressChange(): void {\n this.updateActiveRun({ progress: this.getCoreState().progress })\n this.emitState()\n }\n\n /** Emit the latest snapshot without touching run state. */\n emitState(): void {\n this.emitUpdated()\n this.emitSnapshot()\n }\n\n // --- Internal ---------------------------------------------------------\n\n protected buildSnapshot(): AIDevtoolsGenerationSnapshotBase<TOutput> {\n const core = this.getCoreState()\n return {\n input: core.input,\n result: core.result,\n preview: this.createPreview(core.result),\n progress: core.progress,\n status: core.status,\n isLoading: core.isLoading,\n activeRunId: this.activeRunId,\n runs: this.devtoolsRuns,\n ...(core.error ? { error: core.error } : {}),\n }\n }\n\n protected updateActiveRun(patch: GenerationRunPatch<TOutput>): void {\n if (!this.activeRunId) return\n this.upsertRun(this.activeRunId, patch)\n }\n\n protected upsertRun(runId: string, patch: GenerationRunPatch<TOutput>): void {\n const now = Date.now()\n const index = this.devtoolsRuns.findIndex((run) => run.id === runId)\n const existing = index >= 0 ? this.devtoolsRuns[index] : undefined\n const next: AIDevtoolsGenerationRunSnapshot<TOutput> = existing\n ? { ...existing }\n : {\n id: runId,\n input: this.getCoreState().input,\n result: null,\n preview: this.createPreview(null),\n progress: null,\n status: 'idle',\n isLoading: false,\n startedAt: now,\n updatedAt: now,\n }\n\n if ('input' in patch) next.input = patch.input ?? null\n if ('result' in patch) next.result = patch.result ?? null\n if (patch.preview) next.preview = patch.preview\n if ('progress' in patch) next.progress = patch.progress ?? null\n if (patch.status) next.status = patch.status\n if ('isLoading' in patch) next.isLoading = patch.isLoading === true\n if (patch.completedAt !== undefined) next.completedAt = patch.completedAt\n if (patch.clearError) delete next.error\n if (patch.error !== undefined) next.error = patch.error\n next.updatedAt = now\n\n if (index >= 0) {\n this.devtoolsRuns = this.devtoolsRuns.map((run) =>\n run.id === runId ? next : run,\n )\n } else {\n this.devtoolsRuns = [...this.devtoolsRuns, next]\n }\n\n if (this.devtoolsRuns.length > this.maxRuns) {\n this.devtoolsRuns = this.devtoolsRuns.slice(-this.maxRuns)\n }\n }\n\n protected renameRun(previousRunId: string, nextRunId: string): void {\n if (previousRunId === nextRunId) return\n\n const existing = this.devtoolsRuns.find((run) => run.id === previousRunId)\n if (!existing) return\n\n const renamed = { ...existing, id: nextRunId, updatedAt: Date.now() }\n this.devtoolsRuns = this.devtoolsRuns\n .filter((run) => run.id !== nextRunId)\n .map((run) => (run.id === previousRunId ? renamed : run))\n }\n\n protected getProgress(): AIDevtoolsGenerationProgress | null {\n return this.getCoreState().progress\n }\n\n protected completeProgress(): AIDevtoolsGenerationProgress | null {\n const progress = this.getCoreState().progress\n if (!progress) return null\n return {\n value: 100,\n ...(progress.message ? { message: progress.message } : {}),\n }\n }\n\n protected createPreview(result: TOutput | null): AIDevtoolsGenerationPreview {\n return createAIDevtoolsGenerationPreview({\n outputKind: this.options.metadata.outputKind,\n result,\n })\n }\n\n protected generateRunId(): string {\n return `run-${Date.now()}-${Math.random().toString(36).substring(7)}`\n }\n}\n\n// Video-job specialization: snapshots also carry the job id and the latest\n// provider-reported video status so the panel can show streaming progress\n// before the final URL lands.\n\nexport interface AIDevtoolsVideoSnapshotBase<\n TOutput,\n> extends AIDevtoolsGenerationSnapshotBase<TOutput> {\n jobId: string | null\n videoStatus: unknown\n}\n\nexport interface VideoDevtoolsCoreState<\n TOutput,\n> extends GenerationDevtoolsCoreState<TOutput> {\n jobId: string | null\n videoStatus: unknown\n}\n\nexport interface VideoDevtoolsBridgeOptions<TOutput> extends Omit<\n GenerationDevtoolsBridgeOptions<TOutput>,\n 'getCoreState'\n> {\n getCoreState: () => VideoDevtoolsCoreState<TOutput>\n}\n\nexport interface VideoRunPatch<TOutput> extends GenerationRunPatch<TOutput> {\n jobId?: string | null\n videoStatus?: unknown\n}\n\nexport class VideoDevtoolsBridge<\n TOutput,\n> extends GenerationDevtoolsBridge<TOutput> {\n constructor(options: VideoDevtoolsBridgeOptions<TOutput>) {\n super(options)\n }\n\n recordJobIdChange(): void {\n this.updateActiveRun({\n jobId: (this.getCoreState() as VideoDevtoolsCoreState<TOutput>).jobId,\n } as VideoRunPatch<TOutput>)\n this.emitState()\n }\n\n recordVideoStatusChange(): void {\n const core = this.getCoreState() as VideoDevtoolsCoreState<TOutput>\n this.updateActiveRun({\n videoStatus: core.videoStatus,\n preview: this.createVideoPreview(core.result, core.videoStatus),\n } as VideoRunPatch<TOutput>)\n this.emitState()\n }\n\n protected override buildSnapshot(): AIDevtoolsVideoSnapshotBase<TOutput> {\n const core = this.getCoreState() as VideoDevtoolsCoreState<TOutput>\n return {\n input: core.input,\n result: core.result,\n preview: this.createVideoPreview(core.result, core.videoStatus),\n progress: core.progress,\n status: core.status,\n isLoading: core.isLoading,\n activeRunId: this.activeRunId,\n runs: this.devtoolsRuns,\n jobId: core.jobId,\n videoStatus: core.videoStatus,\n ...(core.error ? { error: core.error } : {}),\n }\n }\n\n protected override upsertRun(\n runId: string,\n patch: VideoRunPatch<TOutput>,\n ): void {\n super.upsertRun(runId, patch)\n if (!('jobId' in patch || 'videoStatus' in patch)) return\n\n const index = this.devtoolsRuns.findIndex((run) => run.id === runId)\n if (index < 0) return\n const target = this.devtoolsRuns[index]\n if (!target) return\n const merged: AIDevtoolsGenerationRunSnapshot<TOutput> = { ...target }\n if ('jobId' in patch) merged.jobId = patch.jobId ?? null\n if ('videoStatus' in patch) merged.videoStatus = patch.videoStatus ?? null\n this.devtoolsRuns = this.devtoolsRuns.map((run) =>\n run.id === runId ? merged : run,\n )\n }\n\n // Override so record* methods inherited from GenerationDevtoolsBridge\n // (e.g. recordResultChange) thread the latest videoStatus into the preview.\n protected override createPreview(\n result: TOutput | null,\n ): AIDevtoolsGenerationPreview {\n const core = this.getCoreState() as VideoDevtoolsCoreState<TOutput>\n return this.createVideoPreview(result, core.videoStatus)\n }\n\n private createVideoPreview(\n result: TOutput | null,\n videoStatus: unknown,\n ): AIDevtoolsGenerationPreview {\n return createAIDevtoolsGenerationPreview({\n outputKind: this.options.metadata.outputKind,\n result,\n videoStatus,\n })\n }\n}\n\n// Wraps the plain emitter so callers can do `this.events.X(...)` and get:\n// auto-attached run/thread context on every event that accepts one,\n// an auto-emitted snapshot after each event, and passive streamId tracking\n// so resolveStreamId() works without the chat client telling it.\nclass ChatDevtoolsAwareEventEmitter extends DefaultChatClientEventEmitter {\n constructor(\n clientId: string,\n private readonly helper: ChatDevtoolsBridge,\n ) {\n super(clientId)\n }\n\n private afterEmit(streamId?: string): void {\n if (streamId) this.helper.recordStreamId(streamId)\n this.helper.emitSnapshot()\n }\n\n // -- methods with run context --------------------------------------------\n\n override textUpdated(\n streamId: string,\n messageId: string,\n content: string,\n context?: ChatClientRunEventContext,\n ): void {\n super.textUpdated(\n streamId,\n messageId,\n content,\n context ?? this.helper.getCurrentRunEventContext(),\n )\n this.afterEmit(streamId)\n }\n\n override thinkingUpdated(\n streamId: string,\n messageId: string,\n content: string,\n delta?: string,\n context?: ChatClientRunEventContext,\n ): void {\n super.thinkingUpdated(\n streamId,\n messageId,\n content,\n delta,\n context ?? this.helper.getCurrentRunEventContext(),\n )\n this.afterEmit(streamId)\n }\n\n override messageAppended(\n uiMessage: Parameters<DefaultChatClientEventEmitter['messageAppended']>[0],\n streamId?: string,\n context?: ChatClientEventContext,\n ): void {\n super.messageAppended(\n uiMessage,\n streamId,\n context ?? this.helper.getCurrentRunEventContext(),\n )\n this.afterEmit(streamId)\n }\n\n override toolCallStateChanged(\n streamId: string,\n messageId: string,\n toolCallId: string,\n toolName: string,\n state: string,\n args: string,\n context?: ChatClientRunEventContext,\n ): void {\n super.toolCallStateChanged(\n streamId,\n messageId,\n toolCallId,\n toolName,\n state,\n args,\n context ?? this.helper.getCurrentRunEventContext(),\n )\n this.afterEmit(streamId)\n }\n\n override structuredOutputChanged(\n eventName: Parameters<\n DefaultChatClientEventEmitter['structuredOutputChanged']\n >[0],\n streamId: string,\n messageId: string,\n output: Parameters<\n DefaultChatClientEventEmitter['structuredOutputChanged']\n >[3],\n context?: ChatClientRunEventContext,\n ): void {\n super.structuredOutputChanged(\n eventName,\n streamId,\n messageId,\n output,\n context ?? this.helper.getCurrentOrLastRunEventContext(),\n )\n this.afterEmit(streamId)\n }\n\n override approvalRequested(\n streamId: string,\n messageId: string,\n toolCallId: string,\n toolName: string,\n input: unknown,\n approvalId: string,\n context?: ChatClientRunEventContext,\n ): void {\n super.approvalRequested(\n streamId,\n messageId,\n toolCallId,\n toolName,\n input,\n approvalId,\n context ?? this.helper.getCurrentOrLastRunEventContext(),\n )\n this.afterEmit(streamId)\n }\n\n override toolResultAdded(\n toolCallId: string,\n toolName: string,\n output: unknown,\n state: string,\n context?: ChatClientEventContext,\n ): void {\n super.toolResultAdded(\n toolCallId,\n toolName,\n output,\n state,\n context ?? this.helper.getCurrentRunEventContext(),\n )\n this.afterEmit()\n }\n\n override toolApprovalResponded(\n approvalId: string,\n toolCallId: string,\n approved: boolean,\n context?: ChatClientRunEventContext,\n ): void {\n super.toolApprovalResponded(\n approvalId,\n toolCallId,\n approved,\n context ?? this.helper.getCurrentRunEventContext(),\n )\n this.afterEmit()\n }\n\n // -- methods without context (just auto-emit snapshot) -------------------\n\n override clientCreated(initialMessageCount: number): void {\n super.clientCreated(initialMessageCount)\n this.afterEmit()\n }\n override loadingChanged(isLoading: boolean): void {\n super.loadingChanged(isLoading)\n this.afterEmit()\n }\n override errorChanged(error: string | null): void {\n super.errorChanged(error)\n this.afterEmit()\n }\n override reloaded(fromMessageIndex: number): void {\n super.reloaded(fromMessageIndex)\n this.afterEmit()\n }\n override stopped(): void {\n super.stopped()\n this.afterEmit()\n }\n override messagesCleared(): void {\n super.messagesCleared()\n this.afterEmit()\n }\n override messageSent(\n messageId: string,\n content: Parameters<DefaultChatClientEventEmitter['messageSent']>[1],\n ): void {\n super.messageSent(messageId, content)\n this.afterEmit()\n }\n override toolFixtureApplied(\n fixture: Parameters<DefaultChatClientEventEmitter['toolFixtureApplied']>[0],\n ): void {\n super.toolFixtureApplied(fixture)\n this.afterEmit()\n }\n}\n\nexport function createChatDevtoolsBridge(\n options: ChatDevtoolsBridgeOptions,\n): ChatDevtoolsBridge {\n return new ChatDevtoolsBridge(options)\n}\n\nexport function createGenerationDevtoolsBridge<TOutput>(\n options: GenerationDevtoolsBridgeOptions<TOutput>,\n): GenerationDevtoolsBridge<TOutput> {\n return new GenerationDevtoolsBridge<TOutput>(options)\n}\n\nexport function createVideoDevtoolsBridge<TOutput>(\n options: VideoDevtoolsBridgeOptions<TOutput>,\n): VideoDevtoolsBridge<TOutput> {\n return new VideoDevtoolsBridge<TOutput>(options)\n}\n"],"names":[],"mappings":";;;AAyHO,SAAS,kCACd,OAC6B;AAC7B,MAAI,MAAM,eAAe,SAAS;AAChC,WAAO,uBAAuB,MAAM,MAAM;AAAA,EAC5C;AAEA,MAAI,MAAM,eAAe,SAAS;AAChC,WAAO,uBAAuB,MAAM,MAAM;AAAA,EAC5C;AAEA,MAAI,MAAM,eAAe,SAAS;AAChC,WAAO,uBAAuB,MAAM,QAAQ,MAAM,WAAW;AAAA,EAC/D;AAEA,MAAI,MAAM,eAAe,QAAQ;AAC/B,WAAO,sBAAsB,MAAM,MAAM;AAAA,EAC3C;AAEA,MAAI,MAAM,WAAW,QAAQ,MAAM,WAAW,QAAW;AACvD,WAAO,EAAE,MAAM,QAAA;AAAA,EACjB;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IACN,OAAO,MAAM;AAAA,EAAA;AAEjB;AAIA,SAAS,uBAAuB,QAA8C;AAC5E,QAAM,SAAS,SAAS,MAAM;AAC9B,QAAM,SAAS,MAAM,QAAQ,QAAQ,MAAM,IAAI,OAAO,SAAS,CAAA;AAC/D,QAAM,QAAQ,OACX,IAAI,CAAC,UAAU,oBAAoB,OAAO,WAAW,CAAC,EACtD,OAAO,qBAAqB;AAE/B,MAAI,MAAM,WAAW,KAAK,WAAW,QAAQ,WAAW,QAAW;AACjE,UAAM,aAAa,oBAAoB,QAAQ,WAAW;AAC1D,QAAI,YAAY;AACd,YAAM,KAAK,UAAU;AAAA,IACvB;AAAA,EACF;AAEA,SAAO,EAAE,MAAM,SAAS,MAAA;AAC1B;AAEA,SAAS,uBAAuB,QAA8C;AAC5E,QAAM,SAAS,SAAS,MAAM;AAC9B,QAAM,QAAQ,QAAQ;AACtB,QAAM,oBAAoB,YAAY,QAAQ,aAAa;AAC3D,QAAM,SAAS,YAAY,QAAQ,QAAQ;AAC3C,QAAM,WAAW,qBAAqB,wBAAwB,MAAM;AAEpE,QAAM,QAA8C,CAAA;AACpD,QAAM,aACJ,OAAO,UAAU,WACb,gBAAgB,OAAO,UAAU;AAAA,IAC/B;AAAA,IACA,UAAU,YAAY,QAAQ,UAAU;AAAA,EAAA,CACzC,IACD,oBAAoB,OAAO,UAAU;AAAA,IACnC;AAAA,EAAA,CACD;AAEP,MAAI,YAAY;AACd,UAAM,KAAK,UAAU;AAAA,EACvB;AAEA,SAAO,EAAE,MAAM,SAAS,MAAA;AAC1B;AAEA,SAAS,uBACP,QACA,aAC6B;AAC7B,QAAM,eAAe,SAAS,MAAM;AACpC,QAAM,eAAe,SAAS,WAAW;AACzC,QAAM,OACJ,oBAAoB,QAAQ,WAAW,KACvC,oBAAoB,aAAa,WAAW;AAC9C,QAAM,QAAQ,OAAO,CAAC,IAAI,IAAI,CAAA;AAC9B,QAAM,MAAM,mBAAmB,gBAAgB,YAAY;AAE3D,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,IACA,GAAI,MAAM,EAAE,QAAQ,CAAA;AAAA,EAAC;AAEzB;AAEA,SAAS,sBAAsB,QAA8C;AAC3E,QAAM,SAAS,SAAS,MAAM;AAC9B,QAAM,OACJ,YAAY,QAAQ,MAAM,KAC1B,YAAY,QAAQ,SAAS,KAC7B,YAAY,QAAQ,SAAS,MAC5B,OAAO,WAAW,WAAW,SAAS;AAEzC,MAAI,SAAS,QAAW;AACtB,WAAO,EAAE,MAAM,QAAQ,KAAA;AAAA,EACzB;AAEA,MAAI,WAAW,QAAQ,WAAW,QAAW;AAC3C,WAAO,EAAE,MAAM,QAAA;AAAA,EACjB;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IACN,OAAO;AAAA,EAAA;AAEX;AAEA,SAAS,mBACP,QAC0C;AAC1C,QAAM,QAAQ,YAAY,QAAQ,OAAO;AACzC,MAAI,CAAC,MAAO,QAAO;AAEnB,SAAO;AAAA,IACL;AAAA,IACA,GAAI,YAAY,QAAQ,QAAQ,IAC5B,EAAE,QAAQ,YAAY,QAAQ,QAAQ,EAAA,IACtC,CAAA;AAAA,IACJ,GAAI,YAAY,QAAQ,UAAU,MAAM,SACpC,EAAE,UAAU,YAAY,QAAQ,UAAU,EAAA,IAC1C,CAAA;AAAA,IACJ,GAAI,YAAY,QAAQ,OAAO,IAC3B,EAAE,OAAO,YAAY,QAAQ,OAAO,MACpC,CAAA;AAAA,EAAC;AAET;AAEA,SAAS,oBACP,OACA,iBACA,SAGI,CAAA,GACuC;AAC3C,QAAM,SAAS,SAAS,KAAK;AAC7B,MAAI,CAAC,OAAQ,QAAO;AAEpB,QAAM,sBACJ,YAAY,QAAQ,aAAa,KAAK,YAAY,QAAQ,UAAU;AACtE,QAAM,WAAW,YAAY,QAAQ,UAAU,KAAK,OAAO;AAC3D,QAAM,SAAS,YAAY,QAAQ,QAAQ,KAAK,OAAO;AACvD,QAAM,MAAM,YAAY,QAAQ,KAAK;AACrC,MAAI,KAAK;AACP,WAAO;AAAA,MACL,KAAK;AAAA,MACL,YAAY;AAAA,MACZ,GAAI,sBAAsB,EAAE,UAAU,oBAAA,IAAwB,CAAA;AAAA,MAC9D,GAAI,SAAS,EAAE,OAAA,IAAW,CAAA;AAAA,MAC1B,GAAI,aAAa,SAAY,EAAE,aAAa,CAAA;AAAA,IAAC;AAAA,EAEjD;AAEA,QAAM,UAAU,YAAY,QAAQ,SAAS;AAC7C,MAAI,CAAC,QAAS,QAAO;AAErB,SAAO,gBAAgB,SAAS,uBAAuB,iBAAiB;AAAA,IACtE;AAAA,IACA;AAAA,EAAA,CACD;AACH;AAEA,SAAS,gBACP,OACA,UACA,SAGI,CAAA,GAC2B;AAC/B,QAAM,MAAM,MAAM,WAAW,OAAO,IAChC,QACA,QAAQ,YAAY,0BAA0B,WAAW,KAAK;AAElE,SAAO;AAAA,IACL;AAAA,IACA,YAAY;AAAA,IACZ,GAAI,WAAW,EAAE,SAAA,IAAa,CAAA;AAAA,IAC9B,GAAI,OAAO,SAAS,EAAE,QAAQ,OAAO,OAAA,IAAW,CAAA;AAAA,IAChD,GAAI,OAAO,aAAa,SAAY,EAAE,UAAU,OAAO,aAAa,CAAA;AAAA,EAAC;AAEzE;AAEA,SAAS,wBAAwB,QAAoC;AACnE,MAAI,CAAC,OAAQ,QAAO;AACpB,MAAI,WAAW,MAAO,QAAO;AAC7B,SAAO,SAAS,MAAM;AACxB;AAEA,SAAS,SAAS,OAA2C;AAC3D,MAAI,CAAC,SAAS,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,GAAG;AAC/D,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,SAAS,YACP,QACA,OACoB;AACpB,QAAM,QAAQ,SAAS,KAAK;AAC5B,SAAO,OAAO,UAAU,YAAY,MAAM,SAAS,IAAI,QAAQ;AACjE;AAEA,SAAS,YACP,QACA,OACoB;AACpB,QAAM,QAAQ,SAAS,KAAK;AAC5B,SAAO,OAAO,UAAU,WAAW,QAAQ;AAC7C;AAEA,SAAS,sBACP,OACwC;AACxC,SAAO,QAAQ,KAAK;AACtB;AA4DA,MAAM,0BAA0B,uBAAO;AAAA,EACrC;AACF;AAEA,SAAS,0BAA6D;AACpE,QAAM,SAAS;AAGf,QAAM,WAAW,OAAO,uBAAuB;AAC/C,MAAI,SAAU,QAAO;AAErB,QAAM,+BAAe,IAAA;AACrB,SAAO,uBAAuB,IAAI;AAClC,SAAO;AACT;AAEO,MAAM,qBAA+C;AAAA,EACvC;AAAA,EACF;AAAA,EACA,gBAAoC,CAAA;AAAA,EAC7C,WAAW;AAAA,EACX,aAAa;AAAA,EACb,aAAa;AAAA,EAErB,YAAY,SAA6C;AACvD,SAAK,UAAU;AACf,SAAK,WAAW,eAAe,QAAQ,MAAM;AAAA,EAC/C;AAAA,EAEA,iBAAuB;AACrB,QAAI,CAAC,KAAK,uBAAuB;AAC/B;AAAA,IACF;AACA,SAAK,aAAa;AAClB,wBAAoB,mBAAmB;AAAA,MACrC,GAAG,KAAK,eAAe,iBAAiB;AAAA,MACxC,GAAG,KAAK,sBAAA;AAAA,MACR,WAAW;AAAA,IAAA,CACZ;AAAA,EACH;AAAA,EAEA,cAAoB;AAClB,QAAI,CAAC,KAAK,kBAAkB;AAC1B;AAAA,IACF;AACA,wBAAoB,gBAAgB;AAAA,MAClC,GAAG,KAAK,eAAe,cAAc;AAAA,MACrC,GAAG,KAAK,sBAAA;AAAA,MACR,WAAW;AAAA,IAAA,CACZ;AAAA,EACH;AAAA,EAEA,eAAqB;AACnB,QAAI,CAAC,KAAK,kBAAkB;AAC1B;AAAA,IACF;AACA,wBAAoB,uBAAuB;AAAA,MACzC,GAAG,KAAK,eAAe,qBAAqB;AAAA,MAC5C,GAAG,KAAK,sBAAA;AAAA;AAAA;AAAA;AAAA,MAIR,OAAO,KAAK,QAAQ,YAAA;AAAA,IAAY,CACjC;AAAA,EACH;AAAA,EAEA,sBAA4B;AAC1B,QAAI,CAAC,KAAK,kBAAkB;AAC1B;AAAA,IACF;AACA,UAAM,QAAQ,KAAK,QAAQ,WACvB,MAAM,KAAK,KAAK,QAAQ,SAAA,CAAU,EAAE,IAAI,CAAC,UAAU;AAAA,MACjD,MAAM,KAAK;AAAA,MACX,aAAa,KAAK;AAAA,MAClB,aAAa,KAAK,cACd,0BAA0B,KAAK,WAAW,IAC1C,EAAE,MAAM,SAAA;AAAA,MACZ,cAAc,KAAK,eACf,0BAA0B,KAAK,YAAY,IAC3C;AAAA,MACJ,eAAe,KAAK;AAAA,MACpB,UAAU,KAAK;AAAA,IAAA,EACf,IACF,CAAA;AAEJ,wBAAoB,oBAAoB;AAAA,MACtC,GAAG,KAAK,eAAe,kBAAkB;AAAA,MACzC,GAAG,KAAK,sBAAA;AAAA,MACR;AAAA,IAAA,CACD;AAAA,EACH;AAAA,EAEA,iBACE,WACA,OACA,QACA,UAA8B,CAAA,GACxB;AACN,QAAI,CAAC,KAAK,kBAAkB;AAC1B;AAAA,IACF;AACA,wBAAoB,WAAW;AAAA,MAC7B,GAAG,KAAK,eAAe,WAAW,gBAAgB,EAAE,OAAO;AAAA,MAC3D;AAAA,MACA;AAAA,MACA,GAAI,QAAQ,QAAQ,EAAE,OAAO,QAAQ,MAAA,IAAU,CAAA;AAAA,IAAC,CACjD;AAAA,EACH;AAAA,EAEA,aAAmB;AACjB,UAAM,uBAAuB,wBAAA;AAC7B,QAAI,qBAAqB,IAAI,KAAK,QAAQ,MAAM,MAAM,MAAM;AAC1D,2BAAqB,OAAO,KAAK,QAAQ,MAAM;AAAA,IACjD;AAEA,eAAW,eAAe,KAAK,cAAc,OAAO,CAAC,GAAG;AACtD,kBAAA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,YAAkB;AAChB,QAAI,KAAK,UAAU;AACjB;AAAA,IACF;AAEA,SAAK,aAAa;AAClB,SAAK,WAAW;AAChB,SAAK,WAAA;AAAA,EACP;AAAA,EAEA,UAAgB;AACd,QAAI,KAAK,UAAU;AACjB;AAAA,IACF;AAEA,SAAK,WAAW;AAChB,QAAI,CAAC,KAAK,YAAY;AACpB,WAAK,WAAA;AACL;AAAA,IACF;AAEA,UAAM,UAAU;AAAA,MACd,GAAG,KAAK,eAAe,mBAAmB;AAAA,MAC1C,GAAG,KAAK,sBAAA;AAAA,MACR,QAAQ;AAAA,IAAA;AAGV,wBAAoB,qBAAqB,OAAO;AAEhD,SAAK,WAAA;AAAA,EACP;AAAA,EAEQ,iBAA0B;AAChC,QAAI,KAAK,YAAY,KAAK,YAAY;AACpC,aAAO;AAAA,IACT;AACA,SAAK,SAAA;AACL,WAAO;AAAA,EACT;AAAA,EAEQ,sBAA+B;AACrC,QAAI,KAAK,YAAY;AACnB,aAAO;AAAA,IACT;AAEA,QAAI,KAAK,UAAU;AACjB,WAAK,WAAW;AAChB,WAAK,aAAa;AAAA,IACpB;AAEA,SAAK,SAAA;AACL,WAAO;AAAA,EACT;AAAA,EAEQ,WAAiB;AACvB,QAAI,KAAK,UAAU;AACjB;AAAA,IACF;AAEA,UAAM,uBAAuB,wBAAA;AAC7B,UAAM,eAAe,qBAAqB,IAAI,KAAK,QAAQ,MAAM;AACjE,QAAI,gBAAgB,iBAAiB,MAAM;AACzC,UAAI,OAAO,aAAa,cAAc,YAAY;AAChD,qBAAa,UAAA;AAAA,MACf,OAAO;AACL,qBAAa,WAAA;AAAA,MACf;AAAA,IACF;AACA,yBAAqB,IAAI,KAAK,QAAQ,QAAQ,IAAI;AAElD,QAAI,KAAK,cAAc,SAAS,GAAG;AACjC;AAAA,IACF;AAEA,SAAK,cAAc;AAAA,MACjB,cAAc,GAAG,0BAA0B,CAAC,UAAU;AACpD,aAAK,mBAAmB,KAAK;AAAA,MAC/B,CAAC;AAAA,IAAA;AAGH,QAAI,KAAK,QAAQ,kBAAkB;AACjC,WAAK,cAAc;AAAA,QACjB,cAAc,GAAG,+BAA+B,CAAC,UAAU;AACzD,eAAK,KAAK,uBAAuB,KAAK;AAAA,QACxC,CAAC;AAAA,MAAA;AAAA,IAEL;AAAA,EACF;AAAA,EAEQ,mBACN,OACM;AACN,QAAI,KAAK,YAAY,KAAK,YAAY;AACpC;AAAA,IACF;AAEA,UAAM,eAAe,MAAM,QAAQ;AACnC,QAAI,gBAAgB,iBAAiB,KAAK,QAAQ,QAAQ;AACxD;AAAA,IACF;AAEA,SAAK,eAAA;AACL,SAAK,oBAAA;AACL,SAAK,aAAA;AAAA,EACP;AAAA,EAEA,MAAc,uBACZ,OACe;AACf,UAAM,UAAU,MAAM;AACtB,QAAI,CAAC,KAAK,qBAAqB,OAAO,GAAG;AACvC;AAAA,IACF;AAEA,UAAM,KAAK,QAAQ,mBAAmB,OAAO;AAAA,EAC/C;AAAA,EAEQ,qBAAqB,SAAyC;AACpE,QAAI,CAAC,QAAQ,UAAU,CAAC,QAAQ,UAAU;AACxC,aAAO;AAAA,IACT;AAEA,QAAI,QAAQ,QAAQ;AAClB,aAAO,QAAQ,WAAW,KAAK,QAAQ;AAAA,IACzC;AAEA,QACE,QAAQ,aACP,CAAC,KAAK,QAAQ,YAAY,QAAQ,aAAa,KAAK,QAAQ,WAC7D;AACA,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,eACN,WAOA,aAAwC,gBACxC,UAA8B,CAAA,GAC9B;AACA,WAAO,8BAA8B;AAAA,MACnC;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,MACA,UAAU,KAAK,QAAQ;AAAA,MACvB,QAAQ,KAAK,QAAQ;AAAA,MACrB,eAAe,KAAK;AAAA,MACpB,GAAI,KAAK,QAAQ,WAAW,EAAE,UAAU,KAAK,QAAQ,SAAA,IAAa,CAAA;AAAA,MAClE,GAAI,QAAQ,QAAQ,EAAE,OAAO,QAAQ,MAAA,IAAU,CAAA;AAAA,MAC/C,WAAW,KAAK,IAAA;AAAA,IAAI,CACrB;AAAA,EACH;AAAA,EAEQ,wBAAwB;AAC9B,WAAO;AAAA,MACL,QAAQ,KAAK,QAAQ;AAAA,MACrB,UAAU,KAAK,QAAQ,SAAS;AAAA,MAChC,GAAI,KAAK,QAAQ,SAAS,OACtB,EAAE,aAAa,KAAK,QAAQ,SAAS,KAAA,IACrC,CAAA;AAAA,MACJ,GAAI,KAAK,QAAQ,SAAS,aACtB,EAAE,YAAY,KAAK,QAAQ,SAAS,WAAA,IACpC,CAAA;AAAA,MACJ,GAAI,KAAK,QAAQ,SAAS,YACtB,EAAE,WAAW,KAAK,QAAQ,SAAS,cACnC,CAAA;AAAA,IAAC;AAAA,EAET;AACF;AAEA,IAAI,mBAAmB;AAEvB,SAAS,eAAe,QAAwB;AAC9C,QAAM,aACJ,WAKA;AAEF,MAAI,YAAY,YAAY;AAC1B,WAAO,UAAU,MAAM,IAAI,WAAW,YAAY;AAAA,EACpD;AAEA,sBAAoB;AACpB,SAAO,UAAU,MAAM,IAAI,gBAAgB;AAC7C;AAiBO,MAAM,2BAA2B,qBAA6C;AAAA,EAC1E;AAAA,EACQ;AAAA,EACT,eAA8B;AAAA,EAC9B,qBAAoC;AAAA,EACpC,kBAAiC;AAAA,EACjC,eAA8B;AAAA,EAC9B;AAAA,EAER,YAAY,SAAoC;AAC9C,UAAM;AAAA,MACJ,GAAG;AAAA;AAAA,MAEH,kBAAkB,CAAC,YAAY,KAAK,aAAa,OAAO;AAAA,IAAA,CACzD;AACD,SAAK,cAAc;AAGnB,SAAK,SAAS,IAAI,8BAA8B,QAAQ,UAAU,IAAI;AAAA,EACxE;AAAA;AAAA,EAIA,mBAAmB,UAA+B;AAChD,SAAK,kBAAkB;AACvB,QAAI,UAAU;AACZ,WAAK,eAAe;AAAA,IACtB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,eAAe,UAAwB;AACrC,QAAI,eAAe,eAAe;AAAA,EACpC;AAAA,EAEA,eAAe,qBAAmC;AAChD,SAAK,OAAO,cAAc,mBAAmB;AAC7C,SAAK,eAAA;AACL,SAAK,oBAAA;AACL,SAAK,aAAA;AAAA,EACP;AAAA,EAEA,qBAA2B;AACzB,SAAK,oBAAA;AACL,SAAK,aAAA;AAAA,EACP;AAAA,EAEA,qBAAoC;AAClC,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,kBAAiC;AAC/B,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,kBAA0B;AACxB,WACE,KAAK,mBACL,KAAK,gBACL,KAAK,YAAY,WAAW,QAAQ;AAAA,EAExC;AAAA;AAAA;AAAA;AAAA,EAKA,SAAS,OAAe,UAAwB;AAC9C,SAAK,eAAe;AACpB,SAAK,qBAAqB;AAC1B,SAAK,sBAAsB,EAAE,OAAO,SAAA;AAAA,EACtC;AAAA,EAEA,aAAa,OAA0B;AACrC,QAAI,MAAM,SAAS,eAAe;AAChC,WAAK,SAAS,MAAM,OAAO,MAAM,QAAQ;AACzC;AAAA,IACF;AAEA,QAAI,MAAM,SAAS,kBAAkB,MAAM,SAAS,aAAa;AAC/D,YAAM,QACJ,MAAM,SAAS,iBACX,MAAM,QACL,MAA6B;AACpC,UAAI,CAAC,SAAS,UAAU,KAAK,cAAc;AACzC,cAAM,UAAU,KAAK,0BAAA;AACrB,YAAI,SAAS;AACX,eAAK,sBAAsB;AAAA,QAC7B;AACA,aAAK,eAAe;AACpB,aAAK,qBAAqB;AAAA,MAC5B;AAAA,IACF;AAAA,EACF;AAAA,EAEA,4BAAmE;AACjE,QAAI,CAAC,KAAK,aAAc,QAAO;AAC/B,WAAO;AAAA,MACL,UAAU,KAAK,sBAAsB,KAAK,YAAY,YAAY;AAAA,MAClE,OAAO,KAAK;AAAA,IAAA;AAAA,EAEhB;AAAA,EAEA,kCAAyE;AACvE,WAAO,KAAK,+BAA+B,KAAK;AAAA,EAClD;AAAA,EAEA,oBAAoB,YAA4C;AAC9D,UAAM,OAA+B,EAAE,WAAA;AACvC,UAAM,aAAa,KAAK,0BAAA;AACxB,QAAI,YAAY;AACd,aAAO;AAAA,QACL,UAAU,WAAW;AAAA,QACrB,OAAO,WAAW;AAAA,QAClB;AAAA,MAAA;AAAA,IAEJ;AACA,QAAI,KAAK,YAAY,UAAU;AAC7B,aAAO,EAAE,UAAU,KAAK,YAAY,UAAU,WAAA;AAAA,IAChD;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,aAAa,SAA+C;AAChE,UAAM,WAAW,KAAK,YAAY,YAAA;AAClC,UAAM,WAAW,QAAQ,YAAY,KAAK,YAAY,YAAY;AAClE,QAAI,QAAQ,SAAS;AACnB,YAAM,KAAK,eAAe,SAAS,UAAU,QAAQ;AACrD;AAAA,IACF;AAEA,UAAM,SAAS,KAAK,+BAA+B,SAAS,QAAQ;AACpE,UAAM,EAAE,SAAS,WAAA,IAAe;AAChC,UAAM,YAAY,QAAQ;AAE1B,SAAK,OAAO,gBAAgB,SAAS,QAAW;AAAA,MAC9C;AAAA,MACA;AAAA,MACA,GAAI,QAAQ,QAAQ,EAAE,OAAO,QAAQ,MAAA,IAAU,CAAA;AAAA,IAAC,CACjD;AACD,SAAK,YAAY,YAAY,CAAC,GAAG,UAAU,OAAO,CAAC;AACnD,SAAK,OAAO,mBAAmB;AAAA,MAC7B,QAAQ,KAAK,YAAY;AAAA,MACzB;AAAA,MACA,GAAI,QAAQ,QAAQ,EAAE,OAAO,QAAQ,MAAA,IAAU,CAAA;AAAA,MAC/C,UAAU,QAAQ;AAAA,MAClB,OAAO,QAAQ;AAAA,MACf,QAAQ,QAAQ;AAAA,MAChB;AAAA,MACA;AAAA,MACA,GAAI,QAAQ,YAAY,SAAY,EAAE,SAAS,QAAQ,QAAA,IAAY,CAAA;AAAA,MACnE,GAAI,QAAQ,UAAU,EAAE,SAAS,QAAQ,QAAA,IAAY,CAAA;AAAA,MACrD,GAAI,QAAQ,YAAY,EAAE,WAAW,QAAQ,UAAA,IAAc,CAAA;AAAA,IAAC,CAC7D;AACD,SAAK,aAAA;AAAA,EACP;AAAA,EAEA,MAAc,eACZ,SACA,UACA,UACe;AACf,UAAM,aAAa,KAAK;AAAA,MACtB,QAAQ;AAAA,MACR;AAAA,IAAA;AAEF,UAAM,YAAY,KAAK,wBAAwB,QAAQ,WAAW,QAAQ;AAC1E,UAAM,UAAqB;AAAA,MACzB,IAAI;AAAA,MACJ,MAAM;AAAA,MACN,OAAO;AAAA,QACL;AAAA,UACE,MAAM;AAAA,UACN,IAAI;AAAA,UACJ,MAAM,QAAQ;AAAA,UACd,WAAW,sBAAsB,QAAQ,KAAK;AAAA,UAC9C,OAAO,QAAQ;AAAA,UACf,OAAO;AAAA,QAAA;AAAA,MACT;AAAA,MAEF,+BAAe,KAAA;AAAA,IAAK;AAGtB,SAAK,OAAO,gBAAgB,SAAS,QAAW;AAAA,MAC9C;AAAA,MACA;AAAA,MACA,GAAI,QAAQ,QAAQ,EAAE,OAAO,QAAQ,MAAA,IAAU,CAAA;AAAA,IAAC,CACjD;AACD,SAAK,YAAY,YAAY,CAAC,GAAG,UAAU,OAAO,CAAC;AACnD,SAAK,aAAA;AAEL,UAAM,aAAa,KAAK,eAAe,QAAQ,QAAQ;AACvD,UAAM,cAAc,YAAY;AAChC,QAAI,CAAC,aAAa;AAChB,cAAQ;AAAA,QACN,+BAA+B,QAAQ,QAAQ;AAAA,MAAA;AAEjD,WAAK,wBAAwB;AAAA,QAC3B;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,QAAQ,QAAQ;AAAA,QAChB,WAAW,QAAQ;AAAA,MAAA,CACpB;AACD;AAAA,IACF;AAEA,QAAI;AACJ,QAAI;AACF,eAAS,MAAM,YAAY,QAAQ,KAAK;AAAA,IAC1C,SAAS,OAAO;AACd,cAAQ;AAAA,QACN,+BAA+B,QAAQ,QAAQ;AAAA,QAC/C;AAAA,MAAA;AAEF,WAAK,wBAAwB;AAAA,QAC3B;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,QAAQ;AAAA,QACR,WACE,iBAAiB,QACb,GAAG,MAAM,IAAI,KAAK,MAAM,OAAO,KAC/B,0BAA0B,OAAO,KAAK,CAAC;AAAA,MAAA,CAC9C;AACD;AAAA,IACF;AACA,SAAK,wBAAwB;AAAA,MAC3B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA,CACD;AAAA,EACH;AAAA,EAEQ,wBAAwB,OAOvB;AACP,UAAM,QAAQ,MAAM,YAAY,iBAAiB;AACjD,SAAK,OAAO;AAAA,MACV,MAAM;AAAA,MACN,MAAM,QAAQ;AAAA,MACd,MAAM;AAAA,MACN;AAAA,MACA;AAAA,QACE,UAAU,MAAM;AAAA,QAChB,GAAI,MAAM,QAAQ,QAAQ,EAAE,OAAO,MAAM,QAAQ,MAAA,IAAU,CAAA;AAAA,QAC3D,YAAY,MAAM;AAAA,MAAA;AAAA,IACpB;AAEF,SAAK,YAAY;AAAA,MACf,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM;AAAA,IAAA;AAER,SAAK,OAAO,mBAAmB;AAAA,MAC7B,QAAQ,KAAK,YAAY;AAAA,MACzB,UAAU,MAAM;AAAA,MAChB,GAAI,MAAM,QAAQ,QAAQ,EAAE,OAAO,MAAM,QAAQ,MAAA,IAAU,CAAA;AAAA,MAC3D,UAAU,MAAM,QAAQ;AAAA,MACxB,OAAO,MAAM,QAAQ;AAAA,MACrB,QAAQ,MAAM;AAAA,MACd,SAAS;AAAA,MACT,WAAW,MAAM;AAAA,MACjB,YAAY,MAAM;AAAA,MAClB,GAAI,MAAM,YAAY,EAAE,WAAW,MAAM,UAAA,IAAc,CAAA;AAAA,IAAC,CACzD;AACD,SAAK,aAAA;AAAA,EACP;AAAA,EAEQ,+BACN,SACA,UAC4C;AAC5C,UAAM,SAAS,KAAK,0BAA0B,SAAS,QAAQ;AAC/D,QAAI,OAAQ,QAAO;AAEnB,UAAM,aAAa,KAAK;AAAA,MACtB,QAAQ;AAAA,MACR;AAAA,IAAA;AAEF,UAAM,YAAY,KAAK,wBAAwB,QAAQ,WAAW,QAAQ;AAC1E,UAAM,QAAQ,QAAQ,YAAY,UAAU;AAE5C,WAAO;AAAA,MACL;AAAA,MACA,SAAS;AAAA,QACP,IAAI;AAAA,QACJ,MAAM;AAAA,QACN,OAAO;AAAA,UACL;AAAA,YACE,MAAM;AAAA,YACN,IAAI;AAAA,YACJ,MAAM,QAAQ;AAAA,YACd,WAAW,sBAAsB,QAAQ,KAAK;AAAA,YAC9C,OAAO,QAAQ;AAAA,YACf,OAAO;AAAA,YACP,QAAQ,QAAQ;AAAA,UAAA;AAAA,UAElB;AAAA,YACE,MAAM;AAAA,YACN;AAAA,YACA,SAAS,sBAAsB,QAAQ,MAAM;AAAA,YAC7C;AAAA,YACA,GAAI,QAAQ,YAAY,EAAE,OAAO,QAAQ,UAAA,IAAc,CAAA;AAAA,UAAC;AAAA,QAC1D;AAAA,QAEF,+BAAe,KAAA;AAAA,MAAK;AAAA,IACtB;AAAA,EAEJ;AAAA,EAEQ,0BACN,SACA,UACwD;AACxD,UAAM,gBAAgB,QAAQ;AAC9B,QAAI,CAAC,iBAAiB,CAAC,MAAM,QAAQ,cAAc,KAAK,GAAG;AACzD,aAAO;AAAA,IACT;AAEA,UAAM,cAAc,KAAK;AAAA,MACvB,cAAc;AAAA,MACd;AAAA,IAAA;AAEF,UAAM,QAAQ,cAAc,MACzB,IAAI,CAAC,SAAS,wBAAwB,MAAM,WAAW,CAAC,EACxD,OAAO,CAAC,SAA8B,QAAQ,IAAI,CAAC;AACtD,UAAM,0BAA0B,QAAQ,aACpC,YAAY,IAAI,QAAQ,UAAU,IAClC;AACJ,2BAAuB,OAAO;AAAA,MAC5B,GAAI,0BACA,EAAE,kBAAkB,wBAAA,IACpB,CAAA;AAAA,MACJ,QAAQ,QAAQ;AAAA,IAAA,CACjB;AAED,QAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,UAAM,cACH,QAAQ,aAAa,YAAY,IAAI,QAAQ,UAAU,IAAI,WAC5D,gBAAgB,KAAK;AACvB,QAAI,CAAC,WAAY,QAAO;AAExB,WAAO;AAAA,MACL;AAAA,MACA,SAAS;AAAA,QACP,IAAI,KAAK,wBAAwB,cAAc,IAAI,QAAQ;AAAA,QAC3D,MAAM,cAAc;AAAA,QACpB;AAAA,QACA,+BAAe,KAAA;AAAA,MAAK;AAAA,IACtB;AAAA,EAEJ;AAAA,EAEQ,2BACN,OACA,UACqB;AACrB,UAAM,0BAAU,IAAA;AAChB,eAAW,QAAQ,OAAO;AACxB,UAAI,CAAC,SAAS,IAAI,KAAK,KAAK,SAAS,YAAa;AAClD,UAAI,OAAO,KAAK,OAAO,SAAU;AACjC,UAAI,IAAI,KAAK,IAAI,KAAK,yBAAyB,KAAK,IAAI,QAAQ,CAAC;AAAA,IACnE;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,wBACN,WACA,UACQ;AACR,QAAI,aAAa,CAAC,SAAS,KAAK,CAAC,YAAY,QAAQ,OAAO,SAAS,GAAG;AACtE,aAAO;AAAA,IACT;AACA,WAAO,KAAK,YAAY,WAAW,aAAa;AAAA,EAClD;AAAA,EAEQ,yBACN,YACA,UACQ;AACR,QAAI,cAAc,CAAC,cAAc,UAAU,UAAU,GAAG;AACtD,aAAO;AAAA,IACT;AACA,WAAO,KAAK,YAAY,WAAW,mBAAmB;AAAA,EACxD;AAAA,EAEQ,eAAe,MAAyC;AAC9D,UAAM,QAAQ,KAAK,YAAY,WAAA;AAC/B,QAAI,CAAC,MAAO,QAAO;AACnB,eAAW,QAAQ,OAAO;AACxB,UAAI,KAAK,SAAS,KAAM,QAAO;AAAA,IACjC;AACA,WAAO;AAAA,EACT;AACF;AAIA,SAAS,SAAS,OAAkD;AAClE,SAAO,OAAO,UAAU,YAAY,UAAU;AAChD;AAEA,SAAS,sBAAsB,OAAwB;AACrD,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,MACE,UAAU,UACV,OAAO,UAAU,cACjB,OAAO,UAAU,UACjB;AACA,WAAO,OAAO,KAAK;AAAA,EACrB;AACA,MAAI;AACF,WAAO,KAAK,UAAU,KAAK;AAAA,EAC7B,SAAS,OAAO;AACd,YAAQ;AAAA,MACN;AAAA,MACA,EAAE,OAAO,MAAA;AAAA,IAAM;AAEjB,WAAO,OAAO,KAAK;AAAA,EACrB;AACF;AAEA,SAAS,0BAA0B,SAA0B;AAC3D,MAAI;AACF,WAAO,KAAK,MAAM,OAAO;AAAA,EAC3B,SAAS,OAAO;AACd,YAAQ;AAAA,MACN;AAAA,MACA,EAAE,OAAO,QAAA;AAAA,IAAQ;AAEnB,WAAO;AAAA,EACT;AACF;AAEA,SAAS,wBACP,MACA,aACyB;AACzB,MAAI,CAAC,SAAS,IAAI,KAAK,OAAO,KAAK,SAAS,SAAU,QAAO;AAC7D,QAAM,SAAkC,EAAE,GAAG,KAAA;AAE7C,MAAI,KAAK,SAAS,eAAe,OAAO,KAAK,OAAO,UAAU;AAC5D,WAAO,KAAK,YAAY,IAAI,KAAK,EAAE,KAAK,KAAK;AAAA,EAC/C;AACA,MAAI,KAAK,SAAS,iBAAiB,OAAO,KAAK,eAAe,UAAU;AACtE,WAAO,aAAa,YAAY,IAAI,KAAK,UAAU,KAAK,KAAK;AAAA,EAC/D;AACA,SAAO;AACT;AAEA,SAAS,gBAAgB,OAA+C;AACtE,QAAM,WAAW,MAAM,KAAK,CAAC,SAAS,KAAK,SAAS,WAAW;AAC/D,SAAO,UAAU,SAAS,cAAc,SAAS,KAAK;AACxD;AAEA,SAAS,uBACP,OACA,eACM;AACN,aAAW,QAAQ,OAAO;AACxB,QAAI,KAAK,SAAS,cAAe;AACjC,UAAM,WAAW,MAAM;AAAA,MACrB,CAAC,cACC,UAAU,SAAS,eACnB,UAAU,OAAO,KAAK,cACtB,UAAU,WAAW;AAAA,IAAA;AAEzB,QAAI,UAAU;AACZ,eAAS,SAAS,MAAM,QAAQ,KAAK,OAAO,IACxC,KAAK,UACL,0BAA0B,KAAK,OAAO;AAAA,IAC5C;AAAA,EACF;AAEA,MAAI,cAAc,oBAAoB,cAAc,WAAW,QAAW;AACxE,UAAM,WAAW,MAAM;AAAA,MACrB,CAAC,cACC,UAAU,SAAS,eACnB,UAAU,OAAO,cAAc,oBAC/B,UAAU,WAAW;AAAA,IAAA;AAEzB,QAAI,UAAU;AACZ,eAAS,SAAS,cAAc;AAAA,IAClC;AAAA,EACF;AACF;AAEA,SAAS,cACP,UACA,YACS;AACT,SAAO,SAAS;AAAA,IAAK,CAAC,YACpB,QAAQ,MAAM,KAAK,CAAC,SAAS;AAC3B,UAAI,KAAK,SAAS,YAAa,QAAO,KAAK,OAAO;AAClD,UAAI,KAAK,SAAS,cAAe,QAAO,KAAK,eAAe;AAC5D,aAAO;AAAA,IACT,CAAC;AAAA,EAAA;AAEL;AA+CO,MAAM,iCAA0C,qBAErD;AAAA,EACU,cAA6B;AAAA,EAC7B,mBAAmB;AAAA,EACnB,eAAgE,CAAA;AAAA,EACvD;AAAA,EACA;AAAA,EAEnB,YAAY,SAAmD;AAC7D,UAAM;AAAA,MACJ,GAAG;AAAA,MACH,aAAa,MAAM,KAAK,cAAA;AAAA,IAAc,CACvC;AACD,SAAK,UAAU,QAAQ,WAAW;AAClC,SAAK,eAAe,QAAQ;AAAA,EAC9B;AAAA;AAAA,EAIA,SAAS,OAAwB;AAC/B,UAAM,QAAQ,KAAK,cAAA;AACnB,SAAK,cAAc;AACnB,SAAK,mBAAmB;AACxB,SAAK,UAAU,OAAO;AAAA,MACpB;AAAA,MACA,QAAQ;AAAA,MACR,SAAS,KAAK,cAAc,IAAI;AAAA,MAChC,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,YAAY;AAAA,IAAA,CACb;AACD,WAAO;AAAA,EACT;AAAA,EAEA,iBAAiB,OAAqB;AACpC,QAAI,KAAK,oBAAoB,KAAK,gBAAgB,MAAO;AAEzD,QACE,CAAC,KAAK,oBACN,KAAK,eACL,KAAK,gBAAgB,OACrB;AACA,WAAK,UAAU,KAAK,aAAa,KAAK;AAAA,IACxC;AAEA,SAAK,cAAc;AACnB,SAAK,mBAAmB;AACxB,SAAK,UAAU,OAAO;AAAA,MACpB,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,YAAY;AAAA,IAAA,CACb;AACD,SAAK,iBAAiB,eAAe,OAAO,SAAS;AACrD,SAAK,UAAA;AAAA,EACP;AAAA,EAEA,UACE,OACA,WACA,QACA,OACM;AACN,SAAK,iBAAiB,KAAK;AAC3B,UAAM,cAAc,KAAK,IAAA;AACzB,UAAM,oBACJ,WAAW,cAAc,KAAK,iBAAA,IAAqB,KAAK,YAAA;AAC1D,UAAM,YACJ,WAAW,cACP,YACA,WAAW,YACT,UACA;AAER,SAAK,UAAU,OAAO;AAAA,MACpB,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,UAAU;AAAA,MACV;AAAA,MACA,GAAI,QAAQ,EAAE,UAAU,EAAE,YAAY,KAAA;AAAA,IAAK,CAC5C;AAED,QAAI,KAAK,gBAAgB,OAAO;AAC9B,WAAK,cAAc;AAAA,IACrB;AACA,SAAK,mBAAmB;AACxB,SAAK,iBAAiB,WAAW,OAAO,QAAQ;AAAA,MAC9C,GAAI,QAAQ,EAAE,UAAU,CAAA;AAAA,IAAC,CAC1B;AACD,SAAK,UAAA;AAAA,EACP;AAAA,EAEA,iBAAgC;AAC9B,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAGA,YAAkB;AAChB,SAAK,cAAc;AACnB,SAAK,mBAAmB;AACxB,SAAK,eAAe,CAAA;AAAA,EACtB;AAAA;AAAA,EAGA,qBAA2B;AACzB,SAAK,gBAAgB;AAAA,MACnB,QAAQ,KAAK,aAAA,EAAe;AAAA,MAC5B,SAAS,KAAK,cAAc,KAAK,aAAA,EAAe,MAAM;AAAA,MACtD,YAAY;AAAA,IAAA,CACb;AACD,SAAK,UAAA;AAAA,EACP;AAAA,EAEA,sBAA4B;AAC1B,SAAK,gBAAgB,EAAE,WAAW,KAAK,aAAA,EAAe,WAAW;AACjE,SAAK,UAAA;AAAA,EACP;AAAA,EAEA,kBAAkB,OAAgC;AAChD,SAAK;AAAA,MACH,QAAQ,EAAE,OAAO,MAAM,YAAY,EAAE,YAAY,KAAA;AAAA,IAAK;AAExD,SAAK,UAAA;AAAA,EACP;AAAA,EAEA,mBAAmB,QAA6C;AAC9D,SAAK,gBAAgB,EAAE,QAAQ;AAC/B,SAAK,UAAA;AAAA,EACP;AAAA,EAEA,uBAA6B;AAC3B,SAAK,gBAAgB,EAAE,UAAU,KAAK,aAAA,EAAe,UAAU;AAC/D,SAAK,UAAA;AAAA,EACP;AAAA;AAAA,EAGA,YAAkB;AAChB,SAAK,YAAA;AACL,SAAK,aAAA;AAAA,EACP;AAAA;AAAA,EAIU,gBAA2D;AACnE,UAAM,OAAO,KAAK,aAAA;AAClB,WAAO;AAAA,MACL,OAAO,KAAK;AAAA,MACZ,QAAQ,KAAK;AAAA,MACb,SAAS,KAAK,cAAc,KAAK,MAAM;AAAA,MACvC,UAAU,KAAK;AAAA,MACf,QAAQ,KAAK;AAAA,MACb,WAAW,KAAK;AAAA,MAChB,aAAa,KAAK;AAAA,MAClB,MAAM,KAAK;AAAA,MACX,GAAI,KAAK,QAAQ,EAAE,OAAO,KAAK,MAAA,IAAU,CAAA;AAAA,IAAC;AAAA,EAE9C;AAAA,EAEU,gBAAgB,OAA0C;AAClE,QAAI,CAAC,KAAK,YAAa;AACvB,SAAK,UAAU,KAAK,aAAa,KAAK;AAAA,EACxC;AAAA,EAEU,UAAU,OAAe,OAA0C;AAC3E,UAAM,MAAM,KAAK,IAAA;AACjB,UAAM,QAAQ,KAAK,aAAa,UAAU,CAAC,QAAQ,IAAI,OAAO,KAAK;AACnE,UAAM,WAAW,SAAS,IAAI,KAAK,aAAa,KAAK,IAAI;AACzD,UAAM,OAAiD,WACnD,EAAE,GAAG,aACL;AAAA,MACE,IAAI;AAAA,MACJ,OAAO,KAAK,aAAA,EAAe;AAAA,MAC3B,QAAQ;AAAA,MACR,SAAS,KAAK,cAAc,IAAI;AAAA,MAChC,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,WAAW;AAAA,MACX,WAAW;AAAA,IAAA;AAGjB,QAAI,WAAW,MAAO,MAAK,QAAQ,MAAM,SAAS;AAClD,QAAI,YAAY,MAAO,MAAK,SAAS,MAAM,UAAU;AACrD,QAAI,MAAM,QAAS,MAAK,UAAU,MAAM;AACxC,QAAI,cAAc,MAAO,MAAK,WAAW,MAAM,YAAY;AAC3D,QAAI,MAAM,OAAQ,MAAK,SAAS,MAAM;AACtC,QAAI,eAAe,MAAO,MAAK,YAAY,MAAM,cAAc;AAC/D,QAAI,MAAM,gBAAgB,OAAW,MAAK,cAAc,MAAM;AAC9D,QAAI,MAAM,WAAY,QAAO,KAAK;AAClC,QAAI,MAAM,UAAU,OAAW,MAAK,QAAQ,MAAM;AAClD,SAAK,YAAY;AAEjB,QAAI,SAAS,GAAG;AACd,WAAK,eAAe,KAAK,aAAa;AAAA,QAAI,CAAC,QACzC,IAAI,OAAO,QAAQ,OAAO;AAAA,MAAA;AAAA,IAE9B,OAAO;AACL,WAAK,eAAe,CAAC,GAAG,KAAK,cAAc,IAAI;AAAA,IACjD;AAEA,QAAI,KAAK,aAAa,SAAS,KAAK,SAAS;AAC3C,WAAK,eAAe,KAAK,aAAa,MAAM,CAAC,KAAK,OAAO;AAAA,IAC3D;AAAA,EACF;AAAA,EAEU,UAAU,eAAuB,WAAyB;AAClE,QAAI,kBAAkB,UAAW;AAEjC,UAAM,WAAW,KAAK,aAAa,KAAK,CAAC,QAAQ,IAAI,OAAO,aAAa;AACzE,QAAI,CAAC,SAAU;AAEf,UAAM,UAAU,EAAE,GAAG,UAAU,IAAI,WAAW,WAAW,KAAK,MAAI;AAClE,SAAK,eAAe,KAAK,aACtB,OAAO,CAAC,QAAQ,IAAI,OAAO,SAAS,EACpC,IAAI,CAAC,QAAS,IAAI,OAAO,gBAAgB,UAAU,GAAI;AAAA,EAC5D;AAAA,EAEU,cAAmD;AAC3D,WAAO,KAAK,eAAe;AAAA,EAC7B;AAAA,EAEU,mBAAwD;AAChE,UAAM,WAAW,KAAK,aAAA,EAAe;AACrC,QAAI,CAAC,SAAU,QAAO;AACtB,WAAO;AAAA,MACL,OAAO;AAAA,MACP,GAAI,SAAS,UAAU,EAAE,SAAS,SAAS,QAAA,IAAY,CAAA;AAAA,IAAC;AAAA,EAE5D;AAAA,EAEU,cAAc,QAAqD;AAC3E,WAAO,kCAAkC;AAAA,MACvC,YAAY,KAAK,QAAQ,SAAS;AAAA,MAClC;AAAA,IAAA,CACD;AAAA,EACH;AAAA,EAEU,gBAAwB;AAChC,WAAO,OAAO,KAAK,IAAA,CAAK,IAAI,KAAK,OAAA,EAAS,SAAS,EAAE,EAAE,UAAU,CAAC,CAAC;AAAA,EACrE;AACF;AAgCO,MAAM,4BAEH,yBAAkC;AAAA,EAC1C,YAAY,SAA8C;AACxD,UAAM,OAAO;AAAA,EACf;AAAA,EAEA,oBAA0B;AACxB,SAAK,gBAAgB;AAAA,MACnB,OAAQ,KAAK,eAAmD;AAAA,IAAA,CACvC;AAC3B,SAAK,UAAA;AAAA,EACP;AAAA,EAEA,0BAAgC;AAC9B,UAAM,OAAO,KAAK,aAAA;AAClB,SAAK,gBAAgB;AAAA,MACnB,aAAa,KAAK;AAAA,MAClB,SAAS,KAAK,mBAAmB,KAAK,QAAQ,KAAK,WAAW;AAAA,IAAA,CACrC;AAC3B,SAAK,UAAA;AAAA,EACP;AAAA,EAEmB,gBAAsD;AACvE,UAAM,OAAO,KAAK,aAAA;AAClB,WAAO;AAAA,MACL,OAAO,KAAK;AAAA,MACZ,QAAQ,KAAK;AAAA,MACb,SAAS,KAAK,mBAAmB,KAAK,QAAQ,KAAK,WAAW;AAAA,MAC9D,UAAU,KAAK;AAAA,MACf,QAAQ,KAAK;AAAA,MACb,WAAW,KAAK;AAAA,MAChB,aAAa,KAAK;AAAA,MAClB,MAAM,KAAK;AAAA,MACX,OAAO,KAAK;AAAA,MACZ,aAAa,KAAK;AAAA,MAClB,GAAI,KAAK,QAAQ,EAAE,OAAO,KAAK,MAAA,IAAU,CAAA;AAAA,IAAC;AAAA,EAE9C;AAAA,EAEmB,UACjB,OACA,OACM;AACN,UAAM,UAAU,OAAO,KAAK;AAC5B,QAAI,EAAE,WAAW,SAAS,iBAAiB,OAAQ;AAEnD,UAAM,QAAQ,KAAK,aAAa,UAAU,CAAC,QAAQ,IAAI,OAAO,KAAK;AACnE,QAAI,QAAQ,EAAG;AACf,UAAM,SAAS,KAAK,aAAa,KAAK;AACtC,QAAI,CAAC,OAAQ;AACb,UAAM,SAAmD,EAAE,GAAG,OAAA;AAC9D,QAAI,WAAW,MAAO,QAAO,QAAQ,MAAM,SAAS;AACpD,QAAI,iBAAiB,MAAO,QAAO,cAAc,MAAM,eAAe;AACtE,SAAK,eAAe,KAAK,aAAa;AAAA,MAAI,CAAC,QACzC,IAAI,OAAO,QAAQ,SAAS;AAAA,IAAA;AAAA,EAEhC;AAAA;AAAA;AAAA,EAImB,cACjB,QAC6B;AAC7B,UAAM,OAAO,KAAK,aAAA;AAClB,WAAO,KAAK,mBAAmB,QAAQ,KAAK,WAAW;AAAA,EACzD;AAAA,EAEQ,mBACN,QACA,aAC6B;AAC7B,WAAO,kCAAkC;AAAA,MACvC,YAAY,KAAK,QAAQ,SAAS;AAAA,MAClC;AAAA,MACA;AAAA,IAAA,CACD;AAAA,EACH;AACF;AAMA,MAAM,sCAAsC,8BAA8B;AAAA,EACxE,YACE,UACiB,QACjB;AACA,UAAM,QAAQ;AAFG,SAAA,SAAA;AAAA,EAGnB;AAAA,EAHmB;AAAA,EAKX,UAAU,UAAyB;AACzC,QAAI,SAAU,MAAK,OAAO,eAAe,QAAQ;AACjD,SAAK,OAAO,aAAA;AAAA,EACd;AAAA;AAAA,EAIS,YACP,UACA,WACA,SACA,SACM;AACN,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA,WAAW,KAAK,OAAO,0BAAA;AAAA,IAA0B;AAEnD,SAAK,UAAU,QAAQ;AAAA,EACzB;AAAA,EAES,gBACP,UACA,WACA,SACA,OACA,SACM;AACN,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,WAAW,KAAK,OAAO,0BAAA;AAAA,IAA0B;AAEnD,SAAK,UAAU,QAAQ;AAAA,EACzB;AAAA,EAES,gBACP,WACA,UACA,SACM;AACN,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA,WAAW,KAAK,OAAO,0BAAA;AAAA,IAA0B;AAEnD,SAAK,UAAU,QAAQ;AAAA,EACzB;AAAA,EAES,qBACP,UACA,WACA,YACA,UACA,OACA,MACA,SACM;AACN,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,WAAW,KAAK,OAAO,0BAAA;AAAA,IAA0B;AAEnD,SAAK,UAAU,QAAQ;AAAA,EACzB;AAAA,EAES,wBACP,WAGA,UACA,WACA,QAGA,SACM;AACN,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,WAAW,KAAK,OAAO,gCAAA;AAAA,IAAgC;AAEzD,SAAK,UAAU,QAAQ;AAAA,EACzB;AAAA,EAES,kBACP,UACA,WACA,YACA,UACA,OACA,YACA,SACM;AACN,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,WAAW,KAAK,OAAO,gCAAA;AAAA,IAAgC;AAEzD,SAAK,UAAU,QAAQ;AAAA,EACzB;AAAA,EAES,gBACP,YACA,UACA,QACA,OACA,SACM;AACN,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,WAAW,KAAK,OAAO,0BAAA;AAAA,IAA0B;AAEnD,SAAK,UAAA;AAAA,EACP;AAAA,EAES,sBACP,YACA,YACA,UACA,SACM;AACN,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA,WAAW,KAAK,OAAO,0BAAA;AAAA,IAA0B;AAEnD,SAAK,UAAA;AAAA,EACP;AAAA;AAAA,EAIS,cAAc,qBAAmC;AACxD,UAAM,cAAc,mBAAmB;AACvC,SAAK,UAAA;AAAA,EACP;AAAA,EACS,eAAe,WAA0B;AAChD,UAAM,eAAe,SAAS;AAC9B,SAAK,UAAA;AAAA,EACP;AAAA,EACS,aAAa,OAA4B;AAChD,UAAM,aAAa,KAAK;AACxB,SAAK,UAAA;AAAA,EACP;AAAA,EACS,SAAS,kBAAgC;AAChD,UAAM,SAAS,gBAAgB;AAC/B,SAAK,UAAA;AAAA,EACP;AAAA,EACS,UAAgB;AACvB,UAAM,QAAA;AACN,SAAK,UAAA;AAAA,EACP;AAAA,EACS,kBAAwB;AAC/B,UAAM,gBAAA;AACN,SAAK,UAAA;AAAA,EACP;AAAA,EACS,YACP,WACA,SACM;AACN,UAAM,YAAY,WAAW,OAAO;AACpC,SAAK,UAAA;AAAA,EACP;AAAA,EACS,mBACP,SACM;AACN,UAAM,mBAAmB,OAAO;AAChC,SAAK,UAAA;AAAA,EACP;AACF;AAEO,SAAS,yBACd,SACoB;AACpB,SAAO,IAAI,mBAAmB,OAAO;AACvC;AAEO,SAAS,+BACd,SACmC;AACnC,SAAO,IAAI,yBAAkC,OAAO;AACtD;AAEO,SAAS,0BACd,SAC8B;AAC9B,SAAO,IAAI,oBAA6B,OAAO;AACjD;"}
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ export type { McpAppBridge, CreateMcpAppBridgeOptions } from './mcp-app-bridge.j
|
|
|
6
6
|
export { RealtimeClient } from './realtime-client.js';
|
|
7
7
|
export { GenerationClient } from './generation-client.js';
|
|
8
8
|
export { VideoGenerationClient } from './video-generation-client.js';
|
|
9
|
-
export type { UIMessage, MessagePart, TextPart, ToolCallPart, ToolResultPart, ThinkingPart, StructuredOutputPart, ChatClientPersistence, ChatClientOptions, ClientContextOptionFromTools, ChatRequestBody, InferChatMessages, InferredClientContext, ChatClientState, ConnectionStatus, ChatFetcher, ChatFetcherInput, ChatFetcherOptions, ChatTransport, DistributedOmit, MultimodalContent, } from './types.js';
|
|
9
|
+
export type { UIMessage, MessagePart, TextPart, ToolCallPart, ToolResultPart, ThinkingPart, StructuredOutputPart, ChatClientPersistence, ChatClientOptions, ClientContextOptionFromTools, ChatRequestBody, InferChatMessages, InferredClientContext, ChatClientState, ConnectionStatus, ChatFetcher, ChatFetcherInput, ChatFetcherOptions, ChatTransport, DistributedOmit, MultimodalContent, QueuedMessage, WhenBusy, QueueBusyReason, QueueConfig, QueueStrategy, QueueOption, SendMessageOptions, } from './types.js';
|
|
10
10
|
export type { InferGenerationOutput, InferGenerationOutputFromReturn, GenerationClientState, GenerationClientOptions, GenerationFetcher, GenerationFetcherOptions, GenerationTransport, VideoGenerationClientOptions, VideoStatusInfo, VideoGenerateResult, ImageGenerateInput, AudioGenerateInput, SpeechGenerateInput, TranscriptionGenerateInput, SummarizeGenerateInput, VideoGenerateInput, } from './generation-types.js';
|
|
11
11
|
export { GENERATION_EVENTS } from './generation-types.js';
|
|
12
12
|
export { UnsupportedResponseStreamError } from './response-stream.js';
|
package/dist/esm/types.d.ts
CHANGED
|
@@ -99,6 +99,83 @@ export interface MultimodalContent {
|
|
|
99
99
|
*/
|
|
100
100
|
id?: string;
|
|
101
101
|
}
|
|
102
|
+
/**
|
|
103
|
+
* Action taken when `sendMessage` is called while the client is busy
|
|
104
|
+
* (streaming, claiming a send, or draining the queue).
|
|
105
|
+
* - `queue`: hold the message; it auto-sends when the current run settles
|
|
106
|
+
* **successfully**.
|
|
107
|
+
* - `drop`: ignore the send (promise still resolves; does not throw).
|
|
108
|
+
* - `interrupt`: abort the current stream and send immediately. Unlike
|
|
109
|
+
* `stop()`, does **not** flush already-queued messages — they still drain
|
|
110
|
+
* after the interrupting send settles successfully.
|
|
111
|
+
*/
|
|
112
|
+
export type WhenBusy = 'queue' | 'drop' | 'interrupt';
|
|
113
|
+
/**
|
|
114
|
+
* Why the client is busy when a {@link QueueStrategy} runs.
|
|
115
|
+
* - `streaming` — an LLM stream is active (`isLoading`).
|
|
116
|
+
* - `sendInFlight` — a send has claimed the client but is not yet loading.
|
|
117
|
+
* - `draining` — the queue drain loop is delivering pending messages.
|
|
118
|
+
*/
|
|
119
|
+
export type QueueBusyReason = 'streaming' | 'sendInFlight' | 'draining';
|
|
120
|
+
/**
|
|
121
|
+
* A user message held in the send queue while a stream is active.
|
|
122
|
+
* Rendered separately from `messages`; cancellable via `cancelQueued(id)`
|
|
123
|
+
* until it drains.
|
|
124
|
+
*/
|
|
125
|
+
export interface QueuedMessage {
|
|
126
|
+
id: string;
|
|
127
|
+
content: string | MultimodalContent;
|
|
128
|
+
createdAt: number;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Declarative queue policy.
|
|
132
|
+
*/
|
|
133
|
+
export interface QueueConfig {
|
|
134
|
+
/**
|
|
135
|
+
* Action when the client is busy (streaming, claiming a send, or draining).
|
|
136
|
+
* Default `'queue'`.
|
|
137
|
+
*/
|
|
138
|
+
whenBusy?: WhenBusy;
|
|
139
|
+
/**
|
|
140
|
+
* How queued items leave the queue.
|
|
141
|
+
* - `'fifo'`: one at a time, in order (default).
|
|
142
|
+
* - `'batch'`: merge all queued items into one send when the run settles
|
|
143
|
+
* successfully.
|
|
144
|
+
*/
|
|
145
|
+
drain?: 'fifo' | 'batch';
|
|
146
|
+
/** Max queued items. Unlimited when omitted. `0` means never queue. */
|
|
147
|
+
maxSize?: number;
|
|
148
|
+
/**
|
|
149
|
+
* Behavior when `maxSize` is reached. Default `'reject'`.
|
|
150
|
+
* `'reject'` silently discards the new send (does not throw);
|
|
151
|
+
* `'drop-oldest'` evicts the oldest queued item to make room.
|
|
152
|
+
* Only meaningful when `maxSize` is set.
|
|
153
|
+
*/
|
|
154
|
+
onOverflow?: 'reject' | 'drop-oldest';
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Escape hatch: decide the action for a single send. Drain stays FIFO for the
|
|
158
|
+
* function form (no `batch` via function). Per-call `sendOptions.whenBusy`
|
|
159
|
+
* overrides the strategy for that send.
|
|
160
|
+
*
|
|
161
|
+
* Actions match {@link WhenBusy}: `'queue' | 'drop' | 'interrupt'`. Concurrent
|
|
162
|
+
* streams are not supported. `pending.id` is the id that will be stored if the
|
|
163
|
+
* action is `'queue'` (safe to pass to `cancelQueued`).
|
|
164
|
+
*/
|
|
165
|
+
export type QueueStrategy = (ctx: {
|
|
166
|
+
pending: QueuedMessage;
|
|
167
|
+
busyReason: QueueBusyReason;
|
|
168
|
+
queued: ReadonlyArray<QueuedMessage>;
|
|
169
|
+
}) => {
|
|
170
|
+
action: WhenBusy;
|
|
171
|
+
};
|
|
172
|
+
/** A `WhenBusy` shorthand, a full config, or a strategy function. */
|
|
173
|
+
export type QueueOption = WhenBusy | QueueConfig | QueueStrategy;
|
|
174
|
+
/** Per-call overrides for `sendMessage`. */
|
|
175
|
+
export interface SendMessageOptions {
|
|
176
|
+
/** Overrides the configured `whenBusy` for this one send. */
|
|
177
|
+
whenBusy?: WhenBusy;
|
|
178
|
+
}
|
|
102
179
|
/**
|
|
103
180
|
* Message parts - building blocks of UIMessage
|
|
104
181
|
*/
|
|
@@ -328,6 +405,21 @@ export interface ChatClientBaseOptions<TTools extends ReadonlyArray<AnyClientToo
|
|
|
328
405
|
* activity visible to all subscribers (e.g. across tabs/devices).
|
|
329
406
|
*/
|
|
330
407
|
onSessionGeneratingChange?: (isGenerating: boolean) => void;
|
|
408
|
+
/**
|
|
409
|
+
* Policy for messages sent while the client is busy (streaming, claiming
|
|
410
|
+
* a send, or draining the queue). Accepts a `WhenBusy` string, a
|
|
411
|
+
* `QueueConfig`, or a `QueueStrategy` function.
|
|
412
|
+
* Default: `{ whenBusy: 'queue', drain: 'fifo' }`.
|
|
413
|
+
* Queued items auto-send only after a **successful** settle; they are
|
|
414
|
+
* discarded on error/abort, `stop()`, `clear()`, `unsubscribe()`, and
|
|
415
|
+
* `reload()`.
|
|
416
|
+
*/
|
|
417
|
+
queue?: QueueOption;
|
|
418
|
+
/**
|
|
419
|
+
* Callback when the pending send queue changes (enqueue, cancel, drain,
|
|
420
|
+
* or flush).
|
|
421
|
+
*/
|
|
422
|
+
onQueueChange?: (queue: Array<QueuedMessage>) => void;
|
|
331
423
|
/**
|
|
332
424
|
* Callback when a custom event is received from a server-side tool.
|
|
333
425
|
* Custom events are emitted by tools using `context.emitCustomEvent()` during execution.
|
package/dist/esm/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sources":["../../src/types.ts"],"sourcesContent":["import type {\n AnyClientTool,\n AudioPart,\n ChunkStrategy,\n ContentPart,\n DocumentPart,\n ImagePart,\n InferToolInput,\n InferToolOutput,\n ModelMessage,\n StreamChunk,\n StructuredOutputPart,\n UIResourcePart,\n VideoPart,\n} from '@tanstack/ai/client'\nimport type { ConnectionAdapter } from './connection-adapters'\nimport type { AIDevtoolsClientMetadata } from './devtools'\nimport type { ChatDevtoolsBridgeFactory } from './devtools-noop'\n\nexport type { StructuredOutputPart } from '@tanstack/ai/client'\n\n/**\n * `messages` is the full UIMessage history (not a delta). `data` is the\n * merged body — `ChatClientOptions.body` plus any per-call data passed to\n * `sendMessage(...)`. `threadId` / `runId` are the AG-UI correlation ids\n * the chat client uses to track this turn — forward them to your server\n * if it needs to correlate requests.\n */\nexport interface ChatFetcherInput {\n messages: Array<UIMessage>\n data?: Record<string, unknown>\n threadId: string\n runId: string\n}\n\nexport interface ChatFetcherOptions {\n /** Fires when `stop()` is called or the request is superseded. */\n signal: AbortSignal\n}\n\n/**\n * Direct function that performs a chat request. Mirrors\n * `GenerationFetcher`. Returns either a `Response` (SSE body parsed by the\n * chat client) or an `AsyncIterable<StreamChunk>` (yielded directly). May\n * return the value synchronously, as a `Promise`, or as an async generator\n * (`async function*`) — the chat client awaits whichever shape is returned.\n *\n * @example\n * ```ts\n * useChat({\n * fetcher: ({ messages }, { signal }) =>\n * chatFn({ data: { messages }, signal }),\n * })\n * ```\n */\nexport type ChatFetcher = (\n input: ChatFetcherInput,\n options: ChatFetcherOptions,\n) =>\n | Response\n | AsyncIterable<StreamChunk>\n | Promise<Response | AsyncIterable<StreamChunk>>\n\n/**\n * Distributive `Omit` — applies `Omit<O, K>` per branch of a union so\n * discriminated unions survive omission. Plain `Omit` collapses unions\n * into a single object shape, which would erase the `ChatTransport` XOR\n * when framework hooks omit React-managed callbacks from\n * `ChatClientOptions`.\n */\nexport type DistributedOmit<\n TObject,\n TKeys extends keyof any,\n> = TObject extends unknown ? Omit<TObject, TKeys> : never\n\n/**\n * Discriminated union enforcing that exactly one of `connection` or\n * `fetcher` is provided. Mirrors `GenerationTransport`.\n */\nexport type ChatTransport =\n | { connection: ConnectionAdapter; fetcher?: never }\n | { fetcher: ChatFetcher; connection?: never }\n\n/**\n * Tool call states - track the lifecycle of a tool call\n */\nexport type ToolCallState =\n | 'awaiting-input' // Received start but no arguments yet\n | 'input-streaming' // Partial arguments received\n | 'input-complete' // All arguments received\n | 'approval-requested' // Waiting for user approval\n | 'approval-responded' // User has approved/denied\n | 'complete' // Result is complete\n | 'error' // Tool execution failed (terminal)\n\n/**\n * Tool result states - track the lifecycle of a tool result\n */\nexport type ToolResultState =\n | 'streaming' // Placeholder for future streamed output\n | 'complete' // Result is complete\n | 'error' // Error occurred\n\n/**\n * ChatClient state - track the lifecycle of a chat\n */\nexport type ChatClientState = 'ready' | 'submitted' | 'streaming' | 'error'\n\n/**\n * Connection lifecycle state for the subscription loop.\n */\nexport type ConnectionStatus =\n | 'disconnected'\n | 'connecting'\n | 'connected'\n | 'error'\n\n/**\n * Multimodal content input for sending messages with rich media.\n * Allows sending text, images, audio, video, and documents to the LLM.\n *\n * @example\n * ```ts\n * // Send an image with a question\n * client.sendMessage({\n * content: [\n * { type: 'text', content: 'What is in this image?' },\n * { type: 'image', source: { type: 'url', value: 'https://example.com/photo.jpg' } }\n * ],\n * id: 'custom-message-id' // optional\n * })\n * ```\n */\nexport interface MultimodalContent {\n /**\n * The content of the message.\n * Can be a simple string or an array of content parts for multimodal messages.\n */\n content: string | Array<ContentPart>\n /**\n * Optional custom ID for the message.\n * If not provided, a unique ID will be generated.\n */\n id?: string\n}\n\n/**\n * Message parts - building blocks of UIMessage\n */\nexport interface TextPart {\n type: 'text'\n content: string\n}\n\n/**\n * Helper type that creates a tool-call part for a specific tool.\n * This is a conditional type to enable proper distribution over union types,\n * creating a discriminated union where `name` is the discriminant.\n */\ntype ToolCallPartForTool<T> = T extends AnyClientTool\n ? {\n type: 'tool-call'\n id: string\n name: T['name']\n arguments: string // JSON string (may be incomplete)\n /** Parsed tool input (typed from inputSchema) */\n input?: InferToolInput<T>\n state: ToolCallState\n /** Tool execution output (for client tools or after approval) */\n output?: InferToolOutput<T>\n } & (NonNullable<T['needsApproval']> extends true\n ? {\n /**\n * Approval metadata — present only on tools defined with\n * `needsApproval: true`. Populated once the call reaches\n * `state: 'approval-requested'`. `needsApproval` is an optional\n * property on the tool, so we index into it (rather than\n * `T extends { needsApproval: true }`, which an optional property\n * never satisfies) and strip `undefined` before comparing to `true`.\n */\n approval?: {\n id: string // Unique approval ID\n needsApproval: boolean // Always true if present\n approved?: boolean // User's decision (undefined until responded)\n }\n }\n : // Tools without `needsApproval: true` never carry an approval field.\n // `& unknown` is a no-op intersection (adds nothing).\n unknown)\n : never\n\n/**\n * Fallback tool-call part type when tools are not typed\n */\ntype UntypedToolCallPart = {\n type: 'tool-call'\n id: string\n name: string\n arguments: string\n input?: any\n state: ToolCallState\n approval?: {\n id: string\n needsApproval: boolean\n approved?: boolean\n }\n output?: any\n}\n\n/**\n * Tool call part that creates a proper discriminated union.\n * When TTools is typed, checking `part.name === 'toolName'` will narrow\n * `part.output` to the correct type for that tool.\n *\n * The discriminant is `name`, so code like:\n * ```ts\n * if (part.name === 'recommendGuitar') {\n * // part.output is now typed to the recommendGuitar tool's output\n * }\n * ```\n */\nexport type ToolCallPart<TTools extends ReadonlyArray<AnyClientTool> = any> =\n // Check if we have a concrete tools array (not 'any' or 'never')\n [TTools] extends [never]\n ? UntypedToolCallPart\n : unknown extends TTools\n ? UntypedToolCallPart\n : TTools extends ReadonlyArray<infer Tool>\n ? Tool extends AnyClientTool\n ? ToolCallPartForTool<Tool>\n : UntypedToolCallPart\n : UntypedToolCallPart\n\nexport interface ToolResultPart {\n type: 'tool-result'\n toolCallId: string\n content: string | Array<ContentPart>\n state: ToolResultState\n error?: string // Error message if state is \"error\"\n}\n\nexport interface ThinkingPart {\n type: 'thinking'\n content: string\n}\n\nexport type MessagePart<\n TTools extends ReadonlyArray<AnyClientTool> = any,\n TData = unknown,\n> =\n | TextPart\n | ImagePart\n | AudioPart\n | VideoPart\n | DocumentPart\n | ToolCallPart<TTools>\n | ToolResultPart\n | ThinkingPart\n | StructuredOutputPart<TData>\n | UIResourcePart\n\n/**\n * UIMessage - Domain-specific message format optimized for building chat UIs\n * Contains parts that can be text, tool calls, or tool results.\n *\n * `TTools` narrows the tool-call/result part types based on the registered\n * tools. `TData` is the schema-inferred type for any `structured-output` part\n * on the message — defaulted to `unknown` so untyped consumers (the core\n * stream processor, the wire converter) don't need to thread a schema generic\n * everywhere; the hook layer (`useChat({ outputSchema })`) substitutes it on\n * the public return so `m.parts.find(p => p.type === 'structured-output').data`\n * is typed without manual casts.\n */\nexport interface UIMessage<\n TTools extends ReadonlyArray<AnyClientTool> = any,\n TData = unknown,\n> {\n id: string\n role: 'system' | 'user' | 'assistant'\n parts: Array<MessagePart<TTools, TData>>\n createdAt?: Date\n}\n\nexport interface ChatClientPersistence<\n TTools extends ReadonlyArray<AnyClientTool> = any,\n> {\n getItem: (\n id: string,\n ) =>\n | Array<UIMessage<TTools>>\n | null\n | undefined\n | Promise<Array<UIMessage<TTools>> | null | undefined>\n setItem: (\n id: string,\n messages: Array<UIMessage<TTools>>,\n ) => void | Promise<void>\n removeItem: (id: string) => void | Promise<void>\n}\n\ntype IsUnknown<T> = unknown extends T\n ? [T] extends [unknown]\n ? true\n : false\n : false\n\ntype KnownContext<T> = IsUnknown<T> extends true ? never : T\n\ntype MergeContext<TLeft, TRight> = [TLeft] extends [never]\n ? TRight\n : [TRight] extends [never]\n ? TLeft\n : TLeft & TRight\n\ntype UnionToIntersection<T> = [T] extends [never]\n ? never\n : (T extends unknown ? (value: T) => void : never) extends (\n value: infer TIntersection,\n ) => void\n ? TIntersection\n : never\n\ntype DefinedContext<T> = Exclude<T, undefined>\n\ntype ContextFromExecute<T> = T extends (...args: any) => any\n ? NonNullable<Parameters<T>[1]> extends { context: infer TContext }\n ? KnownContext<TContext>\n : never\n : never\n\ntype ContextFromClientTool<T> = T extends AnyClientTool\n ? T extends { execute?: infer TExecute }\n ? ContextFromExecute<TExecute>\n : never\n : never\n\ntype RequiredContextFromClientToolUnion<T> = T extends unknown\n ? undefined extends ContextFromClientTool<T>\n ? never\n : ContextFromClientTool<T>\n : never\n\ntype ContextFromClientToolUnion<T> = [\n UnionToIntersection<DefinedContext<ContextFromClientTool<T>>>,\n] extends [never]\n ? never\n : [RequiredContextFromClientToolUnion<T>] extends [never]\n ? UnionToIntersection<DefinedContext<ContextFromClientTool<T>>> | undefined\n : UnionToIntersection<DefinedContext<ContextFromClientTool<T>>>\n\ntype ContextFromClientTools<TTools> =\n IsUnknown<TTools> extends true\n ? never\n : TTools extends readonly [infer THead, ...infer TTail]\n ? MergeContext<\n ContextFromClientTool<THead>,\n ContextFromClientTools<TTail>\n >\n : TTools extends ReadonlyArray<infer TItem>\n ? ContextFromClientToolUnion<TItem>\n : never\n\nexport type InferredClientContext<TTools> = [\n ContextFromClientTools<TTools>,\n] extends [never]\n ? unknown\n : ContextFromClientTools<TTools>\n\nexport type ClientContextOptionFromTools<TTools, TContext> = [\n ContextFromClientTools<TTools>,\n] extends [never]\n ? { context?: TContext }\n : undefined extends ContextFromClientTools<TTools>\n ? { context?: TContext & ContextFromClientTools<TTools> }\n : { context: TContext & ContextFromClientTools<TTools> }\n\n/**\n * Base options for `ChatClient`, excluding the transport (`connection` or\n * `fetcher`) which is supplied separately via `ChatTransport` so the XOR\n * is preserved when composing the final `ChatClientOptions` type.\n */\nexport interface ChatClientBaseOptions<\n TTools extends ReadonlyArray<AnyClientTool> = any,\n TContext = unknown,\n> {\n /**\n * Initial messages to populate the chat\n */\n initialMessages?: Array<UIMessage<TTools>>\n\n /**\n * Optional persistence adapter for chat messages.\n */\n persistence?: ChatClientPersistence<TTools>\n\n /**\n * Unique identifier for this chat instance\n * Used for managing multiple chats\n */\n id?: string\n\n /**\n * Thread ID to use for this chat session. Persists across sends within\n * the session. If omitted, a unique thread ID is generated.\n */\n threadId?: string\n\n /**\n * Arbitrary client-controlled JSON forwarded to the server in the\n * AG-UI `RunAgentInput.forwardedProps` field. Use this for per-session\n * options like provider/model selection or feature flags that the\n * server endpoint should read.\n *\n * Replaces the legacy `body` option. If both are provided,\n * `forwardedProps` wins on key collision.\n */\n forwardedProps?: Record<string, any>\n\n /**\n * @deprecated Use `forwardedProps` instead. `body` continues to work\n * unchanged — its values are merged into the AG-UI\n * `RunAgentInput.forwardedProps` field on the wire and are also\n * mirrored under the legacy `data` field for servers that have not\n * migrated yet. Will be removed in a future major release.\n */\n body?: Record<string, any>\n\n /**\n * Client-local runtime context passed to client tool implementations.\n *\n * This value is not serialized to the server. Use `forwardedProps` for\n * explicit client-to-server handoff of serializable values.\n */\n context?: TContext\n\n /**\n * Callback when a response is received\n */\n onResponse?: (response?: Response) => void | Promise<void>\n\n /**\n * Callback when a stream chunk is received\n */\n onChunk?: (chunk: StreamChunk) => void\n\n /**\n * Callback when the response is finished\n */\n onFinish?: (message: UIMessage<TTools>) => void\n\n /**\n * Callback when an error occurs\n */\n onError?: (error: Error) => void\n\n /**\n * Callback when messages change\n */\n onMessagesChange?: (messages: Array<UIMessage<TTools>>) => void\n\n /**\n * Callback when loading state changes\n */\n onLoadingChange?: (isLoading: boolean) => void\n\n /**\n * Callback when error state changes\n */\n onErrorChange?: (error: Error | undefined) => void\n\n /**\n * Callback when chat status changes\n */\n onStatusChange?: (status: ChatClientState) => void\n\n /**\n * Callback when subscription lifecycle changes.\n * This is independent from request lifecycle (`isLoading`, `status`).\n */\n onSubscriptionChange?: (isSubscribed: boolean) => void\n\n /**\n * Callback when connection lifecycle changes.\n */\n onConnectionStatusChange?: (status: ConnectionStatus) => void\n\n /**\n * Callback when session generation activity changes.\n * Derived from stream run events (RUN_STARTED / RUN_FINISHED / RUN_ERROR).\n * Unlike `onLoadingChange` (request-local), this reflects shared generation\n * activity visible to all subscribers (e.g. across tabs/devices).\n */\n onSessionGeneratingChange?: (isGenerating: boolean) => void\n\n /**\n * Callback when a custom event is received from a server-side tool.\n * Custom events are emitted by tools using `context.emitCustomEvent()` during execution.\n *\n * @param eventType - The name of the custom event\n * @param data - The event payload data\n * @param context - Additional context including the toolCallId that emitted the event\n */\n onCustomEvent?: (\n eventType: string,\n data: unknown,\n context: { toolCallId?: string },\n ) => void\n\n /**\n * Client-side tools with execution logic\n * When provided, tools with execute functions will be called automatically\n */\n tools?: TTools\n\n /**\n * Devtools hook metadata for this client instance.\n */\n devtools?: Partial<AIDevtoolsClientMetadata>\n\n /**\n * Factory that constructs the devtools bridge. Default is a no-op\n * factory, which keeps `@tanstack/ai-client/devtools` (the heavy\n * bridge implementation) out of the main entry's bundle. Frameworks\n * that need live devtools should pass the real factory from\n * `@tanstack/ai-client/devtools`.\n */\n devtoolsBridgeFactory?: ChatDevtoolsBridgeFactory\n\n /**\n * Stream processing options (optional)\n * Configure chunking strategy\n */\n streamProcessor?: {\n /**\n * Strategy for when to emit text updates\n * Defaults to ImmediateStrategy (every chunk)\n */\n chunkStrategy?: ChunkStrategy\n }\n}\n\n/**\n * Options for `ChatClient`. Exactly one of `connection` or `fetcher` must be\n * provided — the type-level XOR is enforced via `ChatTransport`.\n */\nexport type ChatClientOptions<\n TTools extends ReadonlyArray<AnyClientTool> = any,\n TContext = InferredClientContext<TTools>,\n> = DistributedOmit<ChatClientBaseOptions<TTools, TContext>, 'context'> &\n ClientContextOptionFromTools<TTools, TContext> &\n ChatTransport\n\nexport interface ChatRequestBody {\n messages: Array<ModelMessage>\n data?: Record<string, any>\n}\n\n/**\n * Create a typed array of client tools with proper type inference.\n * This eliminates the need for `as const` when defining tool arrays.\n *\n * @example\n * ```ts\n * const tools = clientTools(\n * myTool1.client(() => result1),\n * myTool2.client(() => result2),\n * )\n *\n * // tools is now properly typed as a tuple with literal tool names\n * // This enables type narrowing when checking part.name === 'toolName'\n * ```\n */\nexport function clientTools<const T extends Array<AnyClientTool>>(\n ...tools: T\n): T {\n return tools\n}\n\n/**\n * Helper to create typed chat client options\n * Use this to get proper type inference for messages\n *\n * @example\n * ```ts\n * const tools = clientTools(myTool1, myTool2)\n *\n * const chatOptions = createChatClientOptions({\n * connection: fetchServerSentEvents('/api/chat'),\n * tools,\n * })\n *\n * type MyMessages = InferChatMessages<typeof chatOptions>\n * ```\n */\nexport function createChatClientOptions<\n const TTools extends ReadonlyArray<AnyClientTool>,\n TContext = InferredClientContext<TTools>,\n>(\n options: ChatClientOptions<TTools, TContext>,\n): ChatClientOptions<TTools, TContext> {\n return options\n}\n\n/**\n * Extract the message type from chat options\n *\n * @example\n * ```ts\n * const chatOptions = createChatClientOptions({\n * connection: fetchServerSentEvents('/api/chat'),\n * tools: [myTool1, myTool2],\n * })\n *\n * type MyMessages = InferChatMessages<typeof chatOptions>\n * // MyMessages is now Array<UIMessage<[typeof myTool1, typeof myTool2]>>\n * ```\n */\nexport type InferChatMessages<T> =\n T extends ChatClientOptions<infer TTools, any>\n ? Array<UIMessage<TTools>>\n : never\n"],"names":[],"mappings":"AA4jBO,SAAS,eACX,OACA;AACH,SAAO;AACT;AAkBO,SAAS,wBAId,SACqC;AACrC,SAAO;AACT;"}
|
|
1
|
+
{"version":3,"file":"types.js","sources":["../../src/types.ts"],"sourcesContent":["import type {\n AnyClientTool,\n AudioPart,\n ChunkStrategy,\n ContentPart,\n DocumentPart,\n ImagePart,\n InferToolInput,\n InferToolOutput,\n ModelMessage,\n StreamChunk,\n StructuredOutputPart,\n UIResourcePart,\n VideoPart,\n} from '@tanstack/ai/client'\nimport type { ConnectionAdapter } from './connection-adapters'\nimport type { AIDevtoolsClientMetadata } from './devtools'\nimport type { ChatDevtoolsBridgeFactory } from './devtools-noop'\n\nexport type { StructuredOutputPart } from '@tanstack/ai/client'\n\n/**\n * `messages` is the full UIMessage history (not a delta). `data` is the\n * merged body — `ChatClientOptions.body` plus any per-call data passed to\n * `sendMessage(...)`. `threadId` / `runId` are the AG-UI correlation ids\n * the chat client uses to track this turn — forward them to your server\n * if it needs to correlate requests.\n */\nexport interface ChatFetcherInput {\n messages: Array<UIMessage>\n data?: Record<string, unknown>\n threadId: string\n runId: string\n}\n\nexport interface ChatFetcherOptions {\n /** Fires when `stop()` is called or the request is superseded. */\n signal: AbortSignal\n}\n\n/**\n * Direct function that performs a chat request. Mirrors\n * `GenerationFetcher`. Returns either a `Response` (SSE body parsed by the\n * chat client) or an `AsyncIterable<StreamChunk>` (yielded directly). May\n * return the value synchronously, as a `Promise`, or as an async generator\n * (`async function*`) — the chat client awaits whichever shape is returned.\n *\n * @example\n * ```ts\n * useChat({\n * fetcher: ({ messages }, { signal }) =>\n * chatFn({ data: { messages }, signal }),\n * })\n * ```\n */\nexport type ChatFetcher = (\n input: ChatFetcherInput,\n options: ChatFetcherOptions,\n) =>\n | Response\n | AsyncIterable<StreamChunk>\n | Promise<Response | AsyncIterable<StreamChunk>>\n\n/**\n * Distributive `Omit` — applies `Omit<O, K>` per branch of a union so\n * discriminated unions survive omission. Plain `Omit` collapses unions\n * into a single object shape, which would erase the `ChatTransport` XOR\n * when framework hooks omit React-managed callbacks from\n * `ChatClientOptions`.\n */\nexport type DistributedOmit<\n TObject,\n TKeys extends keyof any,\n> = TObject extends unknown ? Omit<TObject, TKeys> : never\n\n/**\n * Discriminated union enforcing that exactly one of `connection` or\n * `fetcher` is provided. Mirrors `GenerationTransport`.\n */\nexport type ChatTransport =\n | { connection: ConnectionAdapter; fetcher?: never }\n | { fetcher: ChatFetcher; connection?: never }\n\n/**\n * Tool call states - track the lifecycle of a tool call\n */\nexport type ToolCallState =\n | 'awaiting-input' // Received start but no arguments yet\n | 'input-streaming' // Partial arguments received\n | 'input-complete' // All arguments received\n | 'approval-requested' // Waiting for user approval\n | 'approval-responded' // User has approved/denied\n | 'complete' // Result is complete\n | 'error' // Tool execution failed (terminal)\n\n/**\n * Tool result states - track the lifecycle of a tool result\n */\nexport type ToolResultState =\n | 'streaming' // Placeholder for future streamed output\n | 'complete' // Result is complete\n | 'error' // Error occurred\n\n/**\n * ChatClient state - track the lifecycle of a chat\n */\nexport type ChatClientState = 'ready' | 'submitted' | 'streaming' | 'error'\n\n/**\n * Connection lifecycle state for the subscription loop.\n */\nexport type ConnectionStatus =\n | 'disconnected'\n | 'connecting'\n | 'connected'\n | 'error'\n\n/**\n * Multimodal content input for sending messages with rich media.\n * Allows sending text, images, audio, video, and documents to the LLM.\n *\n * @example\n * ```ts\n * // Send an image with a question\n * client.sendMessage({\n * content: [\n * { type: 'text', content: 'What is in this image?' },\n * { type: 'image', source: { type: 'url', value: 'https://example.com/photo.jpg' } }\n * ],\n * id: 'custom-message-id' // optional\n * })\n * ```\n */\nexport interface MultimodalContent {\n /**\n * The content of the message.\n * Can be a simple string or an array of content parts for multimodal messages.\n */\n content: string | Array<ContentPart>\n /**\n * Optional custom ID for the message.\n * If not provided, a unique ID will be generated.\n */\n id?: string\n}\n\n/**\n * Action taken when `sendMessage` is called while the client is busy\n * (streaming, claiming a send, or draining the queue).\n * - `queue`: hold the message; it auto-sends when the current run settles\n * **successfully**.\n * - `drop`: ignore the send (promise still resolves; does not throw).\n * - `interrupt`: abort the current stream and send immediately. Unlike\n * `stop()`, does **not** flush already-queued messages — they still drain\n * after the interrupting send settles successfully.\n */\nexport type WhenBusy = 'queue' | 'drop' | 'interrupt'\n\n/**\n * Why the client is busy when a {@link QueueStrategy} runs.\n * - `streaming` — an LLM stream is active (`isLoading`).\n * - `sendInFlight` — a send has claimed the client but is not yet loading.\n * - `draining` — the queue drain loop is delivering pending messages.\n */\nexport type QueueBusyReason = 'streaming' | 'sendInFlight' | 'draining'\n\n/**\n * A user message held in the send queue while a stream is active.\n * Rendered separately from `messages`; cancellable via `cancelQueued(id)`\n * until it drains.\n */\nexport interface QueuedMessage {\n id: string\n content: string | MultimodalContent\n createdAt: number\n}\n\n/**\n * Declarative queue policy.\n */\nexport interface QueueConfig {\n /**\n * Action when the client is busy (streaming, claiming a send, or draining).\n * Default `'queue'`.\n */\n whenBusy?: WhenBusy\n /**\n * How queued items leave the queue.\n * - `'fifo'`: one at a time, in order (default).\n * - `'batch'`: merge all queued items into one send when the run settles\n * successfully.\n */\n drain?: 'fifo' | 'batch'\n /** Max queued items. Unlimited when omitted. `0` means never queue. */\n maxSize?: number\n /**\n * Behavior when `maxSize` is reached. Default `'reject'`.\n * `'reject'` silently discards the new send (does not throw);\n * `'drop-oldest'` evicts the oldest queued item to make room.\n * Only meaningful when `maxSize` is set.\n */\n onOverflow?: 'reject' | 'drop-oldest'\n}\n\n/**\n * Escape hatch: decide the action for a single send. Drain stays FIFO for the\n * function form (no `batch` via function). Per-call `sendOptions.whenBusy`\n * overrides the strategy for that send.\n *\n * Actions match {@link WhenBusy}: `'queue' | 'drop' | 'interrupt'`. Concurrent\n * streams are not supported. `pending.id` is the id that will be stored if the\n * action is `'queue'` (safe to pass to `cancelQueued`).\n */\nexport type QueueStrategy = (ctx: {\n pending: QueuedMessage\n busyReason: QueueBusyReason\n queued: ReadonlyArray<QueuedMessage>\n}) => { action: WhenBusy }\n\n/** A `WhenBusy` shorthand, a full config, or a strategy function. */\nexport type QueueOption = WhenBusy | QueueConfig | QueueStrategy\n\n/** Per-call overrides for `sendMessage`. */\nexport interface SendMessageOptions {\n /** Overrides the configured `whenBusy` for this one send. */\n whenBusy?: WhenBusy\n}\n\n/**\n * Message parts - building blocks of UIMessage\n */\nexport interface TextPart {\n type: 'text'\n content: string\n}\n\n/**\n * Helper type that creates a tool-call part for a specific tool.\n * This is a conditional type to enable proper distribution over union types,\n * creating a discriminated union where `name` is the discriminant.\n */\ntype ToolCallPartForTool<T> = T extends AnyClientTool\n ? {\n type: 'tool-call'\n id: string\n name: T['name']\n arguments: string // JSON string (may be incomplete)\n /** Parsed tool input (typed from inputSchema) */\n input?: InferToolInput<T>\n state: ToolCallState\n /** Tool execution output (for client tools or after approval) */\n output?: InferToolOutput<T>\n } & (NonNullable<T['needsApproval']> extends true\n ? {\n /**\n * Approval metadata — present only on tools defined with\n * `needsApproval: true`. Populated once the call reaches\n * `state: 'approval-requested'`. `needsApproval` is an optional\n * property on the tool, so we index into it (rather than\n * `T extends { needsApproval: true }`, which an optional property\n * never satisfies) and strip `undefined` before comparing to `true`.\n */\n approval?: {\n id: string // Unique approval ID\n needsApproval: boolean // Always true if present\n approved?: boolean // User's decision (undefined until responded)\n }\n }\n : // Tools without `needsApproval: true` never carry an approval field.\n // `& unknown` is a no-op intersection (adds nothing).\n unknown)\n : never\n\n/**\n * Fallback tool-call part type when tools are not typed\n */\ntype UntypedToolCallPart = {\n type: 'tool-call'\n id: string\n name: string\n arguments: string\n input?: any\n state: ToolCallState\n approval?: {\n id: string\n needsApproval: boolean\n approved?: boolean\n }\n output?: any\n}\n\n/**\n * Tool call part that creates a proper discriminated union.\n * When TTools is typed, checking `part.name === 'toolName'` will narrow\n * `part.output` to the correct type for that tool.\n *\n * The discriminant is `name`, so code like:\n * ```ts\n * if (part.name === 'recommendGuitar') {\n * // part.output is now typed to the recommendGuitar tool's output\n * }\n * ```\n */\nexport type ToolCallPart<TTools extends ReadonlyArray<AnyClientTool> = any> =\n // Check if we have a concrete tools array (not 'any' or 'never')\n [TTools] extends [never]\n ? UntypedToolCallPart\n : unknown extends TTools\n ? UntypedToolCallPart\n : TTools extends ReadonlyArray<infer Tool>\n ? Tool extends AnyClientTool\n ? ToolCallPartForTool<Tool>\n : UntypedToolCallPart\n : UntypedToolCallPart\n\nexport interface ToolResultPart {\n type: 'tool-result'\n toolCallId: string\n content: string | Array<ContentPart>\n state: ToolResultState\n error?: string // Error message if state is \"error\"\n}\n\nexport interface ThinkingPart {\n type: 'thinking'\n content: string\n}\n\nexport type MessagePart<\n TTools extends ReadonlyArray<AnyClientTool> = any,\n TData = unknown,\n> =\n | TextPart\n | ImagePart\n | AudioPart\n | VideoPart\n | DocumentPart\n | ToolCallPart<TTools>\n | ToolResultPart\n | ThinkingPart\n | StructuredOutputPart<TData>\n | UIResourcePart\n\n/**\n * UIMessage - Domain-specific message format optimized for building chat UIs\n * Contains parts that can be text, tool calls, or tool results.\n *\n * `TTools` narrows the tool-call/result part types based on the registered\n * tools. `TData` is the schema-inferred type for any `structured-output` part\n * on the message — defaulted to `unknown` so untyped consumers (the core\n * stream processor, the wire converter) don't need to thread a schema generic\n * everywhere; the hook layer (`useChat({ outputSchema })`) substitutes it on\n * the public return so `m.parts.find(p => p.type === 'structured-output').data`\n * is typed without manual casts.\n */\nexport interface UIMessage<\n TTools extends ReadonlyArray<AnyClientTool> = any,\n TData = unknown,\n> {\n id: string\n role: 'system' | 'user' | 'assistant'\n parts: Array<MessagePart<TTools, TData>>\n createdAt?: Date\n}\n\nexport interface ChatClientPersistence<\n TTools extends ReadonlyArray<AnyClientTool> = any,\n> {\n getItem: (\n id: string,\n ) =>\n | Array<UIMessage<TTools>>\n | null\n | undefined\n | Promise<Array<UIMessage<TTools>> | null | undefined>\n setItem: (\n id: string,\n messages: Array<UIMessage<TTools>>,\n ) => void | Promise<void>\n removeItem: (id: string) => void | Promise<void>\n}\n\ntype IsUnknown<T> = unknown extends T\n ? [T] extends [unknown]\n ? true\n : false\n : false\n\ntype KnownContext<T> = IsUnknown<T> extends true ? never : T\n\ntype MergeContext<TLeft, TRight> = [TLeft] extends [never]\n ? TRight\n : [TRight] extends [never]\n ? TLeft\n : TLeft & TRight\n\ntype UnionToIntersection<T> = [T] extends [never]\n ? never\n : (T extends unknown ? (value: T) => void : never) extends (\n value: infer TIntersection,\n ) => void\n ? TIntersection\n : never\n\ntype DefinedContext<T> = Exclude<T, undefined>\n\ntype ContextFromExecute<T> = T extends (...args: any) => any\n ? NonNullable<Parameters<T>[1]> extends { context: infer TContext }\n ? KnownContext<TContext>\n : never\n : never\n\ntype ContextFromClientTool<T> = T extends AnyClientTool\n ? T extends { execute?: infer TExecute }\n ? ContextFromExecute<TExecute>\n : never\n : never\n\ntype RequiredContextFromClientToolUnion<T> = T extends unknown\n ? undefined extends ContextFromClientTool<T>\n ? never\n : ContextFromClientTool<T>\n : never\n\ntype ContextFromClientToolUnion<T> = [\n UnionToIntersection<DefinedContext<ContextFromClientTool<T>>>,\n] extends [never]\n ? never\n : [RequiredContextFromClientToolUnion<T>] extends [never]\n ? UnionToIntersection<DefinedContext<ContextFromClientTool<T>>> | undefined\n : UnionToIntersection<DefinedContext<ContextFromClientTool<T>>>\n\ntype ContextFromClientTools<TTools> =\n IsUnknown<TTools> extends true\n ? never\n : TTools extends readonly [infer THead, ...infer TTail]\n ? MergeContext<\n ContextFromClientTool<THead>,\n ContextFromClientTools<TTail>\n >\n : TTools extends ReadonlyArray<infer TItem>\n ? ContextFromClientToolUnion<TItem>\n : never\n\nexport type InferredClientContext<TTools> = [\n ContextFromClientTools<TTools>,\n] extends [never]\n ? unknown\n : ContextFromClientTools<TTools>\n\nexport type ClientContextOptionFromTools<TTools, TContext> = [\n ContextFromClientTools<TTools>,\n] extends [never]\n ? { context?: TContext }\n : undefined extends ContextFromClientTools<TTools>\n ? { context?: TContext & ContextFromClientTools<TTools> }\n : { context: TContext & ContextFromClientTools<TTools> }\n\n/**\n * Base options for `ChatClient`, excluding the transport (`connection` or\n * `fetcher`) which is supplied separately via `ChatTransport` so the XOR\n * is preserved when composing the final `ChatClientOptions` type.\n */\nexport interface ChatClientBaseOptions<\n TTools extends ReadonlyArray<AnyClientTool> = any,\n TContext = unknown,\n> {\n /**\n * Initial messages to populate the chat\n */\n initialMessages?: Array<UIMessage<TTools>>\n\n /**\n * Optional persistence adapter for chat messages.\n */\n persistence?: ChatClientPersistence<TTools>\n\n /**\n * Unique identifier for this chat instance\n * Used for managing multiple chats\n */\n id?: string\n\n /**\n * Thread ID to use for this chat session. Persists across sends within\n * the session. If omitted, a unique thread ID is generated.\n */\n threadId?: string\n\n /**\n * Arbitrary client-controlled JSON forwarded to the server in the\n * AG-UI `RunAgentInput.forwardedProps` field. Use this for per-session\n * options like provider/model selection or feature flags that the\n * server endpoint should read.\n *\n * Replaces the legacy `body` option. If both are provided,\n * `forwardedProps` wins on key collision.\n */\n forwardedProps?: Record<string, any>\n\n /**\n * @deprecated Use `forwardedProps` instead. `body` continues to work\n * unchanged — its values are merged into the AG-UI\n * `RunAgentInput.forwardedProps` field on the wire and are also\n * mirrored under the legacy `data` field for servers that have not\n * migrated yet. Will be removed in a future major release.\n */\n body?: Record<string, any>\n\n /**\n * Client-local runtime context passed to client tool implementations.\n *\n * This value is not serialized to the server. Use `forwardedProps` for\n * explicit client-to-server handoff of serializable values.\n */\n context?: TContext\n\n /**\n * Callback when a response is received\n */\n onResponse?: (response?: Response) => void | Promise<void>\n\n /**\n * Callback when a stream chunk is received\n */\n onChunk?: (chunk: StreamChunk) => void\n\n /**\n * Callback when the response is finished\n */\n onFinish?: (message: UIMessage<TTools>) => void\n\n /**\n * Callback when an error occurs\n */\n onError?: (error: Error) => void\n\n /**\n * Callback when messages change\n */\n onMessagesChange?: (messages: Array<UIMessage<TTools>>) => void\n\n /**\n * Callback when loading state changes\n */\n onLoadingChange?: (isLoading: boolean) => void\n\n /**\n * Callback when error state changes\n */\n onErrorChange?: (error: Error | undefined) => void\n\n /**\n * Callback when chat status changes\n */\n onStatusChange?: (status: ChatClientState) => void\n\n /**\n * Callback when subscription lifecycle changes.\n * This is independent from request lifecycle (`isLoading`, `status`).\n */\n onSubscriptionChange?: (isSubscribed: boolean) => void\n\n /**\n * Callback when connection lifecycle changes.\n */\n onConnectionStatusChange?: (status: ConnectionStatus) => void\n\n /**\n * Callback when session generation activity changes.\n * Derived from stream run events (RUN_STARTED / RUN_FINISHED / RUN_ERROR).\n * Unlike `onLoadingChange` (request-local), this reflects shared generation\n * activity visible to all subscribers (e.g. across tabs/devices).\n */\n onSessionGeneratingChange?: (isGenerating: boolean) => void\n\n /**\n * Policy for messages sent while the client is busy (streaming, claiming\n * a send, or draining the queue). Accepts a `WhenBusy` string, a\n * `QueueConfig`, or a `QueueStrategy` function.\n * Default: `{ whenBusy: 'queue', drain: 'fifo' }`.\n * Queued items auto-send only after a **successful** settle; they are\n * discarded on error/abort, `stop()`, `clear()`, `unsubscribe()`, and\n * `reload()`.\n */\n queue?: QueueOption\n\n /**\n * Callback when the pending send queue changes (enqueue, cancel, drain,\n * or flush).\n */\n onQueueChange?: (queue: Array<QueuedMessage>) => void\n\n /**\n * Callback when a custom event is received from a server-side tool.\n * Custom events are emitted by tools using `context.emitCustomEvent()` during execution.\n *\n * @param eventType - The name of the custom event\n * @param data - The event payload data\n * @param context - Additional context including the toolCallId that emitted the event\n */\n onCustomEvent?: (\n eventType: string,\n data: unknown,\n context: { toolCallId?: string },\n ) => void\n\n /**\n * Client-side tools with execution logic\n * When provided, tools with execute functions will be called automatically\n */\n tools?: TTools\n\n /**\n * Devtools hook metadata for this client instance.\n */\n devtools?: Partial<AIDevtoolsClientMetadata>\n\n /**\n * Factory that constructs the devtools bridge. Default is a no-op\n * factory, which keeps `@tanstack/ai-client/devtools` (the heavy\n * bridge implementation) out of the main entry's bundle. Frameworks\n * that need live devtools should pass the real factory from\n * `@tanstack/ai-client/devtools`.\n */\n devtoolsBridgeFactory?: ChatDevtoolsBridgeFactory\n\n /**\n * Stream processing options (optional)\n * Configure chunking strategy\n */\n streamProcessor?: {\n /**\n * Strategy for when to emit text updates\n * Defaults to ImmediateStrategy (every chunk)\n */\n chunkStrategy?: ChunkStrategy\n }\n}\n\n/**\n * Options for `ChatClient`. Exactly one of `connection` or `fetcher` must be\n * provided — the type-level XOR is enforced via `ChatTransport`.\n */\nexport type ChatClientOptions<\n TTools extends ReadonlyArray<AnyClientTool> = any,\n TContext = InferredClientContext<TTools>,\n> = DistributedOmit<ChatClientBaseOptions<TTools, TContext>, 'context'> &\n ClientContextOptionFromTools<TTools, TContext> &\n ChatTransport\n\nexport interface ChatRequestBody {\n messages: Array<ModelMessage>\n data?: Record<string, any>\n}\n\n/**\n * Create a typed array of client tools with proper type inference.\n * This eliminates the need for `as const` when defining tool arrays.\n *\n * @example\n * ```ts\n * const tools = clientTools(\n * myTool1.client(() => result1),\n * myTool2.client(() => result2),\n * )\n *\n * // tools is now properly typed as a tuple with literal tool names\n * // This enables type narrowing when checking part.name === 'toolName'\n * ```\n */\nexport function clientTools<const T extends Array<AnyClientTool>>(\n ...tools: T\n): T {\n return tools\n}\n\n/**\n * Helper to create typed chat client options\n * Use this to get proper type inference for messages\n *\n * @example\n * ```ts\n * const tools = clientTools(myTool1, myTool2)\n *\n * const chatOptions = createChatClientOptions({\n * connection: fetchServerSentEvents('/api/chat'),\n * tools,\n * })\n *\n * type MyMessages = InferChatMessages<typeof chatOptions>\n * ```\n */\nexport function createChatClientOptions<\n const TTools extends ReadonlyArray<AnyClientTool>,\n TContext = InferredClientContext<TTools>,\n>(\n options: ChatClientOptions<TTools, TContext>,\n): ChatClientOptions<TTools, TContext> {\n return options\n}\n\n/**\n * Extract the message type from chat options\n *\n * @example\n * ```ts\n * const chatOptions = createChatClientOptions({\n * connection: fetchServerSentEvents('/api/chat'),\n * tools: [myTool1, myTool2],\n * })\n *\n * type MyMessages = InferChatMessages<typeof chatOptions>\n * // MyMessages is now Array<UIMessage<[typeof myTool1, typeof myTool2]>>\n * ```\n */\nexport type InferChatMessages<T> =\n T extends ChatClientOptions<infer TTools, any>\n ? Array<UIMessage<TTools>>\n : never\n"],"names":[],"mappings":"AA+pBO,SAAS,eACX,OACA;AACH,SAAO;AACT;AAkBO,SAAS,wBAId,SACqC;AACrC,SAAO;AACT;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/ai-client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.22.0",
|
|
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",
|