@tanstack/ai-client 0.18.3 → 0.18.5
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/package.json +3 -3
- package/src/realtime-types.ts +6 -72
- package/dist/esm/chat-client.d.ts +0 -264
- package/dist/esm/chat-client.js +0 -1097
- package/dist/esm/chat-client.js.map +0 -1
- package/dist/esm/client-persistor.d.ts +0 -86
- package/dist/esm/client-persistor.js +0 -243
- package/dist/esm/client-persistor.js.map +0 -1
- package/dist/esm/connection-adapters.d.ts +0 -203
- package/dist/esm/connection-adapters.js +0 -611
- package/dist/esm/connection-adapters.js.map +0 -1
- package/dist/esm/devtools-noop.d.ts +0 -63
- package/dist/esm/devtools-noop.js +0 -141
- package/dist/esm/devtools-noop.js.map +0 -1
- package/dist/esm/devtools.d.ts +0 -276
- package/dist/esm/devtools.js +0 -1178
- package/dist/esm/devtools.js.map +0 -1
- package/dist/esm/events.d.ts +0 -129
- package/dist/esm/events.js +0 -227
- package/dist/esm/events.js.map +0 -1
- package/dist/esm/generation-client.d.ts +0 -99
- package/dist/esm/generation-client.js +0 -325
- package/dist/esm/generation-client.js.map +0 -1
- package/dist/esm/generation-types.d.ts +0 -242
- package/dist/esm/generation-types.js +0 -14
- package/dist/esm/generation-types.js.map +0 -1
- package/dist/esm/index.d.ts +0 -16
- package/dist/esm/index.js +0 -44
- package/dist/esm/index.js.map +0 -1
- package/dist/esm/realtime-client.d.ts +0 -98
- package/dist/esm/realtime-client.js +0 -403
- package/dist/esm/realtime-client.js.map +0 -1
- package/dist/esm/realtime-types.d.ts +0 -118
- package/dist/esm/response-stream.d.ts +0 -7
- package/dist/esm/response-stream.js +0 -32
- package/dist/esm/response-stream.js.map +0 -1
- package/dist/esm/sse-parser.d.ts +0 -8
- package/dist/esm/sse-parser.js +0 -52
- package/dist/esm/sse-parser.js.map +0 -1
- package/dist/esm/sse-utils.d.ts +0 -1
- package/dist/esm/sse-utils.js +0 -11
- package/dist/esm/sse-utils.js.map +0 -1
- package/dist/esm/tool-types.d.ts +0 -20
- package/dist/esm/types.d.ts +0 -419
- package/dist/esm/types.js +0 -11
- package/dist/esm/types.js.map +0 -1
- package/dist/esm/video-generation-client.d.ts +0 -110
- package/dist/esm/video-generation-client.js +0 -382
- package/dist/esm/video-generation-client.js.map +0 -1
package/dist/esm/devtools.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
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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"}
|
package/dist/esm/events.d.ts
DELETED
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
import { ContentPart } from '@tanstack/ai/client';
|
|
2
|
-
import { UIMessage } from './types.js';
|
|
3
|
-
export interface ChatClientRunEventContext {
|
|
4
|
-
threadId: string;
|
|
5
|
-
runId: string;
|
|
6
|
-
toolCallId?: string;
|
|
7
|
-
}
|
|
8
|
-
export interface ChatClientEventContext {
|
|
9
|
-
threadId?: string;
|
|
10
|
-
runId?: string;
|
|
11
|
-
toolCallId?: string;
|
|
12
|
-
}
|
|
13
|
-
export interface ChatClientToolFixtureAppliedEvent {
|
|
14
|
-
hookId: string;
|
|
15
|
-
threadId: string;
|
|
16
|
-
toolName: string;
|
|
17
|
-
input: unknown;
|
|
18
|
-
output: unknown;
|
|
19
|
-
execute?: boolean;
|
|
20
|
-
message?: {
|
|
21
|
-
id: string;
|
|
22
|
-
role: 'system' | 'user' | 'assistant';
|
|
23
|
-
parts: Array<unknown>;
|
|
24
|
-
createdAt?: number | string;
|
|
25
|
-
};
|
|
26
|
-
messageId: string;
|
|
27
|
-
toolCallId: string;
|
|
28
|
-
runId?: string;
|
|
29
|
-
errorText?: string;
|
|
30
|
-
}
|
|
31
|
-
export interface ChatClientStructuredOutputEvent {
|
|
32
|
-
status: 'streaming' | 'complete' | 'error';
|
|
33
|
-
raw?: string;
|
|
34
|
-
partial?: unknown;
|
|
35
|
-
data?: unknown;
|
|
36
|
-
reasoning?: string;
|
|
37
|
-
errorMessage?: string;
|
|
38
|
-
delta?: string;
|
|
39
|
-
}
|
|
40
|
-
export type ChatClientStructuredOutputEventName = 'structured-output:started' | 'structured-output:updated' | 'structured-output:completed' | 'structured-output:errored';
|
|
41
|
-
/**
|
|
42
|
-
* Abstract base class for ChatClient event emission
|
|
43
|
-
*/
|
|
44
|
-
export declare abstract class ChatClientEventEmitter {
|
|
45
|
-
protected clientId: string;
|
|
46
|
-
constructor(clientId: string);
|
|
47
|
-
/**
|
|
48
|
-
* Protected abstract method for emitting events
|
|
49
|
-
* Implementations should handle adding clientId and timestamp
|
|
50
|
-
*/
|
|
51
|
-
protected abstract emitEvent(eventName: string, data?: Record<string, unknown>): void;
|
|
52
|
-
/**
|
|
53
|
-
* Emit client created event
|
|
54
|
-
*/
|
|
55
|
-
clientCreated(initialMessageCount: number): void;
|
|
56
|
-
/**
|
|
57
|
-
* Emit loading state changed event
|
|
58
|
-
*/
|
|
59
|
-
loadingChanged(isLoading: boolean): void;
|
|
60
|
-
/**
|
|
61
|
-
* Emit error state changed event
|
|
62
|
-
*/
|
|
63
|
-
errorChanged(error: string | null): void;
|
|
64
|
-
/**
|
|
65
|
-
* Emit text update events (combines processor and client events)
|
|
66
|
-
*/
|
|
67
|
-
textUpdated(streamId: string, messageId: string, content: string, context?: ChatClientRunEventContext): void;
|
|
68
|
-
/**
|
|
69
|
-
* Emit tool call state change events (combines processor and client events)
|
|
70
|
-
*/
|
|
71
|
-
toolCallStateChanged(streamId: string, messageId: string, toolCallId: string, toolName: string, state: string, args: string, context?: ChatClientRunEventContext): void;
|
|
72
|
-
/**
|
|
73
|
-
* Emit tool result state change event
|
|
74
|
-
*/
|
|
75
|
-
/**
|
|
76
|
-
* Emit thinking update event
|
|
77
|
-
*/
|
|
78
|
-
thinkingUpdated(streamId: string, messageId: string, content: string, delta?: string, context?: ChatClientRunEventContext): void;
|
|
79
|
-
structuredOutputChanged(eventName: ChatClientStructuredOutputEventName, streamId: string, messageId: string, output: ChatClientStructuredOutputEvent, context?: ChatClientRunEventContext): void;
|
|
80
|
-
/**
|
|
81
|
-
* Emit approval requested event
|
|
82
|
-
*/
|
|
83
|
-
approvalRequested(streamId: string, messageId: string, toolCallId: string, toolName: string, input: unknown, approvalId: string, context?: ChatClientRunEventContext): void;
|
|
84
|
-
/**
|
|
85
|
-
* Emit message appended event
|
|
86
|
-
*/
|
|
87
|
-
messageAppended(uiMessage: UIMessage, streamId?: string, context?: ChatClientEventContext): void;
|
|
88
|
-
/**
|
|
89
|
-
* Emit message sent event.
|
|
90
|
-
* Supports both simple string content and multimodal content arrays.
|
|
91
|
-
*
|
|
92
|
-
* @param messageId - The ID of the sent message
|
|
93
|
-
* @param content - The message content (string or array of ContentPart for multimodal)
|
|
94
|
-
*/
|
|
95
|
-
messageSent(messageId: string, content: string | Array<ContentPart>): void;
|
|
96
|
-
/**
|
|
97
|
-
* Emit reloaded event
|
|
98
|
-
*/
|
|
99
|
-
reloaded(fromMessageIndex: number): void;
|
|
100
|
-
/**
|
|
101
|
-
* Emit stopped event
|
|
102
|
-
*/
|
|
103
|
-
stopped(): void;
|
|
104
|
-
/**
|
|
105
|
-
* Emit messages cleared event
|
|
106
|
-
*/
|
|
107
|
-
messagesCleared(): void;
|
|
108
|
-
/**
|
|
109
|
-
* Emit tool result added event
|
|
110
|
-
*/
|
|
111
|
-
toolResultAdded(toolCallId: string, toolName: string, output: unknown, state: string, context?: ChatClientEventContext): void;
|
|
112
|
-
/**
|
|
113
|
-
* Emit tool approval responded event
|
|
114
|
-
*/
|
|
115
|
-
toolApprovalResponded(approvalId: string, toolCallId: string, approved: boolean, context?: ChatClientRunEventContext): void;
|
|
116
|
-
/**
|
|
117
|
-
* Emit tool fixture applied event.
|
|
118
|
-
*/
|
|
119
|
-
toolFixtureApplied(fixture: ChatClientToolFixtureAppliedEvent): void;
|
|
120
|
-
}
|
|
121
|
-
/**
|
|
122
|
-
* Default implementation of ChatClientEventEmitter
|
|
123
|
-
*/
|
|
124
|
-
export declare class DefaultChatClientEventEmitter extends ChatClientEventEmitter {
|
|
125
|
-
/**
|
|
126
|
-
* Emit an event with automatic clientId and timestamp for client/tool events
|
|
127
|
-
*/
|
|
128
|
-
protected emitEvent(eventName: string, data?: Record<string, any>): void;
|
|
129
|
-
}
|
package/dist/esm/events.js
DELETED
|
@@ -1,227 +0,0 @@
|
|
|
1
|
-
import { createAIDevtoolsEventEnvelope, aiEventClient } from "@tanstack/ai-event-client";
|
|
2
|
-
class ChatClientEventEmitter {
|
|
3
|
-
clientId;
|
|
4
|
-
constructor(clientId) {
|
|
5
|
-
this.clientId = clientId;
|
|
6
|
-
}
|
|
7
|
-
/**
|
|
8
|
-
* Emit client created event
|
|
9
|
-
*/
|
|
10
|
-
clientCreated(initialMessageCount) {
|
|
11
|
-
this.emitEvent("client:created", {
|
|
12
|
-
initialMessageCount
|
|
13
|
-
});
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* Emit loading state changed event
|
|
17
|
-
*/
|
|
18
|
-
loadingChanged(isLoading) {
|
|
19
|
-
this.emitEvent("client:loading:changed", { isLoading });
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Emit error state changed event
|
|
23
|
-
*/
|
|
24
|
-
errorChanged(error) {
|
|
25
|
-
this.emitEvent("client:error:changed", {
|
|
26
|
-
error
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Emit text update events (combines processor and client events)
|
|
31
|
-
*/
|
|
32
|
-
textUpdated(streamId, messageId, content, context) {
|
|
33
|
-
this.emitEvent("text:chunk:content", {
|
|
34
|
-
streamId,
|
|
35
|
-
messageId,
|
|
36
|
-
content,
|
|
37
|
-
...context
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Emit tool call state change events (combines processor and client events)
|
|
42
|
-
*/
|
|
43
|
-
toolCallStateChanged(streamId, messageId, toolCallId, toolName, state, args, context) {
|
|
44
|
-
this.emitEvent("tools:call:updated", {
|
|
45
|
-
streamId,
|
|
46
|
-
messageId,
|
|
47
|
-
toolCallId,
|
|
48
|
-
toolName,
|
|
49
|
-
state,
|
|
50
|
-
arguments: args,
|
|
51
|
-
...context
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Emit tool result state change event
|
|
56
|
-
*/
|
|
57
|
-
/**
|
|
58
|
-
* Emit thinking update event
|
|
59
|
-
*/
|
|
60
|
-
thinkingUpdated(streamId, messageId, content, delta, context) {
|
|
61
|
-
this.emitEvent("text:chunk:thinking", {
|
|
62
|
-
streamId,
|
|
63
|
-
messageId,
|
|
64
|
-
content,
|
|
65
|
-
delta,
|
|
66
|
-
...context
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
structuredOutputChanged(eventName, streamId, messageId, output, context) {
|
|
70
|
-
this.emitEvent(eventName, {
|
|
71
|
-
streamId,
|
|
72
|
-
messageId,
|
|
73
|
-
...output,
|
|
74
|
-
...context
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* Emit approval requested event
|
|
79
|
-
*/
|
|
80
|
-
approvalRequested(streamId, messageId, toolCallId, toolName, input, approvalId, context) {
|
|
81
|
-
this.emitEvent("tools:approval:requested", {
|
|
82
|
-
streamId,
|
|
83
|
-
messageId,
|
|
84
|
-
toolCallId,
|
|
85
|
-
toolName,
|
|
86
|
-
input,
|
|
87
|
-
approvalId,
|
|
88
|
-
...context
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
/**
|
|
92
|
-
* Emit message appended event
|
|
93
|
-
*/
|
|
94
|
-
messageAppended(uiMessage, streamId, context) {
|
|
95
|
-
const content = uiMessage.parts.filter((part) => part.type === "text").map((part) => part.content).join(" ");
|
|
96
|
-
this.emitEvent("text:message:created", {
|
|
97
|
-
streamId,
|
|
98
|
-
messageId: uiMessage.id,
|
|
99
|
-
role: uiMessage.role,
|
|
100
|
-
content,
|
|
101
|
-
parts: uiMessage.parts,
|
|
102
|
-
...context
|
|
103
|
-
});
|
|
104
|
-
}
|
|
105
|
-
/**
|
|
106
|
-
* Emit message sent event.
|
|
107
|
-
* Supports both simple string content and multimodal content arrays.
|
|
108
|
-
*
|
|
109
|
-
* @param messageId - The ID of the sent message
|
|
110
|
-
* @param content - The message content (string or array of ContentPart for multimodal)
|
|
111
|
-
*/
|
|
112
|
-
messageSent(messageId, content) {
|
|
113
|
-
const textContent = typeof content === "string" ? content : content.filter((part) => part.type === "text").map((part) => part.content).join("");
|
|
114
|
-
this.emitEvent("text:message:created", {
|
|
115
|
-
messageId,
|
|
116
|
-
role: "user",
|
|
117
|
-
content: textContent,
|
|
118
|
-
// Include full content for multimodal messages
|
|
119
|
-
...Array.isArray(content) && { parts: content }
|
|
120
|
-
});
|
|
121
|
-
this.emitEvent("text:message:user", {
|
|
122
|
-
messageId,
|
|
123
|
-
role: "user",
|
|
124
|
-
content: textContent,
|
|
125
|
-
// Include full content for multimodal messages
|
|
126
|
-
...Array.isArray(content) && { parts: content }
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
/**
|
|
130
|
-
* Emit reloaded event
|
|
131
|
-
*/
|
|
132
|
-
reloaded(fromMessageIndex) {
|
|
133
|
-
this.emitEvent("client:reloaded", {
|
|
134
|
-
fromMessageIndex
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
|
-
/**
|
|
138
|
-
* Emit stopped event
|
|
139
|
-
*/
|
|
140
|
-
stopped() {
|
|
141
|
-
this.emitEvent("client:stopped");
|
|
142
|
-
}
|
|
143
|
-
/**
|
|
144
|
-
* Emit messages cleared event
|
|
145
|
-
*/
|
|
146
|
-
messagesCleared() {
|
|
147
|
-
this.emitEvent("client:messages:cleared");
|
|
148
|
-
}
|
|
149
|
-
/**
|
|
150
|
-
* Emit tool result added event
|
|
151
|
-
*/
|
|
152
|
-
toolResultAdded(toolCallId, toolName, output, state, context) {
|
|
153
|
-
this.emitEvent("tools:result:added", {
|
|
154
|
-
toolCallId,
|
|
155
|
-
toolName,
|
|
156
|
-
output,
|
|
157
|
-
state,
|
|
158
|
-
...context
|
|
159
|
-
});
|
|
160
|
-
}
|
|
161
|
-
/**
|
|
162
|
-
* Emit tool approval responded event
|
|
163
|
-
*/
|
|
164
|
-
toolApprovalResponded(approvalId, toolCallId, approved, context) {
|
|
165
|
-
this.emitEvent("tools:approval:responded", {
|
|
166
|
-
approvalId,
|
|
167
|
-
toolCallId,
|
|
168
|
-
approved,
|
|
169
|
-
...context
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
/**
|
|
173
|
-
* Emit tool fixture applied event.
|
|
174
|
-
*/
|
|
175
|
-
toolFixtureApplied(fixture) {
|
|
176
|
-
this.emitEvent("devtools:tool-fixture:applied", { ...fixture });
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
class DefaultChatClientEventEmitter extends ChatClientEventEmitter {
|
|
180
|
-
/**
|
|
181
|
-
* Emit an event with automatic clientId and timestamp for client/tool events
|
|
182
|
-
*/
|
|
183
|
-
emitEvent(eventName, data) {
|
|
184
|
-
const timestamp = Date.now();
|
|
185
|
-
const isUserVisibleEvent = eventName.startsWith("text:") || eventName.startsWith("tools:") || eventName.startsWith("structured-output:") || eventName === "devtools:tool-fixture:applied";
|
|
186
|
-
const includesClientContext = eventName.startsWith("client:") || eventName.startsWith("tools:") || eventName.startsWith("text:") || eventName.startsWith("structured-output:") || eventName === "devtools:tool-fixture:applied";
|
|
187
|
-
const visibility = isUserVisibleEvent ? "user-visible" : "client-state";
|
|
188
|
-
const envelopeContext = {
|
|
189
|
-
hookId: this.clientId,
|
|
190
|
-
...typeof data?.threadId === "string" ? { threadId: data.threadId } : {},
|
|
191
|
-
...typeof data?.runId === "string" ? { runId: data.runId } : {},
|
|
192
|
-
...typeof data?.streamId === "string" ? { streamId: data.streamId } : {},
|
|
193
|
-
...typeof data?.messageId === "string" ? { messageId: data.messageId } : {},
|
|
194
|
-
...typeof data?.toolCallId === "string" ? { toolCallId: data.toolCallId } : {}
|
|
195
|
-
};
|
|
196
|
-
if (includesClientContext) {
|
|
197
|
-
const envelope = createAIDevtoolsEventEnvelope({
|
|
198
|
-
eventType: eventName,
|
|
199
|
-
clientId: this.clientId,
|
|
200
|
-
...envelopeContext,
|
|
201
|
-
source: "client",
|
|
202
|
-
visibility,
|
|
203
|
-
timestamp
|
|
204
|
-
});
|
|
205
|
-
aiEventClient.emit(eventName, {
|
|
206
|
-
...data,
|
|
207
|
-
...envelope
|
|
208
|
-
});
|
|
209
|
-
} else {
|
|
210
|
-
const envelope = createAIDevtoolsEventEnvelope({
|
|
211
|
-
eventType: eventName,
|
|
212
|
-
source: "client",
|
|
213
|
-
visibility: "client-state",
|
|
214
|
-
timestamp
|
|
215
|
-
});
|
|
216
|
-
aiEventClient.emit(eventName, {
|
|
217
|
-
...data,
|
|
218
|
-
...envelope
|
|
219
|
-
});
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
export {
|
|
224
|
-
ChatClientEventEmitter,
|
|
225
|
-
DefaultChatClientEventEmitter
|
|
226
|
-
};
|
|
227
|
-
//# sourceMappingURL=events.js.map
|
package/dist/esm/events.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"events.js","sources":["../../src/events.ts"],"sourcesContent":["import {\n aiEventClient,\n createAIDevtoolsEventEnvelope,\n} from '@tanstack/ai-event-client'\nimport type { ContentPart } from '@tanstack/ai/client'\nimport type { UIMessage } from './types'\n\nexport interface ChatClientRunEventContext {\n threadId: string\n runId: string\n toolCallId?: string\n}\n\nexport interface ChatClientEventContext {\n threadId?: string\n runId?: string\n toolCallId?: string\n}\n\nexport interface ChatClientToolFixtureAppliedEvent {\n hookId: string\n threadId: string\n toolName: string\n input: unknown\n output: unknown\n execute?: boolean\n message?: {\n id: string\n role: 'system' | 'user' | 'assistant'\n parts: Array<unknown>\n createdAt?: number | string\n }\n messageId: string\n toolCallId: string\n runId?: string\n errorText?: string\n}\n\nexport interface ChatClientStructuredOutputEvent {\n status: 'streaming' | 'complete' | 'error'\n raw?: string\n partial?: unknown\n data?: unknown\n reasoning?: string\n errorMessage?: string\n delta?: string\n}\n\nexport type ChatClientStructuredOutputEventName =\n | 'structured-output:started'\n | 'structured-output:updated'\n | 'structured-output:completed'\n | 'structured-output:errored'\n\n/**\n * Abstract base class for ChatClient event emission\n */\nexport abstract class ChatClientEventEmitter {\n protected clientId: string\n\n constructor(clientId: string) {\n this.clientId = clientId\n }\n\n /**\n * Protected abstract method for emitting events\n * Implementations should handle adding clientId and timestamp\n */\n protected abstract emitEvent(\n eventName: string,\n data?: Record<string, unknown>,\n ): void\n\n /**\n * Emit client created event\n */\n clientCreated(initialMessageCount: number): void {\n this.emitEvent('client:created', {\n initialMessageCount,\n })\n }\n\n /**\n * Emit loading state changed event\n */\n loadingChanged(isLoading: boolean): void {\n this.emitEvent('client:loading:changed', { isLoading })\n }\n\n /**\n * Emit error state changed event\n */\n errorChanged(error: string | null): void {\n this.emitEvent('client:error:changed', {\n error,\n })\n }\n\n /**\n * Emit text update events (combines processor and client events)\n */\n textUpdated(\n streamId: string,\n messageId: string,\n content: string,\n context?: ChatClientRunEventContext,\n ): void {\n this.emitEvent('text:chunk:content', {\n streamId,\n messageId,\n content,\n ...context,\n })\n }\n\n /**\n * Emit tool call state change events (combines processor and client events)\n */\n 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 this.emitEvent('tools:call:updated', {\n streamId,\n messageId,\n toolCallId,\n toolName,\n state,\n arguments: args,\n ...context,\n })\n }\n\n /**\n * Emit tool result state change event\n */\n /**\n * Emit thinking update event\n */\n thinkingUpdated(\n streamId: string,\n messageId: string,\n content: string,\n delta?: string,\n context?: ChatClientRunEventContext,\n ): void {\n this.emitEvent('text:chunk:thinking', {\n streamId,\n messageId,\n content,\n delta,\n ...context,\n })\n }\n\n structuredOutputChanged(\n eventName: ChatClientStructuredOutputEventName,\n streamId: string,\n messageId: string,\n output: ChatClientStructuredOutputEvent,\n context?: ChatClientRunEventContext,\n ): void {\n this.emitEvent(eventName, {\n streamId,\n messageId,\n ...output,\n ...context,\n })\n }\n\n /**\n * Emit approval requested event\n */\n 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 this.emitEvent('tools:approval:requested', {\n streamId,\n messageId,\n toolCallId,\n toolName,\n input,\n approvalId,\n ...context,\n })\n }\n\n /**\n * Emit message appended event\n */\n messageAppended(\n uiMessage: UIMessage,\n streamId?: string,\n context?: ChatClientEventContext,\n ): void {\n const content = uiMessage.parts\n .filter((part) => part.type === 'text')\n .map((part) => part.content)\n .join(' ')\n\n this.emitEvent('text:message:created', {\n streamId,\n messageId: uiMessage.id,\n role: uiMessage.role,\n content,\n parts: uiMessage.parts,\n ...context,\n })\n }\n\n /**\n * Emit message sent event.\n * Supports both simple string content and multimodal content arrays.\n *\n * @param messageId - The ID of the sent message\n * @param content - The message content (string or array of ContentPart for multimodal)\n */\n messageSent(messageId: string, content: string | Array<ContentPart>): void {\n // For text content, extract it; for multimodal, provide the array\n const textContent =\n typeof content === 'string'\n ? content\n : content\n .filter((part) => part.type === 'text')\n .map((part) => (part as { type: 'text'; content: string }).content)\n .join('')\n\n this.emitEvent('text:message:created', {\n messageId,\n role: 'user',\n content: textContent,\n // Include full content for multimodal messages\n ...(Array.isArray(content) && { parts: content }),\n })\n\n this.emitEvent('text:message:user', {\n messageId,\n role: 'user',\n content: textContent,\n // Include full content for multimodal messages\n ...(Array.isArray(content) && { parts: content }),\n })\n }\n\n /**\n * Emit reloaded event\n */\n reloaded(fromMessageIndex: number): void {\n this.emitEvent('client:reloaded', {\n fromMessageIndex,\n })\n }\n /**\n * Emit stopped event\n */\n stopped(): void {\n this.emitEvent('client:stopped')\n }\n\n /**\n * Emit messages cleared event\n */\n messagesCleared(): void {\n this.emitEvent('client:messages:cleared')\n }\n\n /**\n * Emit tool result added event\n */\n toolResultAdded(\n toolCallId: string,\n toolName: string,\n output: unknown,\n state: string,\n context?: ChatClientEventContext,\n ): void {\n this.emitEvent('tools:result:added', {\n toolCallId,\n toolName,\n output,\n state,\n ...context,\n })\n }\n\n /**\n * Emit tool approval responded event\n */\n toolApprovalResponded(\n approvalId: string,\n toolCallId: string,\n approved: boolean,\n context?: ChatClientRunEventContext,\n ): void {\n this.emitEvent('tools:approval:responded', {\n approvalId,\n toolCallId,\n approved,\n ...context,\n })\n }\n\n /**\n * Emit tool fixture applied event.\n */\n toolFixtureApplied(fixture: ChatClientToolFixtureAppliedEvent): void {\n this.emitEvent('devtools:tool-fixture:applied', { ...fixture })\n }\n}\n\n/**\n * Default implementation of ChatClientEventEmitter\n */\nexport class DefaultChatClientEventEmitter extends ChatClientEventEmitter {\n /**\n * Emit an event with automatic clientId and timestamp for client/tool events\n */\n protected emitEvent(eventName: string, data?: Record<string, any>): void {\n const timestamp = Date.now()\n const isUserVisibleEvent =\n eventName.startsWith('text:') ||\n eventName.startsWith('tools:') ||\n eventName.startsWith('structured-output:') ||\n eventName === 'devtools:tool-fixture:applied'\n const includesClientContext =\n eventName.startsWith('client:') ||\n eventName.startsWith('tools:') ||\n eventName.startsWith('text:') ||\n eventName.startsWith('structured-output:') ||\n eventName === 'devtools:tool-fixture:applied'\n const visibility = isUserVisibleEvent ? 'user-visible' : 'client-state'\n const envelopeContext = {\n hookId: this.clientId,\n ...(typeof data?.threadId === 'string'\n ? { threadId: data.threadId }\n : {}),\n ...(typeof data?.runId === 'string' ? { runId: data.runId } : {}),\n ...(typeof data?.streamId === 'string'\n ? { streamId: data.streamId }\n : {}),\n ...(typeof data?.messageId === 'string'\n ? { messageId: data.messageId }\n : {}),\n ...(typeof data?.toolCallId === 'string'\n ? { toolCallId: data.toolCallId }\n : {}),\n }\n\n // For client:* and tool:* events, automatically add clientId and timestamp\n if (includesClientContext) {\n const envelope = createAIDevtoolsEventEnvelope({\n eventType: eventName,\n clientId: this.clientId,\n ...envelopeContext,\n source: 'client',\n visibility,\n timestamp,\n })\n aiEventClient.emit(eventName as any, {\n ...data,\n ...envelope,\n })\n } else {\n const envelope = createAIDevtoolsEventEnvelope({\n eventType: eventName,\n source: 'client',\n visibility: 'client-state',\n timestamp,\n })\n // For other events, just add timestamp\n aiEventClient.emit(eventName as any, {\n ...data,\n ...envelope,\n })\n }\n }\n}\n"],"names":[],"mappings":"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"}
|