@tanstack/ai-client 0.18.5 → 0.18.6

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.
Files changed (48) hide show
  1. package/dist/esm/chat-client.d.ts +264 -0
  2. package/dist/esm/chat-client.js +1097 -0
  3. package/dist/esm/chat-client.js.map +1 -0
  4. package/dist/esm/client-persistor.d.ts +86 -0
  5. package/dist/esm/client-persistor.js +243 -0
  6. package/dist/esm/client-persistor.js.map +1 -0
  7. package/dist/esm/connection-adapters.d.ts +203 -0
  8. package/dist/esm/connection-adapters.js +611 -0
  9. package/dist/esm/connection-adapters.js.map +1 -0
  10. package/dist/esm/devtools-noop.d.ts +63 -0
  11. package/dist/esm/devtools-noop.js +141 -0
  12. package/dist/esm/devtools-noop.js.map +1 -0
  13. package/dist/esm/devtools.d.ts +276 -0
  14. package/dist/esm/devtools.js +1178 -0
  15. package/dist/esm/devtools.js.map +1 -0
  16. package/dist/esm/events.d.ts +129 -0
  17. package/dist/esm/events.js +227 -0
  18. package/dist/esm/events.js.map +1 -0
  19. package/dist/esm/generation-client.d.ts +99 -0
  20. package/dist/esm/generation-client.js +325 -0
  21. package/dist/esm/generation-client.js.map +1 -0
  22. package/dist/esm/generation-types.d.ts +242 -0
  23. package/dist/esm/generation-types.js +14 -0
  24. package/dist/esm/generation-types.js.map +1 -0
  25. package/dist/esm/index.d.ts +16 -0
  26. package/dist/esm/index.js +44 -0
  27. package/dist/esm/index.js.map +1 -0
  28. package/dist/esm/realtime-client.d.ts +98 -0
  29. package/dist/esm/realtime-client.js +403 -0
  30. package/dist/esm/realtime-client.js.map +1 -0
  31. package/dist/esm/realtime-types.d.ts +78 -0
  32. package/dist/esm/response-stream.d.ts +7 -0
  33. package/dist/esm/response-stream.js +32 -0
  34. package/dist/esm/response-stream.js.map +1 -0
  35. package/dist/esm/sse-parser.d.ts +8 -0
  36. package/dist/esm/sse-parser.js +52 -0
  37. package/dist/esm/sse-parser.js.map +1 -0
  38. package/dist/esm/sse-utils.d.ts +1 -0
  39. package/dist/esm/sse-utils.js +11 -0
  40. package/dist/esm/sse-utils.js.map +1 -0
  41. package/dist/esm/tool-types.d.ts +20 -0
  42. package/dist/esm/types.d.ts +419 -0
  43. package/dist/esm/types.js +11 -0
  44. package/dist/esm/types.js.map +1 -0
  45. package/dist/esm/video-generation-client.d.ts +110 -0
  46. package/dist/esm/video-generation-client.js +382 -0
  47. package/dist/esm/video-generation-client.js.map +1 -0
  48. package/package.json +3 -3
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-client.js","sources":["../../src/chat-client.ts"],"sourcesContent":["import {\n StreamProcessor,\n convertSchemaToJsonSchema,\n generateMessageId,\n isStandardSchema,\n normalizeToUIMessage,\n parseWithStandardSchema,\n} from '@tanstack/ai/client'\nimport { createNoOpChatDevtoolsBridge } from './devtools-noop'\nimport {\n fetcherToConnectionAdapter,\n getChunkRunId,\n normalizeConnectionAdapter,\n} from './connection-adapters'\nimport { ChatPersistor } from './client-persistor'\nimport type {\n AnyClientTool,\n ContentPart,\n ModelMessage,\n StreamChunk,\n} from '@tanstack/ai/client'\nimport type {\n ConnectionAdapter,\n SubscribeConnectionAdapter,\n} from './connection-adapters'\nimport type {\n ChatClientEventEmitter,\n ChatClientRunEventContext,\n} from './events'\nimport type {\n AIDevtoolsChatSnapshot,\n ChatDevtoolsBridge,\n ChatDevtoolsBridgeOptions,\n} from './devtools'\nimport type {\n ChatClientOptions,\n ChatClientState,\n ChatFetcher,\n ConnectionStatus,\n MessagePart,\n MultimodalContent,\n ToolCallPart,\n UIMessage,\n} from './types'\n\ntype ChatClientUpdateOptionsWithoutContext<\n TTools extends ReadonlyArray<AnyClientTool>,\n> = {\n connection?: ConnectionAdapter\n fetcher?: ChatFetcher\n /** @deprecated Use `forwardedProps` instead. */\n body?: Record<string, any>\n forwardedProps?: Record<string, any>\n tools?: TTools\n onResponse?: (response?: Response) => void | Promise<void>\n onChunk?: (chunk: StreamChunk) => void\n onFinish?: (message: UIMessage) => void\n onError?: (error: Error) => void\n onSubscriptionChange?: (isSubscribed: boolean) => void\n onConnectionStatusChange?: (status: ConnectionStatus) => void\n onSessionGeneratingChange?: (isGenerating: boolean) => void\n onCustomEvent?: (\n eventType: string,\n data: unknown,\n context: { toolCallId?: string },\n ) => void\n}\n\ntype ClientToolResult = {\n toolCallId: string\n tool: string\n output: any\n state?: 'output-available' | 'output-error'\n errorText?: string\n}\n\nfunction resolveTransport(transport: {\n connection?: ConnectionAdapter\n fetcher?: ChatFetcher\n}): ConnectionAdapter {\n const { connection, fetcher } = transport\n if (connection && fetcher) {\n throw new Error(\n 'ChatClient: pass either `connection` or `fetcher`, not both.',\n )\n }\n if (connection) return connection\n if (fetcher) return fetcherToConnectionAdapter(fetcher)\n throw new Error('ChatClient: either `connection` or `fetcher` is required.')\n}\n\nexport class ChatClient<\n TTools extends ReadonlyArray<AnyClientTool> = any,\n TContext = unknown,\n> {\n private readonly processor: StreamProcessor\n private connection: SubscribeConnectionAdapter\n private readonly uniqueId: string\n private readonly threadId: string\n // All persistence concerns (hydrate / save / clear, plus suppression of late\n // chunks after a mid-stream clear) live in ChatPersistor so this class stays\n // focused on streaming. Undefined when no `persistence` adapter is configured.\n private readonly persistor?: ChatPersistor\n private currentRunId: string | null = null\n // Track the legacy `body` option and the canonical `forwardedProps`\n // option as separate slots so that `updateOptions({ forwardedProps })`\n // doesn't wipe a previously-set `body` (and vice versa). They are\n // merged on every send, with `forwardedProps` winning on key collision.\n private bodyOption: Record<string, any> = {}\n private forwardedPropsOption: Record<string, any> = {}\n private context: TContext | undefined = undefined\n private pendingMessageBody: Record<string, any> | undefined = undefined\n private isLoading = false\n private isSubscribed = false\n private error: Error | undefined = undefined\n private status: ChatClientState = 'ready'\n private connectionStatus: ConnectionStatus = 'disconnected'\n private abortController: AbortController | null = null\n private readonly clientToolsRef: { current: Map<string, AnyClientTool> }\n private readonly devtoolsBridge: ChatDevtoolsBridge\n /**\n * Alias for `this.events`. The bridge installs an\n * emitter that auto-attaches run/thread context and auto-emits a\n * snapshot after every event, so chat-client only ever calls\n * `this.events.X(...)` exactly like it did before devtools landed.\n */\n private readonly events: ChatClientEventEmitter\n private currentStreamId: string | null = null\n private currentMessageId: string | null = null\n private readonly postStreamActions: Array<() => Promise<void>> = []\n // Track pending client tool executions to await them before stream finalization\n private readonly pendingToolExecutions: Map<string, Promise<void>> = new Map()\n private activeClientTools: Map<string, AnyClientTool> | null = null\n private activeContext: TContext | undefined = undefined\n // Flag to deduplicate continuation checks during action draining\n private continuationPending = false\n private subscriptionAbortController: AbortController | null = null\n private processingResolve: (() => void) | null = null\n private errorReportedGeneration: number | null = null\n private streamGeneration = 0\n // Tracks whether a queued checkForContinuation was skipped because\n // continuationPending was true (chained approval scenario)\n private continuationSkipped = false\n private draining = false\n private sessionGenerating = false\n private readonly activeRunIds = new Set<string>()\n private devtoolsMounted = false\n\n private readonly callbacksRef: {\n current: {\n onResponse: (response?: Response) => void | Promise<void>\n onChunk: (chunk: StreamChunk) => void\n onFinish: (message: UIMessage) => void\n onError: (error: Error) => void\n onMessagesChange: (messages: Array<UIMessage>) => void\n onLoadingChange: (isLoading: boolean) => void\n onErrorChange: (error: Error | undefined) => void\n onStatusChange: (status: ChatClientState) => void\n onSubscriptionChange: (isSubscribed: boolean) => void\n onConnectionStatusChange: (status: ConnectionStatus) => void\n onSessionGeneratingChange: (isGenerating: boolean) => void\n onCustomEvent: (\n eventType: string,\n data: unknown,\n context: { toolCallId?: string },\n ) => void\n }\n }\n\n constructor(options: ChatClientOptions<TTools, TContext>) {\n this.uniqueId = options.id || this.generateUniqueId('chat')\n this.threadId = options.threadId || this.generateUniqueId('thread')\n if (options.persistence) {\n this.persistor = new ChatPersistor(\n options.persistence,\n this.uniqueId,\n (messages) => this.processor.setMessages(messages),\n )\n }\n // Both `body` (deprecated) and `forwardedProps` populate the AG-UI\n // `RunAgentInput.forwardedProps` wire field. They are stored\n // separately so `updateOptions` can replace one without touching the\n // other; the merge happens at send time, with `forwardedProps`\n // winning on key collision.\n this.bodyOption = options.body || {}\n this.forwardedPropsOption = options.forwardedProps || {}\n this.context = options.context\n this.connection = normalizeConnectionAdapter(resolveTransport(options))\n\n // Build client tools map\n this.clientToolsRef = { current: new Map() }\n if (options.tools) {\n for (const tool of options.tools) {\n this.clientToolsRef.current.set(tool.name, tool)\n }\n }\n\n this.devtoolsBridge = (\n options.devtoolsBridgeFactory ?? createNoOpChatDevtoolsBridge\n )(this.buildDevtoolsBridgeOptions(options.devtools))\n this.events = this.devtoolsBridge.events\n\n this.callbacksRef = {\n current: {\n onResponse: options.onResponse || (() => {}),\n onChunk: options.onChunk || (() => {}),\n onFinish: options.onFinish || (() => {}),\n onError: options.onError || (() => {}),\n onMessagesChange: options.onMessagesChange || (() => {}),\n onLoadingChange: options.onLoadingChange || (() => {}),\n onErrorChange: options.onErrorChange || (() => {}),\n onStatusChange: options.onStatusChange || (() => {}),\n onSubscriptionChange: options.onSubscriptionChange || (() => {}),\n onConnectionStatusChange:\n options.onConnectionStatusChange || (() => {}),\n onSessionGeneratingChange:\n options.onSessionGeneratingChange || (() => {}),\n onCustomEvent: options.onCustomEvent || (() => {}),\n },\n }\n\n // Create StreamProcessor with event handlers.\n // Use conditional spreads so we don't pass `undefined` into\n // `StreamProcessorOptions` fields under `exactOptionalPropertyTypes`.\n const persistedMessages = this.persistor?.readInitial()\n const initialMessages = Array.isArray(persistedMessages)\n ? persistedMessages\n : options.initialMessages\n\n this.processor = new StreamProcessor({\n ...(options.streamProcessor?.chunkStrategy\n ? { chunkStrategy: options.streamProcessor.chunkStrategy }\n : {}),\n ...(initialMessages ? { initialMessages } : {}),\n events: {\n onMessagesChange: (messages: Array<UIMessage>) => {\n this.persistor?.notifyMessagesChanged(messages)\n this.callbacksRef.current.onMessagesChange(messages)\n },\n onStreamStart: () => {\n this.setStatus('streaming')\n const assistantMessageId =\n this.processor.getCurrentAssistantMessageId()\n if (!assistantMessageId) {\n return\n }\n const messages = this.processor.getMessages()\n const assistantMessage = messages.find(\n (m: UIMessage) => m.id === assistantMessageId,\n )\n if (assistantMessage) {\n this.currentMessageId = assistantMessage.id\n this.events.messageAppended(\n assistantMessage,\n this.currentStreamId || undefined,\n )\n }\n },\n onStreamEnd: (message: UIMessage) => {\n this.callbacksRef.current.onFinish(message)\n this.setStatus('ready')\n // Resolve the processing-complete promise so streamResponse can continue\n this.resolveProcessing()\n },\n onError: (error: Error) => {\n this.reportStreamError(error)\n },\n onTextUpdate: (messageId: string, content: string) => {\n // Emit text update to devtools\n if (this.currentStreamId) {\n this.events.textUpdated(this.currentStreamId, messageId, content)\n }\n },\n onThinkingUpdate: (messageId: string, content: string) => {\n // Emit thinking update to devtools\n if (this.currentStreamId) {\n this.events.thinkingUpdated(\n this.currentStreamId,\n messageId,\n content,\n undefined,\n )\n }\n },\n onStructuredOutputChange: (args) => {\n const streamId = this.devtoolsBridge.resolveStreamId()\n const eventName =\n args.phase === 'start'\n ? 'structured-output:started'\n : args.phase === 'complete'\n ? 'structured-output:completed'\n : args.phase === 'error'\n ? 'structured-output:errored'\n : 'structured-output:updated'\n\n this.currentMessageId = args.messageId\n this.events.structuredOutputChanged(\n eventName,\n streamId,\n args.messageId,\n {\n status: args.status,\n raw: args.raw,\n ...(args.partial !== undefined ? { partial: args.partial } : {}),\n ...(args.data !== undefined ? { data: args.data } : {}),\n ...(args.reasoning !== undefined\n ? { reasoning: args.reasoning }\n : {}),\n ...(args.errorMessage !== undefined\n ? { errorMessage: args.errorMessage }\n : {}),\n ...(args.delta !== undefined ? { delta: args.delta } : {}),\n },\n )\n },\n onToolCallStateChange: (\n messageId: string,\n toolCallId: string,\n state: string,\n args: string,\n ) => {\n // Get the tool name from the messages\n const messages = this.processor.getMessages()\n const message = messages.find((m: UIMessage) => m.id === messageId)\n const toolCallPart = message?.parts.find(\n (p: MessagePart): p is ToolCallPart =>\n p.type === 'tool-call' && p.id === toolCallId,\n )\n const toolName = toolCallPart?.name || 'unknown'\n\n // Emit tool call state change to devtools\n if (this.currentStreamId) {\n this.events.toolCallStateChanged(\n this.currentStreamId,\n messageId,\n toolCallId,\n toolName,\n state,\n args,\n )\n }\n },\n onToolCall: (args: {\n toolCallId: string\n toolName: string\n input: any\n }) => {\n // Handle client-side tool execution automatically\n const clientTools =\n this.activeClientTools ?? this.clientToolsRef.current\n const clientTool = clientTools.get(args.toolName)\n const executeFunc = clientTool?.execute\n if (executeFunc) {\n // Capture the run context at execution-start so a tool whose\n // result lands AFTER the originating run finishes still reports\n // back against the originating run, not whatever run is\n // current when the result emits.\n const runEventContext =\n this.devtoolsBridge.getCurrentRunEventContext()\n // Create and track the execution promise\n const executionPromise = (async () => {\n try {\n const context =\n this.activeClientTools === null\n ? this.context\n : this.activeContext\n const output = await executeFunc(args.input, {\n toolCallId: args.toolCallId,\n context: context as TContext,\n emitCustomEvent: () => {},\n })\n await this.addToolResultForClientTool(\n {\n toolCallId: args.toolCallId,\n tool: args.toolName,\n output,\n state: 'output-available',\n },\n clientTool,\n runEventContext,\n )\n } catch (error: any) {\n await this.addToolResultForClientTool(\n {\n toolCallId: args.toolCallId,\n tool: args.toolName,\n output: null,\n state: 'output-error',\n errorText: error.message,\n },\n clientTool,\n runEventContext,\n )\n } finally {\n // Remove from pending when complete\n this.pendingToolExecutions.delete(args.toolCallId)\n }\n })()\n\n // Track the pending execution\n this.pendingToolExecutions.set(args.toolCallId, executionPromise)\n }\n },\n onApprovalRequest: (args: {\n toolCallId: string\n toolName: string\n input: any\n approvalId: string\n }) => {\n const streamId = this.devtoolsBridge.resolveStreamId()\n const messageIdForApproval =\n this.findMessageIdForToolCall(args.toolCallId) ??\n this.currentMessageId ??\n ''\n\n this.events.approvalRequested(\n streamId,\n messageIdForApproval,\n args.toolCallId,\n args.toolName,\n args.input,\n args.approvalId,\n )\n },\n onCustomEvent: (\n eventType: string,\n data: unknown,\n context: { toolCallId?: string },\n ) => {\n this.callbacksRef.current.onCustomEvent(eventType, data, context)\n },\n },\n })\n\n this.persistor?.hydrateAsync(persistedMessages)\n }\n\n mountDevtools(): void {\n if (this.devtoolsMounted) {\n return\n }\n\n this.devtoolsMounted = true\n this.devtoolsBridge.mountWithTools(this.processor.getMessages().length)\n }\n\n /**\n * Drain a runId-less RUN_ERROR that belongs to a cleared run the client is\n * still tracking. The persistor owns the cleared-run bookkeeping; the client\n * owns the active-run / session / processing state.\n */\n private drainIgnoredRunlessChunk(chunk: StreamChunk): void {\n if (chunk.type !== 'RUN_ERROR') return\n const runId = this.persistor?.takeRunlessRunId()\n if (!runId) return\n this.activeRunIds.delete(runId)\n this.setSessionGenerating(this.activeRunIds.size > 0)\n this.resolveProcessing()\n }\n\n private updateRunLifecycle(\n chunk: StreamChunk,\n options?: { resolveProcessing?: boolean },\n ): void {\n if (chunk.type === 'RUN_STARTED') {\n const chunkRunId = getChunkRunId(chunk) ?? chunk.runId\n this.activeRunIds.add(chunkRunId)\n this.persistor?.onRunStarted(chunkRunId)\n this.setSessionGenerating(true)\n return\n }\n\n if (chunk.type !== 'RUN_FINISHED' && chunk.type !== 'RUN_ERROR') {\n return\n }\n\n const runId = getChunkRunId(chunk)\n if (runId) {\n this.activeRunIds.delete(runId)\n this.persistor?.onRunSettled(runId)\n } else if (chunk.type === 'RUN_ERROR') {\n // RUN_ERROR without runId is a session-level error; clear all runs.\n this.activeRunIds.clear()\n this.persistor?.onSessionRunError()\n }\n this.setSessionGenerating(this.activeRunIds.size > 0)\n if (options?.resolveProcessing !== false) {\n this.resolveProcessing()\n }\n }\n\n private generateUniqueId(prefix: string): string {\n return `${prefix}-${Date.now()}-${Math.random().toString(36).substring(7)}`\n }\n\n private setIsLoading(isLoading: boolean): void {\n this.isLoading = isLoading\n this.callbacksRef.current.onLoadingChange(isLoading)\n this.events.loadingChanged(isLoading)\n }\n\n private setStatus(status: ChatClientState): void {\n this.status = status\n this.callbacksRef.current.onStatusChange(status)\n this.devtoolsBridge.emitSnapshot()\n }\n\n private setIsSubscribed(isSubscribed: boolean): void {\n this.isSubscribed = isSubscribed\n this.callbacksRef.current.onSubscriptionChange(isSubscribed)\n this.devtoolsBridge.emitSnapshot()\n }\n\n private setConnectionStatus(status: ConnectionStatus): void {\n this.connectionStatus = status\n this.callbacksRef.current.onConnectionStatusChange(status)\n this.devtoolsBridge.emitSnapshot()\n }\n\n private setSessionGenerating(isGenerating: boolean): void {\n if (this.sessionGenerating === isGenerating) return\n this.sessionGenerating = isGenerating\n this.callbacksRef.current.onSessionGeneratingChange(isGenerating)\n this.devtoolsBridge.emitSnapshot()\n }\n\n private resetSessionGenerating(): void {\n this.activeRunIds.clear()\n this.persistor?.resetIgnored()\n this.setSessionGenerating(false)\n }\n\n private setError(error: Error | undefined): void {\n this.error = error\n this.callbacksRef.current.onErrorChange(error)\n this.events.errorChanged(error?.message || null)\n }\n\n private buildDevtoolsBridgeOptions(\n devtools: ChatClientOptions['devtools'],\n ): ChatDevtoolsBridgeOptions {\n return {\n hookId: this.uniqueId,\n clientId: this.uniqueId,\n threadId: this.threadId,\n metadata: {\n hookName: devtools?.hookName ?? 'useChat',\n outputKind: devtools?.outputKind ?? 'chat',\n ...(devtools?.framework ? { framework: devtools.framework } : {}),\n ...(devtools?.name ? { name: devtools.name } : {}),\n },\n getSnapshot: () => this.getDevtoolsSnapshot(),\n getTools: () => this.clientToolsRef.current.values(),\n getMessages: () => this.processor.getMessages(),\n setMessages: (messages: Array<UIMessage>) => {\n this.processor.setMessages(messages)\n },\n addToolResult: (toolCallId, output, errorText) => {\n this.processor.addToolResult(toolCallId, output, errorText)\n },\n generateId: (prefix) => this.generateUniqueId(prefix),\n }\n }\n\n private getDevtoolsSnapshot(): AIDevtoolsChatSnapshot {\n return {\n messages: this.processor.getMessages(),\n status: this.status,\n isLoading: this.isLoading,\n isSubscribed: this.isSubscribed,\n connectionStatus: this.connectionStatus,\n sessionGenerating: this.sessionGenerating,\n activeRunIds: Array.from(this.activeRunIds),\n ...(this.error ? { error: this.error.message } : {}),\n }\n }\n\n private findMessageIdForToolCall(toolCallId: string): string | undefined {\n const messages = this.processor.getMessages()\n for (const message of messages) {\n const match = message.parts.find(\n (part: MessagePart): part is ToolCallPart =>\n part.type === 'tool-call' && part.id === toolCallId,\n )\n if (match) return message.id\n }\n return undefined\n }\n\n private abortSubscriptionLoop(): void {\n this.subscriptionAbortController?.abort()\n this.subscriptionAbortController = null\n }\n\n private resolveProcessing(): void {\n this.processingResolve?.()\n this.processingResolve = null\n }\n\n private cancelInFlightStream(options?: {\n setReadyStatus?: boolean\n abortSubscription?: boolean\n }): void {\n this.abortController?.abort()\n this.abortController = null\n if (options?.abortSubscription) {\n this.abortSubscriptionLoop()\n }\n this.resolveProcessing()\n this.setIsLoading(false)\n if (options?.setReadyStatus) {\n this.setStatus('ready')\n }\n }\n\n private reportStreamError(error: Error): void {\n const alreadyReported =\n this.errorReportedGeneration === this.streamGeneration\n this.setError(error)\n // Preserve request-level error semantics even if a RUN_ERROR arrives\n // slightly after loading flips false during stream teardown.\n if (\n this.isLoading ||\n this.status === 'submitted' ||\n this.status === 'streaming'\n ) {\n this.setStatus('error')\n }\n if (!alreadyReported) {\n this.errorReportedGeneration = this.streamGeneration\n this.callbacksRef.current.onError(error)\n }\n }\n\n /**\n * Start the background subscription loop.\n */\n private startSubscription(): void {\n this.subscriptionAbortController = new AbortController()\n const signal = this.subscriptionAbortController.signal\n\n this.consumeSubscription(signal)\n .catch((err) => {\n if (err instanceof Error && err.name !== 'AbortError') {\n this.setConnectionStatus('error')\n this.resetSessionGenerating()\n this.setIsSubscribed(false)\n this.reportStreamError(err)\n }\n // Resolve pending processing so streamResponse doesn't hang\n this.resolveProcessing()\n })\n .finally(() => {\n // Ignore stale loops that were superseded by a restart.\n if (this.subscriptionAbortController?.signal !== signal) {\n return\n }\n this.subscriptionAbortController = null\n if (!signal.aborted && this.isSubscribed) {\n this.setIsSubscribed(false)\n if (this.connectionStatus !== 'error') {\n this.setConnectionStatus('disconnected')\n }\n }\n })\n }\n\n /**\n * Consume chunks from the connection subscription.\n */\n private async consumeSubscription(signal: AbortSignal): Promise<void> {\n const stream = this.connection.subscribe(signal)\n for await (const chunk of stream) {\n if (signal.aborted) break\n if (this.connectionStatus === 'connecting') {\n this.setConnectionStatus('connected')\n }\n const shouldIgnore = this.persistor?.shouldIgnoreChunk(chunk) ?? false\n if (shouldIgnore) {\n if (chunk.type === 'RUN_FINISHED' || chunk.type === 'RUN_ERROR') {\n if (getChunkRunId(chunk)) {\n this.updateRunLifecycle(chunk, { resolveProcessing: false })\n } else {\n this.drainIgnoredRunlessChunk(chunk)\n }\n }\n continue\n }\n this.callbacksRef.current.onChunk(chunk)\n this.devtoolsBridge.observeChunk(chunk)\n this.processor.processChunk(chunk)\n // Run lifecycle (active-run tracking, session-generating state, and\n // processing resolution for RUN_FINISHED / RUN_ERROR) is handled in a\n // single place so the ignored-chunk path above and this path can't\n // diverge. RUN_ERROR carries its runId via the AG-UI passthrough so a\n // per-run error only clears that run, while a runId-less RUN_ERROR is\n // treated as a session-level error that clears every active run.\n this.updateRunLifecycle(chunk)\n // Yield control back to event loop for UI updates\n await new Promise((resolve) => setTimeout(resolve, 0))\n }\n }\n\n /**\n * Ensure subscription loop is running, starting it if needed.\n */\n private ensureSubscription(): void {\n if (!this.isSubscribed) {\n this.subscribe()\n return\n }\n if (\n !this.subscriptionAbortController ||\n this.subscriptionAbortController.signal.aborted\n ) {\n this.subscribe({ restart: true })\n }\n }\n\n /**\n * Create a promise that resolves when onStreamEnd fires.\n * Used by streamResponse to await processing completion.\n */\n private waitForProcessing(): Promise<void> {\n // Resolve any stale promise (e.g., from a previous aborted request)\n this.resolveProcessing()\n return new Promise<void>((resolve) => {\n this.processingResolve = resolve\n })\n }\n\n /**\n * Send a message and stream the response.\n * Supports both simple string content and multimodal content (images, audio, video, documents).\n *\n * @param content - The message content. Can be:\n * - A simple string for text-only messages\n * - A MultimodalContent object with content array and optional custom ID\n * @param body - Optional body parameters to merge with the client's base body for this request.\n * Uses shallow merge with per-message body taking priority.\n *\n * @example\n * ```ts\n * // Simple text message\n * await client.sendMessage('Hello!')\n *\n * // Text message with custom body params\n * await client.sendMessage('Hello!', { temperature: 0.7 })\n *\n * // Multimodal message with image\n * await 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 * })\n *\n * // Multimodal message with custom ID and body params\n * await client.sendMessage(\n * {\n * content: [\n * { type: 'text', content: 'Describe this audio' },\n * { type: 'audio', source: { type: 'data', value: 'base64...' } }\n * ],\n * id: 'custom-message-id'\n * },\n * { model: 'gpt-4-audio' }\n * )\n * ```\n */\n async sendMessage(\n content: string | MultimodalContent,\n body?: Record<string, any>,\n ): Promise<void> {\n this.mountDevtools()\n const emptyMessage = typeof content === 'string' && !content.trim()\n if (emptyMessage || this.isLoading) {\n return\n }\n // Normalize input to extract content, id, and validate\n const normalizedContent = this.normalizeMessageInput(content)\n\n // Store the per-message body for use in streamResponse\n this.pendingMessageBody = body\n\n // Add user message via processor\n const userMessage = this.processor.addUserMessage(\n normalizedContent.content,\n normalizedContent.id,\n )\n this.events.messageSent(userMessage.id, normalizedContent.content)\n\n await this.streamResponse()\n }\n\n /**\n * Normalize the message input to extract content and optional id.\n * Trims string content automatically.\n */\n private normalizeMessageInput(input: string | MultimodalContent): {\n content: string | Array<ContentPart>\n id?: string\n } {\n if (typeof input === 'string') {\n return { content: input.trim() }\n }\n return { content: input.content, id: input.id }\n }\n\n /**\n * Append a message and stream the response\n */\n async append(message: UIMessage | ModelMessage): Promise<void> {\n this.mountDevtools()\n // Normalize the message to ensure it has id and createdAt\n const normalizedMessage = normalizeToUIMessage(message, generateMessageId)\n\n // Skip system messages - they're handled via systemPrompts, not UIMessages\n if (normalizedMessage.role === 'system') {\n return\n }\n\n // Type assertion: after checking for system, we know it's user or assistant\n const uiMessage = normalizedMessage as UIMessage\n\n // Emit message appended event\n this.events.messageAppended(uiMessage)\n\n // Add to messages\n const messages = this.processor.getMessages()\n this.processor.setMessages([...messages, uiMessage])\n this.devtoolsBridge.emitSnapshot()\n\n // If stream is in progress, queue the response for after it ends\n if (this.isLoading) {\n this.queuePostStreamAction(async () => {\n await this.streamResponse()\n })\n return\n }\n\n await this.streamResponse()\n }\n\n /**\n * Stream a response from the LLM.\n * Returns true if the stream completed successfully, false on abort or error.\n */\n private async streamResponse(): Promise<boolean> {\n // Guard against concurrent streams - if already loading, skip\n if (this.isLoading) {\n return false\n }\n\n // Track generation so a superseded stream's cleanup doesn't clobber the new one\n const generation = ++this.streamGeneration\n const runId = `run-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`\n this.currentRunId = runId\n\n this.setIsLoading(true)\n this.setStatus('submitted')\n this.setError(undefined)\n this.errorReportedGeneration = null\n this.abortController = new AbortController()\n // Capture the signal immediately so that a concurrent stop() or\n // sendMessage() that reassigns this.abortController cannot cause\n // connect() to receive a stale or null signal.\n const signal = this.abortController.signal\n // Reset pending tool executions for the new stream\n this.pendingToolExecutions.clear()\n let streamCompletedSuccessfully = false\n let activeDevtoolsRunId: string | null = null\n let runTerminalEventEmitted = false\n\n try {\n // Get UIMessages with parts (preserves approval state and client tool results)\n const messages = this.processor.getMessages()\n const clientTools = new Map(this.clientToolsRef.current)\n const runtimeContext = this.context\n\n // Call onResponse callback\n await this.callbacksRef.current.onResponse()\n\n // If the stream was cancelled during the onResponse await (e.g. stop()\n // from a callback or unmount, or reload() superseding this stream),\n // bail out before allocating waitForProcessing() — otherwise the\n // resolveProcessing() that ran during cancellation is a no-op and the\n // await processingComplete below would deadlock.\n if (signal.aborted) {\n return false\n }\n\n // Merge sources for the wire `forwardedProps` field, in priority\n // order (later spreads win):\n // 1. Legacy `body` option (deprecated).\n // 2. Canonical `forwardedProps` option (wins over `body`).\n // 3. Per-message `body` arg passed to `sendMessage` (highest).\n // The AG-UI standard `threadId` is sent at the wire's top level for\n // run/conversation correlation, so we no longer auto-emit a separate\n // `conversationId` here — `chat({ threadId })` server-side covers the\n // same role for devtools/observability.\n const mergedBody = {\n ...this.bodyOption,\n ...this.forwardedPropsOption,\n ...this.pendingMessageBody,\n }\n\n // Clear the pending message body after use\n this.pendingMessageBody = undefined\n\n // Generate stream ID — assistant message will be created by stream events\n this.currentStreamId = this.generateUniqueId('stream')\n this.devtoolsBridge.setCurrentStreamId(this.currentStreamId)\n this.currentMessageId = null\n this.activeClientTools = clientTools\n this.activeContext = runtimeContext\n\n // Reset processor stream state for new response — prevents stale\n // messageStates entries (from a previous stream) from blocking\n // creation of a new assistant message (e.g. after reload).\n this.processor.prepareAssistantMessage()\n\n // Ensure subscription loop is running\n this.ensureSubscription()\n\n // Set up promise that resolves when onStreamEnd fires\n const processingComplete = this.waitForProcessing()\n\n // Build per-send run context for AG-UI compliance\n // Note: mergedBody already contains the merged this.body + pendingMessageBody\n // (pendingMessageBody was cleared above, so we use mergedBody as forwardedProps)\n // Convert each client tool's `inputSchema` (a Standard Schema:\n // Zod, ArkType, Valibot, etc.) to JSON Schema for the wire. Foreign\n // AG-UI servers consuming `RunAgentInput.tools[].parameters` expect\n // JSON Schema; sending a Standard Schema instance directly would\n // serialize to an unusable shape.\n const runContext = {\n threadId: this.threadId,\n runId,\n clientTools: Array.from(clientTools.values()).map((t) => ({\n name: t.name,\n description: t.description,\n parameters: t.inputSchema\n ? convertSchemaToJsonSchema(t.inputSchema)\n : { type: 'object' },\n })),\n forwardedProps: { ...mergedBody },\n }\n this.devtoolsBridge.beginRun(runContext.runId, this.threadId)\n activeDevtoolsRunId = runContext.runId\n this.devtoolsBridge.emitRunLifecycle(\n 'run:created',\n runContext.runId,\n 'created',\n )\n this.devtoolsBridge.emitRunLifecycle(\n 'run:started',\n runContext.runId,\n 'started',\n )\n this.devtoolsBridge.emitSnapshot()\n\n // Send through normalized connection (pushes chunks to subscription queue)\n await this.connection.send(messages, mergedBody, signal, runContext)\n\n // Wait for subscription loop to finish processing all chunks\n await processingComplete\n\n // If this stream was superseded (e.g. by reload()), bail out —\n // the new stream owns the processor and processingResolve now.\n if (generation !== this.streamGeneration) {\n return false\n }\n\n // A RUN_ERROR from the stream transitions status to error.\n // Do not treat this stream as a successful completion.\n if (this.status === 'error') {\n if (activeDevtoolsRunId) {\n this.devtoolsBridge.emitRunLifecycle(\n 'run:errored',\n activeDevtoolsRunId,\n 'errored',\n this.error ? { error: this.error.message } : {},\n )\n runTerminalEventEmitted = true\n }\n return false\n }\n\n // Wait for pending client tool executions\n if (this.pendingToolExecutions.size > 0) {\n await Promise.all(this.pendingToolExecutions.values())\n }\n\n // Finalize (idempotent — may already be done by RUN_FINISHED handler)\n this.processor.finalizeStream()\n streamCompletedSuccessfully = true\n } catch (err) {\n if (err instanceof Error) {\n if (err.name === 'AbortError') {\n if (activeDevtoolsRunId) {\n this.devtoolsBridge.emitRunLifecycle(\n 'run:cancelled',\n activeDevtoolsRunId,\n 'cancelled',\n )\n runTerminalEventEmitted = true\n }\n return false\n }\n if (generation === this.streamGeneration) {\n this.reportStreamError(err)\n if (activeDevtoolsRunId) {\n this.devtoolsBridge.emitRunLifecycle(\n 'run:errored',\n activeDevtoolsRunId,\n 'errored',\n { error: err.message },\n )\n runTerminalEventEmitted = true\n }\n }\n }\n } finally {\n // Only clean up if this is still the active stream.\n // A superseded stream (e.g. reload() started a new one) must not\n // clobber the new stream's abortController or isLoading state.\n if (generation === this.streamGeneration) {\n this.currentStreamId = null\n this.devtoolsBridge.setCurrentStreamId(null)\n this.currentMessageId = null\n this.currentRunId = null\n this.activeClientTools = null\n this.activeContext = undefined\n this.abortController = null\n this.setIsLoading(false)\n this.pendingMessageBody = undefined // Ensure it's cleared even on error\n\n if (activeDevtoolsRunId && !runTerminalEventEmitted) {\n if (streamCompletedSuccessfully) {\n this.devtoolsBridge.emitRunLifecycle(\n 'run:completed',\n activeDevtoolsRunId,\n 'completed',\n )\n } else if (signal.aborted) {\n this.devtoolsBridge.emitRunLifecycle(\n 'run:cancelled',\n activeDevtoolsRunId,\n 'cancelled',\n )\n }\n }\n\n // Drain any actions that were queued while the stream was in progress\n await this.drainPostStreamActions()\n\n // Continue conversation if the stream ended with a tool result (server tool completed)\n // but ONLY if the model indicated it wants to continue (finishReason !== 'stop').\n // When finishReason is 'stop', the model is done — don't re-send.\n if (streamCompletedSuccessfully) {\n const messages = this.processor.getMessages()\n const lastPart = messages.at(-1)?.parts.at(-1)\n const { finishReason } = this.processor.getState()\n\n if (\n lastPart?.type === 'tool-result' &&\n finishReason !== 'stop' &&\n this.shouldAutoSend()\n ) {\n try {\n await this.checkForContinuation()\n } catch (error) {\n console.error('Failed to continue flow after tool result:', error)\n }\n } else if (this.status !== 'ready') {\n // Terminal run, but onStreamEnd never fired: the processor had no\n // assistant message to emit it for (e.g. a bare RUN_FINISHED{stop},\n // #421). The normal path already set 'ready', so this is a no-op.\n this.setStatus('ready')\n }\n }\n }\n }\n\n return streamCompletedSuccessfully\n }\n\n /**\n * Start the client subscription loop.\n * This controls the connection lifecycle independently from request lifecycle.\n */\n subscribe(options?: { restart?: boolean }): void {\n const restart = options?.restart === true\n if (this.isSubscribed && !restart) {\n return\n }\n\n if (this.isSubscribed && restart) {\n this.abortSubscriptionLoop()\n }\n\n this.setIsSubscribed(true)\n this.setConnectionStatus('connecting')\n this.startSubscription()\n }\n\n /**\n * Unsubscribe and fully tear down live behavior.\n * This aborts an in-flight request and the subscription loop.\n */\n unsubscribe(): void {\n this.cancelInFlightStream({\n setReadyStatus: true,\n abortSubscription: true,\n })\n this.resetSessionGenerating()\n this.setIsSubscribed(false)\n this.setConnectionStatus('disconnected')\n }\n\n /**\n * Reload the last assistant message\n */\n async reload(): Promise<void> {\n const messages = this.processor.getMessages()\n if (messages.length === 0) return\n\n // Find the last user message\n const lastUserMessageIndex = messages.findLastIndex(\n (m) => m.role === 'user',\n )\n\n if (lastUserMessageIndex === -1) return\n\n // Cancel any active stream before reloading\n if (this.isLoading) {\n this.cancelInFlightStream()\n }\n\n this.events.reloaded(lastUserMessageIndex)\n\n // Remove all messages after the last user message\n this.processor.removeMessagesAfter(lastUserMessageIndex)\n this.devtoolsBridge.emitSnapshot()\n\n // Resend\n await this.streamResponse()\n }\n\n /**\n * Stop the current stream\n */\n stop(): void {\n const hadLocalStream = this.abortController !== null\n this.cancelInFlightStream({ setReadyStatus: true })\n if (hadLocalStream) {\n this.resetSessionGenerating()\n }\n this.events.stopped()\n }\n\n /**\n * Clear all messages\n */\n clear(): void {\n if (this.persistor) {\n this.persistor.snapshotClear({\n messages: this.processor.getMessages(),\n activeRunIds: this.activeRunIds,\n currentRunId: this.currentRunId,\n })\n if (this.isLoading) {\n this.cancelInFlightStream({ setReadyStatus: true })\n this.resetSessionGenerating()\n } else if (this.activeRunIds.size > 0) {\n this.resetSessionGenerating()\n }\n // Suppress persisting the empty snapshot that clearMessages emits, then\n // remove the stored conversation outright.\n this.persistor.beginClear()\n }\n this.processor.clearMessages()\n this.persistor?.remove()\n this.setError(undefined)\n this.events.messagesCleared()\n }\n\n /**\n * Add the result of a client-side tool execution\n */\n async addToolResult(result: ClientToolResult): Promise<void> {\n const clientTool = this.clientToolsRef.current.get(result.tool)\n await this.addToolResultForClientTool(result, clientTool)\n }\n\n private async addToolResultForClientTool(\n result: ClientToolResult,\n clientTool: AnyClientTool | undefined,\n context?: ChatClientRunEventContext,\n ): Promise<void> {\n if (clientTool && result.state !== 'output-error') {\n try {\n result = {\n ...result,\n output: this.validateClientToolOutput(clientTool, result.output),\n }\n } catch (error: any) {\n result = {\n ...result,\n output: null,\n state: 'output-error',\n errorText: error.message,\n }\n }\n }\n\n this.events.toolResultAdded(\n result.toolCallId,\n result.tool,\n result.output,\n result.state || 'output-available',\n context,\n )\n\n // Forward an error message only for output-error results (with a fallback so\n // a message-less `throw new Error()` still reaches the terminal 'error'\n // state); a stray errorText on a successful result must not signal an error.\n this.processor.addToolResult(\n result.toolCallId,\n result.output,\n result.state === 'output-error'\n ? result.errorText || 'Tool execution failed'\n : undefined,\n )\n\n // If stream is in progress, queue continuation check for after it ends\n if (this.isLoading) {\n this.queuePostStreamAction(() => this.checkForContinuation())\n return\n }\n\n await this.checkForContinuation()\n }\n\n private validateClientToolOutput(\n clientTool: AnyClientTool,\n output: any,\n ): any {\n if (clientTool.outputSchema && isStandardSchema(clientTool.outputSchema)) {\n return parseWithStandardSchema(clientTool.outputSchema, output)\n }\n\n return output\n }\n\n /**\n * Respond to a tool approval request\n */\n async addToolApprovalResponse(response: {\n id: string // approval.id, not toolCallId\n approved: boolean\n }): Promise<void> {\n // Find the tool call ID from the approval ID\n const messages = this.processor.getMessages()\n let foundToolCallId: string | undefined\n\n for (const msg of messages) {\n const toolCallPart = msg.parts.find(\n (p: MessagePart): p is ToolCallPart =>\n p.type === 'tool-call' && p.approval?.id === response.id,\n )\n if (toolCallPart) {\n foundToolCallId = toolCallPart.id\n break\n }\n }\n\n if (foundToolCallId) {\n this.events.toolApprovalResponded(\n response.id,\n foundToolCallId,\n response.approved,\n )\n }\n\n // Add response via processor\n this.processor.addToolApprovalResponse(response.id, response.approved)\n this.devtoolsBridge.emitSnapshot()\n\n // If stream is in progress, queue continuation check for after it ends\n if (this.isLoading) {\n this.queuePostStreamAction(() => this.checkForContinuation())\n return\n }\n\n await this.checkForContinuation()\n }\n\n /**\n * Queue an action to be executed after the current stream ends\n */\n private queuePostStreamAction(action: () => Promise<void>): void {\n this.postStreamActions.push(action)\n }\n\n /**\n * Drain and execute all queued post-stream actions\n */\n private async drainPostStreamActions(): Promise<void> {\n if (this.draining) return\n this.draining = true\n try {\n let action: (() => Promise<void>) | undefined\n while ((action = this.postStreamActions.shift()) !== undefined) {\n await action()\n }\n } finally {\n this.draining = false\n }\n }\n\n /**\n * Check if we should continue the flow and do so if needed\n */\n private async checkForContinuation(): Promise<void> {\n // Prevent duplicate continuation attempts\n if (this.continuationPending || this.isLoading) {\n this.continuationSkipped = true\n return\n }\n\n if (this.shouldAutoSend()) {\n this.continuationPending = true\n this.continuationSkipped = false\n let succeeded = false\n try {\n succeeded = await this.streamResponse()\n } finally {\n this.continuationPending = false\n }\n // If a queued check was skipped while continuationPending was true\n // (e.g. a chained approval responded to during the stream), re-evaluate\n // now that the flag is cleared. Only replay after a successful stream —\n // aborted or errored streams should not trigger further continuation.\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- mutated asynchronously during await\n if (this.continuationSkipped && succeeded) {\n this.continuationSkipped = false\n await this.checkForContinuation()\n }\n }\n }\n\n /**\n * Check if all tool calls are complete and we should auto-send.\n * Requires that there is at least one tool call in the last assistant message;\n * a text-only response has nothing to auto-send.\n */\n private shouldAutoSend(): boolean {\n const messages = this.processor.getMessages()\n const lastAssistant = messages.findLast(\n (m: UIMessage) => m.role === 'assistant',\n )\n if (!lastAssistant) return false\n const hasToolCalls = lastAssistant.parts.some(\n (p: MessagePart) => p.type === 'tool-call',\n )\n if (!hasToolCalls) return false\n return this.processor.areAllToolsComplete()\n }\n\n /**\n * Get current messages\n */\n getMessages(): Array<UIMessage<TTools>> {\n return this.processor.getMessages() as Array<UIMessage<TTools>>\n }\n\n /**\n * Get loading state\n */\n getIsLoading(): boolean {\n return this.isLoading\n }\n\n /**\n * Get current status\n */\n getStatus(): ChatClientState {\n return this.status\n }\n\n /**\n * Get whether the subscription loop is active\n */\n getIsSubscribed(): boolean {\n return this.isSubscribed\n }\n\n /**\n * Get current connection lifecycle status\n */\n getConnectionStatus(): ConnectionStatus {\n return this.connectionStatus\n }\n\n /**\n * Whether the shared session is actively generating.\n * Derived from stream run events (RUN_STARTED / RUN_FINISHED / RUN_ERROR).\n * Unlike `isLoading` (request-local), this reflects shared generation\n * activity visible to all subscribers (e.g. across tabs/devices).\n */\n getSessionGenerating(): boolean {\n return this.sessionGenerating\n }\n\n /**\n * Get current error\n */\n getError(): Error | undefined {\n return this.error\n }\n\n /**\n * Manually set messages\n */\n setMessagesManually(messages: Array<UIMessage<TTools>>): void {\n this.processor.setMessages(messages)\n this.devtoolsBridge.emitSnapshot()\n }\n\n /**\n * Update options refs (for use in React hooks to avoid recreating client)\n */\n updateOptions(options: ChatClientUpdateOptionsWithoutContext<TTools>): void\n updateOptions(\n options: ChatClientUpdateOptionsWithoutContext<TTools> &\n Pick<ChatClientOptions<TTools, TContext>, 'context'>,\n ): void\n updateOptions(\n options: ChatClientUpdateOptionsWithoutContext<TTools> & {\n context?: TContext | undefined\n },\n ): void {\n if (options.connection !== undefined || options.fetcher !== undefined) {\n const wasSubscribed = this.isSubscribed\n\n if (this.isLoading) {\n this.cancelInFlightStream({\n setReadyStatus: true,\n abortSubscription: true,\n })\n } else if (wasSubscribed) {\n this.abortSubscriptionLoop()\n }\n\n this.resetSessionGenerating()\n this.setIsSubscribed(false)\n this.setConnectionStatus('disconnected')\n this.connection = normalizeConnectionAdapter(\n resolveTransport({\n connection: options.connection,\n fetcher: options.fetcher,\n }),\n )\n\n if (wasSubscribed) {\n this.subscribe()\n }\n }\n // Replace each wire-payload slot independently so callers can update one\n // without wiping the other. Passing `undefined` for `body` or\n // `forwardedProps` leaves that slot unchanged; context is cleared when the\n // key is present with an `undefined` value.\n if (options.body !== undefined) {\n this.bodyOption = options.body\n }\n if (options.forwardedProps !== undefined) {\n this.forwardedPropsOption = options.forwardedProps\n }\n if ('context' in options) {\n this.context = options.context\n }\n if (options.tools !== undefined) {\n this.clientToolsRef.current = new Map()\n for (const tool of options.tools) {\n this.clientToolsRef.current.set(tool.name, tool)\n }\n this.devtoolsBridge.notifyToolsChanged()\n }\n if (options.onResponse !== undefined) {\n this.callbacksRef.current.onResponse = options.onResponse\n }\n if (options.onChunk !== undefined) {\n this.callbacksRef.current.onChunk = options.onChunk\n }\n if (options.onFinish !== undefined) {\n this.callbacksRef.current.onFinish = options.onFinish\n }\n if (options.onError !== undefined) {\n this.callbacksRef.current.onError = options.onError\n }\n if (options.onSubscriptionChange !== undefined) {\n this.callbacksRef.current.onSubscriptionChange =\n options.onSubscriptionChange\n }\n if (options.onConnectionStatusChange !== undefined) {\n this.callbacksRef.current.onConnectionStatusChange =\n options.onConnectionStatusChange\n }\n if (options.onSessionGeneratingChange !== undefined) {\n this.callbacksRef.current.onSessionGeneratingChange =\n options.onSessionGeneratingChange\n }\n if (options.onCustomEvent !== undefined) {\n this.callbacksRef.current.onCustomEvent = options.onCustomEvent\n }\n }\n\n dispose(): void {\n this.unsubscribe()\n this.devtoolsBridge.dispose()\n this.devtoolsMounted = false\n }\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,86 @@
1
+ import { StreamChunk } from '@tanstack/ai/client';
2
+ import { ChatClientPersistence, UIMessage } from './types.js';
3
+ /**
4
+ * Encapsulates everything persistence-related for `ChatClient` so the client
5
+ * itself stays focused on streaming and message state.
6
+ *
7
+ * Two responsibilities live here:
8
+ *
9
+ * 1. **Storage orchestration** — hydrate from `getItem(id)` on creation, save to
10
+ * `setItem(id, messages)` on every change through an ordered write queue, and
11
+ * `removeItem(id)` on clear. A generation counter discards stale writes when a
12
+ * removal or a newer conversation supersedes an in-flight async operation.
13
+ * 2. **Clear-during-stream suppression** — when a conversation is cleared while a
14
+ * stream is still producing, late chunks for the cleared run(s) must not
15
+ * repopulate the now-empty state. The persistor tracks the cleared ids and
16
+ * decides, per chunk, whether the client should ignore it.
17
+ *
18
+ * All adapter calls are best-effort: a throwing or rejecting adapter is swallowed
19
+ * so storage problems never break the chat.
20
+ */
21
+ export declare class ChatPersistor {
22
+ private readonly adapter;
23
+ private readonly id;
24
+ private readonly applyMessages;
25
+ private skipNextPersist;
26
+ private generation;
27
+ private queue;
28
+ private queuePending;
29
+ private messagesGeneration;
30
+ private readonly clearedMessageIds;
31
+ private readonly clearedRunIds;
32
+ private readonly ignoredActiveRunIds;
33
+ private readonly clearedToolCallIds;
34
+ private currentRunlessRunId;
35
+ constructor(adapter: ChatClientPersistence, id: string, applyMessages: (messages: Array<UIMessage>) => void);
36
+ /**
37
+ * Synchronously read the persisted messages for constructor-time hydration.
38
+ * Returns the raw `getItem` result (which may be a promise for async stores).
39
+ */
40
+ readInitial(): Array<UIMessage> | null | undefined | Promise<Array<UIMessage> | null | undefined>;
41
+ /**
42
+ * Apply messages from an async `getItem` once it resolves, unless the message
43
+ * list has already changed since hydration began.
44
+ */
45
+ hydrateAsync(persistedMessages: Array<UIMessage> | null | undefined | Promise<Array<UIMessage> | null | undefined>): void;
46
+ /**
47
+ * Record a message-list change and queue a `setItem` write for it. Skips a
48
+ * single write after {@link beginClear} so the clear's empty snapshot isn't
49
+ * persisted between `clearMessages()` and {@link remove}.
50
+ */
51
+ notifyMessagesChanged(messages: Array<UIMessage>): void;
52
+ /** Remove the persisted conversation. Invalidates any queued writes. */
53
+ remove(): void;
54
+ private runOperation;
55
+ /**
56
+ * Capture the message/run ids that exist at the moment of a clear so chunks
57
+ * still arriving for them can be ignored.
58
+ */
59
+ snapshotClear(context: {
60
+ messages: Array<UIMessage>;
61
+ activeRunIds: Set<string>;
62
+ currentRunId: string | null;
63
+ }): void;
64
+ /** Mark that the next persisted message change (the clear itself) is skipped. */
65
+ beginClear(): void;
66
+ /** Whether a chunk belongs to cleared state and should not be processed. */
67
+ shouldIgnoreChunk(chunk: StreamChunk): boolean;
68
+ /**
69
+ * The owning client calls this when a run starts so runless content chunks
70
+ * (adapters that omit `runId` on content events) can be attributed to it.
71
+ */
72
+ onRunStarted(runId: string): void;
73
+ /** Forget a settled run, advancing the runless pointer to another ignored run. */
74
+ onRunSettled(runId: string): void;
75
+ /** A session-level (runId-less) RUN_ERROR clears all ignored-run tracking. */
76
+ onSessionRunError(): void;
77
+ /** Clear the ignored-active-run markers (mirrors a session-generating reset). */
78
+ resetIgnored(): void;
79
+ /**
80
+ * Consume the current runless run id (if any), forgetting it. Used when an
81
+ * ignored, runId-less RUN_ERROR drains the run the client is still tracking.
82
+ */
83
+ takeRunlessRunId(): string | null;
84
+ private markIgnoredChunkIds;
85
+ private isRunlessChunkFromIgnoredRun;
86
+ }
@@ -0,0 +1,243 @@
1
+ import { getChunkRunId } from "./connection-adapters.js";
2
+ function getChunkToolCallId(chunk) {
3
+ return "toolCallId" in chunk && typeof chunk.toolCallId === "string" ? chunk.toolCallId : void 0;
4
+ }
5
+ function getChunkMessageId(chunk) {
6
+ return "messageId" in chunk && typeof chunk.messageId === "string" ? chunk.messageId : void 0;
7
+ }
8
+ function getChunkParentMessageId(chunk) {
9
+ return "parentMessageId" in chunk && typeof chunk.parentMessageId === "string" ? chunk.parentMessageId : void 0;
10
+ }
11
+ class ChatPersistor {
12
+ constructor(adapter, id, applyMessages) {
13
+ this.adapter = adapter;
14
+ this.id = id;
15
+ this.applyMessages = applyMessages;
16
+ }
17
+ adapter;
18
+ id;
19
+ applyMessages;
20
+ // --- storage queue state ---
21
+ skipNextPersist = false;
22
+ generation = 0;
23
+ queue = Promise.resolve();
24
+ queuePending = false;
25
+ // Bumped on every message change; lets an in-flight async hydration detect
26
+ // that the message list moved on and avoid clobbering it.
27
+ messagesGeneration = 0;
28
+ // --- clear-during-stream suppression state ---
29
+ clearedMessageIds = /* @__PURE__ */ new Set();
30
+ clearedRunIds = /* @__PURE__ */ new Set();
31
+ ignoredActiveRunIds = /* @__PURE__ */ new Set();
32
+ clearedToolCallIds = /* @__PURE__ */ new Set();
33
+ currentRunlessRunId = null;
34
+ // ---------------------------------------------------------------------------
35
+ // Storage orchestration
36
+ // ---------------------------------------------------------------------------
37
+ /**
38
+ * Synchronously read the persisted messages for constructor-time hydration.
39
+ * Returns the raw `getItem` result (which may be a promise for async stores).
40
+ */
41
+ readInitial() {
42
+ try {
43
+ return this.adapter.getItem(this.id);
44
+ } catch {
45
+ return void 0;
46
+ }
47
+ }
48
+ /**
49
+ * Apply messages from an async `getItem` once it resolves, unless the message
50
+ * list has already changed since hydration began.
51
+ */
52
+ hydrateAsync(persistedMessages) {
53
+ if (!(persistedMessages instanceof Promise)) {
54
+ return;
55
+ }
56
+ const hydrationGeneration = this.messagesGeneration;
57
+ persistedMessages.then((messages) => {
58
+ if (Array.isArray(messages) && this.messagesGeneration === hydrationGeneration) {
59
+ this.applyMessages(messages);
60
+ }
61
+ }).catch(() => {
62
+ });
63
+ }
64
+ /**
65
+ * Record a message-list change and queue a `setItem` write for it. Skips a
66
+ * single write after {@link beginClear} so the clear's empty snapshot isn't
67
+ * persisted between `clearMessages()` and {@link remove}.
68
+ */
69
+ notifyMessagesChanged(messages) {
70
+ this.messagesGeneration++;
71
+ if (this.skipNextPersist) {
72
+ this.skipNextPersist = false;
73
+ return;
74
+ }
75
+ const generation = this.generation;
76
+ const messagesSnapshot = [...messages];
77
+ this.runOperation(() => {
78
+ if (generation !== this.generation) {
79
+ return;
80
+ }
81
+ return this.adapter.setItem(this.id, messagesSnapshot);
82
+ });
83
+ }
84
+ /** Remove the persisted conversation. Invalidates any queued writes. */
85
+ remove() {
86
+ const generation = ++this.generation;
87
+ this.runOperation(() => {
88
+ if (generation !== this.generation) {
89
+ return;
90
+ }
91
+ return this.adapter.removeItem(this.id);
92
+ });
93
+ }
94
+ runOperation(operation) {
95
+ if (this.queuePending) {
96
+ const queued = this.queue.then(operation).catch(() => {
97
+ });
98
+ this.queue = queued;
99
+ void queued.finally(() => {
100
+ if (this.queue === queued) {
101
+ this.queuePending = false;
102
+ }
103
+ });
104
+ return;
105
+ }
106
+ try {
107
+ const result = operation();
108
+ if (result instanceof Promise) {
109
+ this.queuePending = true;
110
+ const queued = result.catch(() => {
111
+ });
112
+ this.queue = queued;
113
+ void queued.finally(() => {
114
+ if (this.queue === queued) {
115
+ this.queuePending = false;
116
+ }
117
+ });
118
+ }
119
+ } catch {
120
+ }
121
+ }
122
+ // ---------------------------------------------------------------------------
123
+ // Clear-during-stream suppression
124
+ // ---------------------------------------------------------------------------
125
+ /**
126
+ * Capture the message/run ids that exist at the moment of a clear so chunks
127
+ * still arriving for them can be ignored.
128
+ */
129
+ snapshotClear(context) {
130
+ for (const message of context.messages) {
131
+ this.clearedMessageIds.add(message.id);
132
+ }
133
+ for (const runId of context.activeRunIds) {
134
+ this.clearedRunIds.add(runId);
135
+ this.ignoredActiveRunIds.add(runId);
136
+ }
137
+ if (context.currentRunId) {
138
+ this.clearedRunIds.add(context.currentRunId);
139
+ this.ignoredActiveRunIds.add(context.currentRunId);
140
+ }
141
+ }
142
+ /** Mark that the next persisted message change (the clear itself) is skipped. */
143
+ beginClear() {
144
+ this.skipNextPersist = true;
145
+ }
146
+ /** Whether a chunk belongs to cleared state and should not be processed. */
147
+ shouldIgnoreChunk(chunk) {
148
+ const runId = getChunkRunId(chunk);
149
+ if (runId && this.clearedRunIds.has(runId)) {
150
+ if (chunk.type === "RUN_STARTED") {
151
+ this.ignoredActiveRunIds.add(runId);
152
+ this.currentRunlessRunId = runId;
153
+ }
154
+ this.markIgnoredChunkIds(chunk);
155
+ return true;
156
+ }
157
+ if (runId && this.ignoredActiveRunIds.has(runId)) {
158
+ this.markIgnoredChunkIds(chunk);
159
+ return true;
160
+ }
161
+ if (this.isRunlessChunkFromIgnoredRun(chunk)) {
162
+ this.markIgnoredChunkIds(chunk);
163
+ return true;
164
+ }
165
+ const toolCallId = getChunkToolCallId(chunk);
166
+ if (toolCallId && this.clearedToolCallIds.has(toolCallId)) {
167
+ return true;
168
+ }
169
+ const parentMessageId = getChunkParentMessageId(chunk);
170
+ if (parentMessageId && this.clearedMessageIds.has(parentMessageId)) {
171
+ if (toolCallId) {
172
+ this.clearedToolCallIds.add(toolCallId);
173
+ }
174
+ return true;
175
+ }
176
+ const messageId = getChunkMessageId(chunk);
177
+ if (!messageId) {
178
+ return false;
179
+ }
180
+ if (this.clearedMessageIds.has(messageId)) {
181
+ return true;
182
+ }
183
+ return false;
184
+ }
185
+ /**
186
+ * The owning client calls this when a run starts so runless content chunks
187
+ * (adapters that omit `runId` on content events) can be attributed to it.
188
+ */
189
+ onRunStarted(runId) {
190
+ this.currentRunlessRunId = runId;
191
+ }
192
+ /** Forget a settled run, advancing the runless pointer to another ignored run. */
193
+ onRunSettled(runId) {
194
+ this.ignoredActiveRunIds.delete(runId);
195
+ this.clearedRunIds.delete(runId);
196
+ if (this.currentRunlessRunId === runId) {
197
+ this.currentRunlessRunId = this.ignoredActiveRunIds.values().next().value ?? null;
198
+ }
199
+ }
200
+ /** A session-level (runId-less) RUN_ERROR clears all ignored-run tracking. */
201
+ onSessionRunError() {
202
+ this.ignoredActiveRunIds.clear();
203
+ this.currentRunlessRunId = null;
204
+ }
205
+ /** Clear the ignored-active-run markers (mirrors a session-generating reset). */
206
+ resetIgnored() {
207
+ this.ignoredActiveRunIds.clear();
208
+ }
209
+ /**
210
+ * Consume the current runless run id (if any), forgetting it. Used when an
211
+ * ignored, runId-less RUN_ERROR drains the run the client is still tracking.
212
+ */
213
+ takeRunlessRunId() {
214
+ const runId = this.currentRunlessRunId;
215
+ if (!runId) return null;
216
+ this.ignoredActiveRunIds.delete(runId);
217
+ this.clearedRunIds.delete(runId);
218
+ this.currentRunlessRunId = this.ignoredActiveRunIds.values().next().value ?? null;
219
+ return runId;
220
+ }
221
+ markIgnoredChunkIds(chunk) {
222
+ const messageId = getChunkMessageId(chunk);
223
+ if (messageId) {
224
+ this.clearedMessageIds.add(messageId);
225
+ }
226
+ const toolCallId = getChunkToolCallId(chunk);
227
+ if (toolCallId) {
228
+ this.clearedToolCallIds.add(toolCallId);
229
+ }
230
+ }
231
+ isRunlessChunkFromIgnoredRun(chunk) {
232
+ const runId = getChunkRunId(chunk);
233
+ if (runId || !this.currentRunlessRunId) return false;
234
+ if (!this.ignoredActiveRunIds.has(this.currentRunlessRunId) && !this.clearedRunIds.has(this.currentRunlessRunId)) {
235
+ return false;
236
+ }
237
+ return chunk.type === "TEXT_MESSAGE_START" || chunk.type === "TEXT_MESSAGE_CONTENT" || chunk.type === "TOOL_CALL_START" || chunk.type === "TOOL_CALL_ARGS" || chunk.type === "TOOL_CALL_END" || chunk.type === "TOOL_CALL_RESULT" || chunk.type === "MESSAGES_SNAPSHOT" || chunk.type === "RUN_ERROR";
238
+ }
239
+ }
240
+ export {
241
+ ChatPersistor
242
+ };
243
+ //# sourceMappingURL=client-persistor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-persistor.js","sources":["../../src/client-persistor.ts"],"sourcesContent":["import { getChunkRunId } from './connection-adapters'\nimport type { StreamChunk } from '@tanstack/ai/client'\nimport type { ChatClientPersistence, UIMessage } from './types'\n\n// `StreamChunk` is a discriminated union; `toolCallId` / `messageId` /\n// `parentMessageId` exist on only some members. Narrow with `in` (matching\n// `getChunkRunId`) instead of asserting a shape, so the field's real type is\n// preserved and a protocol rename can't be read past silently.\nfunction getChunkToolCallId(chunk: StreamChunk): string | undefined {\n return 'toolCallId' in chunk && typeof chunk.toolCallId === 'string'\n ? chunk.toolCallId\n : undefined\n}\n\nfunction getChunkMessageId(chunk: StreamChunk): string | undefined {\n return 'messageId' in chunk && typeof chunk.messageId === 'string'\n ? chunk.messageId\n : undefined\n}\n\nfunction getChunkParentMessageId(chunk: StreamChunk): string | undefined {\n return 'parentMessageId' in chunk && typeof chunk.parentMessageId === 'string'\n ? chunk.parentMessageId\n : undefined\n}\n\n/**\n * Encapsulates everything persistence-related for `ChatClient` so the client\n * itself stays focused on streaming and message state.\n *\n * Two responsibilities live here:\n *\n * 1. **Storage orchestration** — hydrate from `getItem(id)` on creation, save to\n * `setItem(id, messages)` on every change through an ordered write queue, and\n * `removeItem(id)` on clear. A generation counter discards stale writes when a\n * removal or a newer conversation supersedes an in-flight async operation.\n * 2. **Clear-during-stream suppression** — when a conversation is cleared while a\n * stream is still producing, late chunks for the cleared run(s) must not\n * repopulate the now-empty state. The persistor tracks the cleared ids and\n * decides, per chunk, whether the client should ignore it.\n *\n * All adapter calls are best-effort: a throwing or rejecting adapter is swallowed\n * so storage problems never break the chat.\n */\nexport class ChatPersistor {\n // --- storage queue state ---\n private skipNextPersist = false\n private generation = 0\n private queue: Promise<void> = Promise.resolve()\n private queuePending = false\n // Bumped on every message change; lets an in-flight async hydration detect\n // that the message list moved on and avoid clobbering it.\n private messagesGeneration = 0\n\n // --- clear-during-stream suppression state ---\n private readonly clearedMessageIds = new Set<string>()\n private readonly clearedRunIds = new Set<string>()\n private readonly ignoredActiveRunIds = new Set<string>()\n private readonly clearedToolCallIds = new Set<string>()\n private currentRunlessRunId: string | null = null\n\n constructor(\n private readonly adapter: ChatClientPersistence,\n private readonly id: string,\n private readonly applyMessages: (messages: Array<UIMessage>) => void,\n ) {}\n\n // ---------------------------------------------------------------------------\n // Storage orchestration\n // ---------------------------------------------------------------------------\n\n /**\n * Synchronously read the persisted messages for constructor-time hydration.\n * Returns the raw `getItem` result (which may be a promise for async stores).\n */\n readInitial():\n | Array<UIMessage>\n | null\n | undefined\n | Promise<Array<UIMessage> | null | undefined> {\n try {\n return this.adapter.getItem(this.id)\n } catch {\n return undefined\n }\n }\n\n /**\n * Apply messages from an async `getItem` once it resolves, unless the message\n * list has already changed since hydration began.\n */\n hydrateAsync(\n persistedMessages:\n | Array<UIMessage>\n | null\n | undefined\n | Promise<Array<UIMessage> | null | undefined>,\n ): void {\n if (!(persistedMessages instanceof Promise)) {\n return\n }\n\n const hydrationGeneration = this.messagesGeneration\n persistedMessages\n .then((messages) => {\n if (\n Array.isArray(messages) &&\n this.messagesGeneration === hydrationGeneration\n ) {\n this.applyMessages(messages)\n }\n })\n .catch(() => {\n // Persistence adapters are best-effort and must not break chat setup.\n })\n }\n\n /**\n * Record a message-list change and queue a `setItem` write for it. Skips a\n * single write after {@link beginClear} so the clear's empty snapshot isn't\n * persisted between `clearMessages()` and {@link remove}.\n */\n notifyMessagesChanged(messages: Array<UIMessage>): void {\n this.messagesGeneration++\n if (this.skipNextPersist) {\n this.skipNextPersist = false\n return\n }\n const generation = this.generation\n const messagesSnapshot = [...messages]\n this.runOperation(() => {\n if (generation !== this.generation) {\n return\n }\n return this.adapter.setItem(this.id, messagesSnapshot)\n })\n }\n\n /** Remove the persisted conversation. Invalidates any queued writes. */\n remove(): void {\n const generation = ++this.generation\n this.runOperation(() => {\n if (generation !== this.generation) {\n return\n }\n return this.adapter.removeItem(this.id)\n })\n }\n\n private runOperation(operation: () => void | Promise<void>): void {\n if (this.queuePending) {\n const queued = this.queue.then(operation).catch(() => {\n // Persistence adapters are best-effort and must not break chat updates.\n })\n this.queue = queued\n void queued.finally(() => {\n if (this.queue === queued) {\n this.queuePending = false\n }\n })\n return\n }\n\n try {\n const result = operation()\n if (result instanceof Promise) {\n this.queuePending = true\n const queued = result.catch(() => {\n // Persistence adapters are best-effort and must not break chat updates.\n })\n this.queue = queued\n void queued.finally(() => {\n if (this.queue === queued) {\n this.queuePending = false\n }\n })\n }\n } catch {\n // Persistence adapters are best-effort and must not break chat updates.\n }\n }\n\n // ---------------------------------------------------------------------------\n // Clear-during-stream suppression\n // ---------------------------------------------------------------------------\n\n /**\n * Capture the message/run ids that exist at the moment of a clear so chunks\n * still arriving for them can be ignored.\n */\n snapshotClear(context: {\n messages: Array<UIMessage>\n activeRunIds: Set<string>\n currentRunId: string | null\n }): void {\n for (const message of context.messages) {\n this.clearedMessageIds.add(message.id)\n }\n for (const runId of context.activeRunIds) {\n this.clearedRunIds.add(runId)\n this.ignoredActiveRunIds.add(runId)\n }\n if (context.currentRunId) {\n this.clearedRunIds.add(context.currentRunId)\n this.ignoredActiveRunIds.add(context.currentRunId)\n }\n }\n\n /** Mark that the next persisted message change (the clear itself) is skipped. */\n beginClear(): void {\n this.skipNextPersist = true\n }\n\n /** Whether a chunk belongs to cleared state and should not be processed. */\n shouldIgnoreChunk(chunk: StreamChunk): boolean {\n const runId = getChunkRunId(chunk)\n if (runId && this.clearedRunIds.has(runId)) {\n if (chunk.type === 'RUN_STARTED') {\n this.ignoredActiveRunIds.add(runId)\n this.currentRunlessRunId = runId\n }\n this.markIgnoredChunkIds(chunk)\n return true\n }\n\n if (runId && this.ignoredActiveRunIds.has(runId)) {\n this.markIgnoredChunkIds(chunk)\n return true\n }\n\n if (this.isRunlessChunkFromIgnoredRun(chunk)) {\n this.markIgnoredChunkIds(chunk)\n return true\n }\n\n const toolCallId = getChunkToolCallId(chunk)\n if (toolCallId && this.clearedToolCallIds.has(toolCallId)) {\n return true\n }\n\n const parentMessageId = getChunkParentMessageId(chunk)\n if (parentMessageId && this.clearedMessageIds.has(parentMessageId)) {\n if (toolCallId) {\n this.clearedToolCallIds.add(toolCallId)\n }\n return true\n }\n\n const messageId = getChunkMessageId(chunk)\n if (!messageId) {\n return false\n }\n if (this.clearedMessageIds.has(messageId)) {\n return true\n }\n\n return false\n }\n\n /**\n * The owning client calls this when a run starts so runless content chunks\n * (adapters that omit `runId` on content events) can be attributed to it.\n */\n onRunStarted(runId: string): void {\n this.currentRunlessRunId = runId\n }\n\n /** Forget a settled run, advancing the runless pointer to another ignored run. */\n onRunSettled(runId: string): void {\n this.ignoredActiveRunIds.delete(runId)\n this.clearedRunIds.delete(runId)\n if (this.currentRunlessRunId === runId) {\n this.currentRunlessRunId =\n this.ignoredActiveRunIds.values().next().value ?? null\n }\n }\n\n /** A session-level (runId-less) RUN_ERROR clears all ignored-run tracking. */\n onSessionRunError(): void {\n this.ignoredActiveRunIds.clear()\n this.currentRunlessRunId = null\n }\n\n /** Clear the ignored-active-run markers (mirrors a session-generating reset). */\n resetIgnored(): void {\n this.ignoredActiveRunIds.clear()\n }\n\n /**\n * Consume the current runless run id (if any), forgetting it. Used when an\n * ignored, runId-less RUN_ERROR drains the run the client is still tracking.\n */\n takeRunlessRunId(): string | null {\n const runId = this.currentRunlessRunId\n if (!runId) return null\n this.ignoredActiveRunIds.delete(runId)\n this.clearedRunIds.delete(runId)\n // Advance to another still-ignored run (mirroring `onRunSettled`) so that\n // when two cleared runs drain concurrently, draining one via a runId-less\n // RUN_ERROR doesn't stop suppressing the other's runless content.\n this.currentRunlessRunId =\n this.ignoredActiveRunIds.values().next().value ?? null\n return runId\n }\n\n private markIgnoredChunkIds(chunk: StreamChunk): void {\n const messageId = getChunkMessageId(chunk)\n if (messageId) {\n this.clearedMessageIds.add(messageId)\n }\n const toolCallId = getChunkToolCallId(chunk)\n if (toolCallId) {\n this.clearedToolCallIds.add(toolCallId)\n }\n }\n\n private isRunlessChunkFromIgnoredRun(chunk: StreamChunk): boolean {\n const runId = getChunkRunId(chunk)\n if (runId || !this.currentRunlessRunId) return false\n if (\n !this.ignoredActiveRunIds.has(this.currentRunlessRunId) &&\n !this.clearedRunIds.has(this.currentRunlessRunId)\n ) {\n return false\n }\n return (\n chunk.type === 'TEXT_MESSAGE_START' ||\n chunk.type === 'TEXT_MESSAGE_CONTENT' ||\n chunk.type === 'TOOL_CALL_START' ||\n chunk.type === 'TOOL_CALL_ARGS' ||\n chunk.type === 'TOOL_CALL_END' ||\n chunk.type === 'TOOL_CALL_RESULT' ||\n chunk.type === 'MESSAGES_SNAPSHOT' ||\n chunk.type === 'RUN_ERROR'\n )\n }\n}\n"],"names":[],"mappings":"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"}