@sqlrooms/ai-core 0.28.1-rc.0 → 0.29.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"chatTransport.d.ts","sourceRoot":"","sources":["../src/chatTransport.ts"],"names":[],"mappings":"AACA,OAAO,EAA0B,iBAAiB,EAAC,MAAM,sBAAsB,CAAC;AAEhF,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,sBAAsB,CAAC;AAEnD,OAAO,KAAK,EAAC,UAAU,EAAE,aAAa,EAAE,OAAO,EAAE,WAAW,EAAC,MAAM,IAAI,CAAC;AACxE,OAAO,EAEL,oBAAoB,EAGpB,SAAS,EACV,MAAM,IAAI,CAAC;AAOZ,OAAO,KAAK,EAAC,wBAAwB,EAAC,MAAM,SAAS,CAAC;AACtD,OAAO,EAAC,aAAa,EAAC,MAAM,SAAS,CAAC;AAOtC,MAAM,MAAM,QAAQ,GAAG;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,sBAAsB,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,QAAQ,CAAC,wBAAwB,CAAC,CAAC;IAC1C,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,eAAe,EAAE,MAAM,MAAM,CAAC;IAC9B;;;;;OAKG;IACH,cAAc,CAAC,EAAE,MAAM,aAAa,GAAG,SAAS,CAAC;CAClD,CAAC;AAEF;;GAEG;AACH,wBAAgB,4BAA4B,CAC1C,KAAK,EAAE,QAAQ,CAAC,wBAAwB,CAAC,EACzC,SAAS,CAAC,EAAE,MAAM,IAEV,YAAY,MAAM,EAAE,gBAAgB,OAAO,UAmBpD;AAwBD;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,EACxC,eAAe,CAAC,EAAE,iBAAiB,CAAC,iBAAiB,CAAC,GACrD,OAAO,CAkBT;AAED,wBAAgB,+BAA+B,CAAC,EAC9C,SAAS,EACT,KAAK,EACL,eAAe,EACf,YAAY,EACZ,OAAO,EACP,eAAe,EACf,cAAc,GACf,EAAE,mBAAmB,qFAiFrB;AAED,wBAAgB,gCAAgC,CAAC,MAAM,EAAE;IACvD,KAAK,EAAE,QAAQ,CAAC,wBAAwB,CAAC,CAAC;IAC1C,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACnB,IACS,UAAU,MAAM,EAAE,UAAU,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,iFAmD3D;AAED,wBAAgB,kBAAkB,CAAC,EACjC,KAAK,GACN,EAAE;IACD,KAAK,EAAE,QAAQ,CAAC,wBAAwB,CAAC,CAAC;CAC3C;8DAMM;QACD,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,QAAQ,CAAC;QACnB,aAAa,CAAC,EAAE,aAAa,CAAC;KAC/B;4BAiFuB,MAAM,YAAY,UAAU,CAAC,WAAW,CAAC;6CAoB9D;QACD,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,SAAS,EAAE,CAAC;KACvB;6BAsJwB,MAAM,SAAS,OAAO;EAgFlD"}
1
+ {"version":3,"file":"chatTransport.d.ts","sourceRoot":"","sources":["../src/chatTransport.ts"],"names":[],"mappings":"AACA,OAAO,EAA0B,iBAAiB,EAAC,MAAM,sBAAsB,CAAC;AAEhF,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,sBAAsB,CAAC;AAEnD,OAAO,KAAK,EAAC,UAAU,EAAE,aAAa,EAAE,OAAO,EAAE,WAAW,EAAC,MAAM,IAAI,CAAC;AACxE,OAAO,EAEL,oBAAoB,EAGpB,SAAS,EACV,MAAM,IAAI,CAAC;AAOZ,OAAO,KAAK,EAAC,wBAAwB,EAAC,MAAM,SAAS,CAAC;AACtD,OAAO,EAAC,aAAa,EAAC,MAAM,SAAS,CAAC;AAQtC,MAAM,MAAM,QAAQ,GAAG;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,sBAAsB,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,QAAQ,CAAC,wBAAwB,CAAC,CAAC;IAC1C,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,eAAe,EAAE,MAAM,MAAM,CAAC;IAC9B;;;;;OAKG;IACH,cAAc,CAAC,EAAE,MAAM,aAAa,GAAG,SAAS,CAAC;CAClD,CAAC;AAEF;;GAEG;AACH,wBAAgB,4BAA4B,CAC1C,KAAK,EAAE,QAAQ,CAAC,wBAAwB,CAAC,EACzC,SAAS,CAAC,EAAE,MAAM,IAEV,YAAY,MAAM,EAAE,gBAAgB,OAAO,UAmBpD;AAwBD;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,EACxC,eAAe,CAAC,EAAE,iBAAiB,CAAC,iBAAiB,CAAC,GACrD,OAAO,CAkBT;AAED,wBAAgB,+BAA+B,CAAC,EAC9C,SAAS,EACT,KAAK,EACL,eAAe,EACf,YAAY,EACZ,OAAO,EACP,eAAe,EACf,cAAc,GACf,EAAE,mBAAmB,qFAiFrB;AAED,wBAAgB,gCAAgC,CAAC,MAAM,EAAE;IACvD,KAAK,EAAE,QAAQ,CAAC,wBAAwB,CAAC,CAAC;IAC1C,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACnB,IACS,UAAU,MAAM,EAAE,UAAU,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,iFAmD3D;AAED,wBAAgB,kBAAkB,CAAC,EACjC,KAAK,GACN,EAAE;IACD,KAAK,EAAE,QAAQ,CAAC,wBAAwB,CAAC,CAAC;CAC3C;8DAMM;QACD,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,QAAQ,CAAC;QACnB,aAAa,CAAC,EAAE,aAAa,CAAC;KAC/B;4BAmFuB,MAAM,YAAY,UAAU,CAAC,WAAW,CAAC;6CAoB9D;QACD,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,SAAS,EAAE,CAAC;KACvB;6BAsJwB,MAAM,SAAS,OAAO;EAgFlD"}
@@ -4,7 +4,7 @@ import { getErrorMessageForDisplay } from '@sqlrooms/utils';
4
4
  import { convertToModelMessages, DefaultChatTransport, lastAssistantMessageIsCompleteWithToolCalls, streamText, } from 'ai';
5
5
  import { produce } from 'immer';
6
6
  import { AI_DEFAULT_TEMPERATURE, ANALYSIS_PENDING_ID, TOOL_CALL_CANCELLED, } from './constants';
7
- import { fixIncompleteToolCalls, mergeAbortSignals, ToolAbortError, } from './utils';
7
+ import { fixIncompleteToolCalls, mergeAbortSignals, sanitizeMessagesForLLM, ToolAbortError, } from './utils';
8
8
  /**
9
9
  * Creates a handler for tool completion that updates the tool additional data in the store
10
10
  */
@@ -115,7 +115,7 @@ export function createLocalChatTransportFactory({ sessionId, store, defaultProvi
115
115
  ]);
116
116
  const result = streamText({
117
117
  model,
118
- messages: convertToModelMessages(messagesCopy),
118
+ messages: convertToModelMessages(sanitizeMessagesForLLM(messagesCopy)),
119
119
  tools,
120
120
  system: systemInstructions,
121
121
  abortSignal,
@@ -201,7 +201,7 @@ export function createChatHandlers({ store, }) {
201
201
  const sessionMessages = (session?.uiMessages ?? []);
202
202
  const llmResult = await tool.execute(input, {
203
203
  toolCallId,
204
- messages: convertToModelMessages(sessionMessages),
204
+ messages: convertToModelMessages(sanitizeMessagesForLLM(sessionMessages)),
205
205
  abortSignal: abortController?.signal,
206
206
  });
207
207
  addToolResult?.({
@@ -1 +1 @@
1
- {"version":3,"file":"chatTransport.js","sourceRoot":"","sources":["../src/chatTransport.ts"],"names":[],"mappings":"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","sourcesContent":["import {createOpenAICompatible} from '@ai-sdk/openai-compatible';\nimport {convertToVercelAiToolV5, OpenAssistantTool} from '@openassistant/utils';\nimport type {AnalysisSessionSchema} from '@sqlrooms/ai-config';\nimport type {StoreApi} from '@sqlrooms/room-store';\nimport {getErrorMessageForDisplay} from '@sqlrooms/utils';\nimport type {DataUIPart, LanguageModel, ToolSet, UIDataTypes} from 'ai';\nimport {\n convertToModelMessages,\n DefaultChatTransport,\n lastAssistantMessageIsCompleteWithToolCalls,\n streamText,\n UIMessage,\n} from 'ai';\nimport {produce} from 'immer';\nimport {\n AI_DEFAULT_TEMPERATURE,\n ANALYSIS_PENDING_ID,\n TOOL_CALL_CANCELLED,\n} from './constants';\nimport type {AiSliceStateForTransport} from './types';\nimport {AddToolResult} from './types';\nimport {\n fixIncompleteToolCalls,\n mergeAbortSignals,\n ToolAbortError,\n} from './utils';\n\nexport type ToolCall = {\n input: string;\n toolCallId: string;\n toolName: string;\n type: 'tool-input-available';\n};\n\nexport type ChatTransportConfig = {\n sessionId: string;\n store: StoreApi<AiSliceStateForTransport>;\n defaultProvider: string;\n defaultModel: string;\n headers?: Record<string, string>;\n getInstructions: () => string;\n /**\n * Optional: supply a pre-configured custom model.\n * e.g. import {anthropic} from \"@ai-sdk/anthropic\";\n * getCustomModel: () => anthropic('claude-sonnet-4-5')\n * If provided, this model will be used instead of the default OpenAI-compatible client.\n */\n getCustomModel?: () => LanguageModel | undefined;\n};\n\n/**\n * Creates a handler for tool completion that updates the tool additional data in the store\n */\nexport function createOnToolCompletedHandler(\n store: StoreApi<AiSliceStateForTransport>,\n sessionId?: string,\n) {\n return (toolCallId: string, additionalData: unknown) => {\n // Prefer explicit sessionId if provided, otherwise attempt to resolve from toolCallId.\n const toolCallSessionId = store\n .getState()\n .ai.getToolCallSession(toolCallId);\n const resolvedSessionId =\n sessionId ||\n toolCallSessionId ||\n store.getState().ai.config.currentSessionId;\n if (!resolvedSessionId) return;\n\n store\n .getState()\n .ai.setSessionToolAdditionalData(\n resolvedSessionId,\n toolCallId,\n additionalData,\n );\n };\n}\n\nfunction getSessionById(\n store: StoreApi<AiSliceStateForTransport>,\n sessionId: string | undefined,\n): AnalysisSessionSchema | undefined {\n if (!sessionId) return undefined;\n\n const sessions = store.getState().ai.config.sessions;\n const session = sessions.find(\n (s: AnalysisSessionSchema) => s.id === sessionId,\n );\n\n if (!session) {\n return undefined;\n }\n\n if (session.id !== sessionId) {\n return undefined;\n }\n\n return session;\n}\n\n/**\n * Converts OpenAssistant tools to Vercel AI SDK tools with onToolCompleted handler\n */\nexport function convertToAiSDKTools(\n tools: Record<string, OpenAssistantTool>,\n onToolCompleted?: OpenAssistantTool['onToolCompleted'],\n): ToolSet {\n return Object.entries(tools || {}).reduce(\n (acc: ToolSet, [name, tool]: [string, OpenAssistantTool]) => {\n acc[name] = convertToVercelAiToolV5({\n ...tool,\n onToolCompleted: (toolCallId: string, additionalData: unknown) => {\n if (tool.onToolCompleted) {\n // Call the onToolCompleted handler provided by the tool if it exists\n tool.onToolCompleted(toolCallId, additionalData);\n }\n // Call the onToolCompleted handler provided by the caller if it exists\n onToolCompleted?.(toolCallId, additionalData);\n },\n });\n return acc;\n },\n {},\n );\n}\n\nexport function createLocalChatTransportFactory({\n sessionId,\n store,\n defaultProvider,\n defaultModel,\n headers,\n getInstructions,\n getCustomModel,\n}: ChatTransportConfig) {\n return () => {\n const fetchImpl = async (_input: RequestInfo | URL, init?: RequestInit) => {\n // Parse caller-supplied body defensively to avoid breaking the stream\n const body = init?.body as string;\n let parsed: unknown = {};\n try {\n parsed = body ? JSON.parse(body) : {};\n } catch {\n parsed = {};\n }\n const parsedObj = (parsed as {messages?: unknown}) || {};\n\n // Resolve provider/model/apiKey/baseUrl at call time to pick up latest settings.\n const state = store.getState();\n const sessionFromBody = getSessionById(store, sessionId);\n const provider = sessionFromBody?.modelProvider || defaultProvider;\n const modelId = sessionFromBody?.model || defaultModel;\n\n // Fetch API key and base URL dynamically to pick up settings changes\n const apiKey = state.ai.getApiKeyFromSettings();\n const baseUrl = state.ai.getBaseUrlFromSettings();\n\n // Prefer a user-supplied model if available\n let model: LanguageModel | undefined = getCustomModel?.();\n\n // Fallback to OpenAI-compatible if no custom model provided\n if (!model) {\n const openai = createOpenAICompatible({\n apiKey,\n name: provider,\n baseURL: baseUrl ?? 'https://api.openai.com/v1',\n headers,\n });\n model = openai.chatModel(modelId);\n }\n\n const messagesCopy = Array.isArray(parsedObj.messages)\n ? (parsedObj.messages as UIMessage[])\n : [];\n\n const onToolCompleted = createOnToolCompletedHandler(store, sessionId);\n const tools = convertToAiSDKTools(state.ai.tools || {}, onToolCompleted);\n // Remove execute from tools for the model call so tool invocations are\n // handled exclusively by onChatToolCall. convertToAiSDKTools is expected\n // to return fresh tool objects; if that ever changes, clone before mutate.\n Object.values(tools).forEach((tool) => {\n tool.execute = undefined;\n });\n\n // get system instructions dynamically at request time to ensure fresh table schema\n const systemInstructions = getInstructions();\n\n const providerOptions = state.ai.getProviderOptions?.({\n provider,\n modelId,\n });\n\n // Get abort controller for the owning session (from body) if available\n const sessionAbortSignal = state.ai.getAbortController(sessionId)?.signal;\n // Also respect the request-level abort signal from useChat().stop()\n const abortSignal = mergeAbortSignals([\n init?.signal ?? undefined,\n sessionAbortSignal,\n ]);\n\n const result = streamText({\n model,\n messages: convertToModelMessages(messagesCopy),\n tools,\n system: systemInstructions,\n abortSignal,\n temperature: AI_DEFAULT_TEMPERATURE,\n ...(providerOptions ? {providerOptions} : {}),\n });\n\n return result.toUIMessageStreamResponse();\n };\n\n return new DefaultChatTransport({fetch: fetchImpl});\n };\n}\n\nexport function createRemoteChatTransportFactory(params: {\n store: StoreApi<AiSliceStateForTransport>;\n defaultProvider: string;\n defaultModel: string;\n sessionId: string;\n}) {\n return (endpoint: string, headers?: Record<string, string>) => {\n const fetchImpl = async (input: RequestInfo | URL, init?: RequestInit) => {\n const {store, defaultProvider, defaultModel, sessionId} = params;\n // Get current session's model and provider at request time\n const state = store.getState();\n\n // Parse the existing body and add model information (defensive parsing)\n const body = init?.body as string;\n let parsed: unknown = {};\n try {\n parsed = body ? JSON.parse(body) : {};\n } catch {\n parsed = {};\n }\n\n const sessionFromBody = getSessionById(store, sessionId);\n const modelProvider = sessionFromBody?.modelProvider || defaultProvider;\n const model = sessionFromBody?.model || defaultModel;\n\n const parsedObj =\n typeof parsed === 'object' && parsed !== null\n ? (parsed as Record<string, unknown>)\n : {};\n const enhancedBody = {\n ...parsedObj,\n modelProvider,\n model,\n };\n\n // Merge request abort (useChat.stop) with per-session abort (cancelAnalysis)\n const sessionAbortSignal = state.ai.getAbortController(sessionId)?.signal;\n const abortSignal = mergeAbortSignals([\n init?.signal ?? undefined,\n sessionAbortSignal,\n ]);\n\n // Make the request with enhanced body\n return fetch(input, {\n ...init,\n signal: abortSignal,\n body: JSON.stringify(enhancedBody),\n });\n };\n\n return new DefaultChatTransport({\n api: endpoint,\n credentials: 'include',\n headers,\n fetch: fetchImpl,\n });\n };\n}\n\nexport function createChatHandlers({\n store,\n}: {\n store: StoreApi<AiSliceStateForTransport>;\n}) {\n return {\n onChatToolCall: async ({\n sessionId,\n toolCall,\n addToolResult,\n }: {\n sessionId: string;\n toolCall: ToolCall;\n addToolResult?: AddToolResult;\n }) => {\n const {input, toolCallId, toolName} = toolCall;\n try {\n const state = store.getState();\n const session = getSessionById(store, sessionId);\n state.ai.setToolCallSession(toolCallId, sessionId);\n\n const abortController = sessionId\n ? state.ai.getAbortController(sessionId)\n : undefined;\n if (abortController?.signal.aborted) {\n addToolResult?.({\n tool: toolName,\n toolCallId,\n state: 'output-error',\n errorText: TOOL_CALL_CANCELLED,\n });\n return;\n }\n\n const onToolCompleted = createOnToolCompletedHandler(store, sessionId);\n const tools = convertToAiSDKTools(\n state.ai.tools || {},\n onToolCompleted,\n );\n\n const tool = tools[toolName];\n if (tool && state.ai.tools[toolName]?.execute && tool.execute) {\n const sessionMessages = (session?.uiMessages ?? []) as UIMessage[];\n const llmResult = await tool.execute(input, {\n toolCallId,\n messages: convertToModelMessages(sessionMessages),\n abortSignal: abortController?.signal,\n });\n\n addToolResult?.({\n tool: toolName,\n toolCallId,\n output: llmResult,\n });\n state.ai.setToolCallSession(toolCallId, undefined);\n } else {\n // Tool has no execute function - wait for UI component to call addToolResult\n const hasToolComponent = !!state.ai.findToolComponent(toolName);\n if (hasToolComponent && state.ai.waitForToolResult) {\n try {\n await state.ai.waitForToolResult(\n sessionId,\n toolCallId,\n abortController?.signal,\n );\n state.ai.setToolCallSession(toolCallId, undefined);\n } catch (error) {\n if (addToolResult && error instanceof Error) {\n addToolResult({\n tool: toolName,\n toolCallId,\n state: 'output-error',\n errorText: error.message,\n });\n }\n throw error;\n }\n }\n }\n // If no ToolComponent, we still return (no-op) - the UI won't render anything\n // and the tool call will remain incomplete, which is fine for error handling\n } catch (error) {\n const isAbortError = error instanceof ToolAbortError;\n addToolResult?.({\n tool: toolName,\n toolCallId,\n state: 'output-error',\n errorText: isAbortError\n ? TOOL_CALL_CANCELLED\n : getErrorMessageForDisplay(error),\n });\n // ensure mapping cleared on error too\n store.getState().ai.setToolCallSession(toolCallId, undefined);\n }\n },\n onChatData: (sessionId: string, dataPart: DataUIPart<UIDataTypes>) => {\n if (\n dataPart.type === 'data-tool-additional-output' &&\n dataPart.data &&\n (dataPart.data as {toolCallId?: unknown}).toolCallId != null\n ) {\n const {toolCallId, output} = dataPart.data as {\n toolCallId: string;\n output: unknown;\n };\n if (sessionId) {\n store\n .getState()\n .ai.setSessionToolAdditionalData(sessionId, toolCallId, output);\n }\n }\n },\n onChatFinish: ({\n sessionId,\n messages,\n }: {\n sessionId: string;\n messages: UIMessage[];\n }) => {\n if (!sessionId) return;\n try {\n const state = store.getState();\n const abortController = state.ai.getAbortController(sessionId);\n\n // check if the analysis has been aborted, force-complete and clean up immediately\n const aborted = !!abortController?.signal.aborted;\n if (aborted) {\n const sessionMessages =\n (getSessionById(store, sessionId)?.uiMessages as UIMessage[]) || [];\n const sourceMessages =\n messages && messages.length > 0 ? messages : sessionMessages;\n const completedMessages = fixIncompleteToolCalls(sourceMessages);\n state.ai.setSessionUiMessages(sessionId, completedMessages);\n\n state.ai.setIsRunning(sessionId, false);\n state.ai.setAbortController(sessionId, undefined);\n\n // Ensure an analysis result exists and is marked as cancelled\n store.setState((stateToUpdate: AiSliceStateForTransport) =>\n produce(stateToUpdate, (draft: AiSliceStateForTransport) => {\n const targetSession = draft.ai.config.sessions.find(\n (s: AnalysisSessionSchema) => s.id === sessionId,\n );\n if (!targetSession) return;\n\n const lastUserMessage = completedMessages\n .filter((msg) => msg.role === 'user')\n .slice(-1)[0];\n if (!lastUserMessage) return;\n\n const promptText = lastUserMessage.parts\n .filter((part) => part.type === 'text')\n .map((part) => (part as {text: string}).text)\n .join('');\n\n const pendingIndex = targetSession.analysisResults.findIndex(\n (result) => result.id === ANALYSIS_PENDING_ID,\n );\n\n if (pendingIndex !== -1) {\n targetSession.analysisResults[pendingIndex] = {\n id: lastUserMessage.id,\n prompt: promptText,\n errorMessage: {error: TOOL_CALL_CANCELLED},\n isCompleted: true,\n };\n } else {\n const existing = targetSession.analysisResults.find(\n (r) => r.id === lastUserMessage.id,\n );\n if (!existing) {\n targetSession.analysisResults.push({\n id: lastUserMessage.id,\n prompt: promptText,\n errorMessage: {error: TOOL_CALL_CANCELLED},\n isCompleted: true,\n });\n }\n }\n }),\n );\n return;\n }\n\n // fix any incomplete tool-calls before saving (can happen with AbortController)\n const completedMessages = fixIncompleteToolCalls(messages);\n state.ai.setSessionUiMessages(sessionId, completedMessages);\n\n store.setState((stateToUpdate: AiSliceStateForTransport) =>\n produce(stateToUpdate, (draft: AiSliceStateForTransport) => {\n const targetSession = draft.ai.config.sessions.find(\n (s: AnalysisSessionSchema) => s.id === sessionId,\n );\n if (!targetSession) return;\n\n const lastUserMessage = completedMessages\n .filter((msg) => msg.role === 'user')\n .slice(-1)[0];\n\n if (lastUserMessage) {\n const promptText = lastUserMessage.parts\n .filter((part) => part.type === 'text')\n .map((part) => (part as {text: string}).text)\n .join('');\n\n const pendingIndex = targetSession.analysisResults.findIndex(\n (result) => result.id === ANALYSIS_PENDING_ID,\n );\n\n if (pendingIndex !== -1) {\n targetSession.analysisResults[pendingIndex] = {\n id: lastUserMessage.id,\n prompt: promptText,\n isCompleted: true,\n };\n } else {\n const existingResult = targetSession.analysisResults.find(\n (result) => result.id === lastUserMessage.id,\n );\n if (!existingResult) {\n targetSession.analysisResults.push({\n id: lastUserMessage.id,\n prompt: promptText,\n isCompleted: true,\n });\n }\n }\n }\n }),\n );\n\n const shouldAutoSendNext = lastAssistantMessageIsCompleteWithToolCalls({\n messages: completedMessages,\n });\n\n const lastMessage = completedMessages[completedMessages.length - 1];\n const isLastMessageAssistant = lastMessage?.role === 'assistant';\n let tailHasTool = false;\n if (isLastMessageAssistant) {\n const parts = lastMessage?.parts ?? [];\n let lastStepStartIndex = -1;\n for (let i = parts.length - 1; i >= 0; i--) {\n if (parts[i]?.type === 'step-start') {\n lastStepStartIndex = i;\n break;\n }\n }\n const tailParts = parts.slice(lastStepStartIndex + 1);\n tailHasTool = tailParts.some(\n (part) =>\n typeof part?.type === 'string' &&\n (part.type.startsWith('tool-') || part.type === 'dynamic-tool'),\n );\n }\n\n const shouldEndAnalysis =\n (isLastMessageAssistant && !shouldAutoSendNext && !tailHasTool) ||\n (!shouldAutoSendNext && !isLastMessageAssistant);\n\n if (shouldEndAnalysis) {\n state.ai.setIsRunning(sessionId, false);\n state.ai.setAbortController(sessionId, undefined);\n }\n } catch (err) {\n console.error('onChatFinish error:', err);\n throw err;\n }\n },\n onChatError: (sessionId: string, error: unknown) => {\n try {\n let errMsg = getErrorMessageForDisplay(error);\n if (!errMsg || errMsg.trim().length === 0) {\n errMsg = 'Unknown error';\n }\n\n // Detect API key errors (401/403 or common error messages)\n const isApiKeyError = isAuthenticationError(error, errMsg);\n if (isApiKeyError) {\n const session = getSessionById(store, sessionId);\n const provider = session?.modelProvider || 'openai';\n store.getState().ai.setApiKeyError(provider, true);\n }\n\n store.setState((state: AiSliceStateForTransport) =>\n produce(state, (draft: AiSliceStateForTransport) => {\n if (!sessionId) return;\n const targetSession = draft.ai.config.sessions.find(\n (s: AnalysisSessionSchema) => s.id === sessionId,\n );\n if (targetSession) {\n // fix any incomplete tool-calls before saving (can happen with AbortController)\n const existingMessages = (targetSession.uiMessages ||\n []) as UIMessage[];\n targetSession.uiMessages = fixIncompleteToolCalls(\n existingMessages,\n ) as AnalysisSessionSchema['uiMessages'];\n\n const uiMessages = targetSession.uiMessages as UIMessage[];\n const lastUserMessage = uiMessages\n .filter((msg) => msg.role === 'user')\n .slice(-1)[0];\n\n if (lastUserMessage) {\n const promptText = lastUserMessage.parts\n .filter((part) => part.type === 'text')\n .map((part) => (part as {text: string}).text)\n .join('');\n\n const pendingIndex = targetSession.analysisResults.findIndex(\n (result) => result.id === ANALYSIS_PENDING_ID,\n );\n\n if (pendingIndex !== -1) {\n targetSession.analysisResults[pendingIndex] = {\n id: lastUserMessage.id,\n prompt: promptText,\n errorMessage: {error: errMsg},\n isCompleted: true,\n };\n } else {\n const existingResult = targetSession.analysisResults.find(\n (result) => result.id === lastUserMessage.id,\n );\n\n if (!existingResult) {\n targetSession.analysisResults.push({\n id: lastUserMessage.id,\n prompt: promptText,\n errorMessage: {error: errMsg},\n isCompleted: true,\n });\n } else {\n existingResult.errorMessage = {error: errMsg};\n }\n }\n }\n }\n }),\n );\n\n store.getState().ai.setIsRunning(sessionId, false);\n store.getState().ai.setAbortController(sessionId, undefined);\n } catch (err) {\n console.error('Failed to store chat error:', err);\n throw err;\n }\n },\n };\n}\n\n/**\n * Detects if an error is related to API key authentication issues.\n * Checks for HTTP 401/403 status codes and common error message patterns.\n */\nfunction isAuthenticationError(error: unknown, errorMessage: string): boolean {\n // Check for HTTP status codes in the error object\n if (error && typeof error === 'object') {\n const err = error as Record<string, unknown>;\n const status =\n err.status ??\n err.statusCode ??\n (err.response as Record<string, unknown>)?.status;\n if (status === 401 || status === 403) {\n return true;\n }\n }\n\n // Check for common authentication error patterns in the message\n const lowerMsg = errorMessage.toLowerCase();\n const authPatterns = [\n 'invalid api key',\n 'incorrect api key',\n 'invalid_api_key',\n 'unauthorized',\n 'authentication failed',\n 'api key is invalid',\n 'api key not found',\n 'invalid authorization',\n 'invalid credentials',\n 'access denied',\n '401',\n '403',\n ];\n\n return authPatterns.some((pattern) => lowerMsg.includes(pattern));\n}\n"]}
1
+ {"version":3,"file":"chatTransport.js","sourceRoot":"","sources":["../src/chatTransport.ts"],"names":[],"mappings":"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","sourcesContent":["import {createOpenAICompatible} from '@ai-sdk/openai-compatible';\nimport {convertToVercelAiToolV5, OpenAssistantTool} from '@openassistant/utils';\nimport type {AnalysisSessionSchema} from '@sqlrooms/ai-config';\nimport type {StoreApi} from '@sqlrooms/room-store';\nimport {getErrorMessageForDisplay} from '@sqlrooms/utils';\nimport type {DataUIPart, LanguageModel, ToolSet, UIDataTypes} from 'ai';\nimport {\n convertToModelMessages,\n DefaultChatTransport,\n lastAssistantMessageIsCompleteWithToolCalls,\n streamText,\n UIMessage,\n} from 'ai';\nimport {produce} from 'immer';\nimport {\n AI_DEFAULT_TEMPERATURE,\n ANALYSIS_PENDING_ID,\n TOOL_CALL_CANCELLED,\n} from './constants';\nimport type {AiSliceStateForTransport} from './types';\nimport {AddToolResult} from './types';\nimport {\n fixIncompleteToolCalls,\n mergeAbortSignals,\n sanitizeMessagesForLLM,\n ToolAbortError,\n} from './utils';\n\nexport type ToolCall = {\n input: string;\n toolCallId: string;\n toolName: string;\n type: 'tool-input-available';\n};\n\nexport type ChatTransportConfig = {\n sessionId: string;\n store: StoreApi<AiSliceStateForTransport>;\n defaultProvider: string;\n defaultModel: string;\n headers?: Record<string, string>;\n getInstructions: () => string;\n /**\n * Optional: supply a pre-configured custom model.\n * e.g. import {anthropic} from \"@ai-sdk/anthropic\";\n * getCustomModel: () => anthropic('claude-sonnet-4-5')\n * If provided, this model will be used instead of the default OpenAI-compatible client.\n */\n getCustomModel?: () => LanguageModel | undefined;\n};\n\n/**\n * Creates a handler for tool completion that updates the tool additional data in the store\n */\nexport function createOnToolCompletedHandler(\n store: StoreApi<AiSliceStateForTransport>,\n sessionId?: string,\n) {\n return (toolCallId: string, additionalData: unknown) => {\n // Prefer explicit sessionId if provided, otherwise attempt to resolve from toolCallId.\n const toolCallSessionId = store\n .getState()\n .ai.getToolCallSession(toolCallId);\n const resolvedSessionId =\n sessionId ||\n toolCallSessionId ||\n store.getState().ai.config.currentSessionId;\n if (!resolvedSessionId) return;\n\n store\n .getState()\n .ai.setSessionToolAdditionalData(\n resolvedSessionId,\n toolCallId,\n additionalData,\n );\n };\n}\n\nfunction getSessionById(\n store: StoreApi<AiSliceStateForTransport>,\n sessionId: string | undefined,\n): AnalysisSessionSchema | undefined {\n if (!sessionId) return undefined;\n\n const sessions = store.getState().ai.config.sessions;\n const session = sessions.find(\n (s: AnalysisSessionSchema) => s.id === sessionId,\n );\n\n if (!session) {\n return undefined;\n }\n\n if (session.id !== sessionId) {\n return undefined;\n }\n\n return session;\n}\n\n/**\n * Converts OpenAssistant tools to Vercel AI SDK tools with onToolCompleted handler\n */\nexport function convertToAiSDKTools(\n tools: Record<string, OpenAssistantTool>,\n onToolCompleted?: OpenAssistantTool['onToolCompleted'],\n): ToolSet {\n return Object.entries(tools || {}).reduce(\n (acc: ToolSet, [name, tool]: [string, OpenAssistantTool]) => {\n acc[name] = convertToVercelAiToolV5({\n ...tool,\n onToolCompleted: (toolCallId: string, additionalData: unknown) => {\n if (tool.onToolCompleted) {\n // Call the onToolCompleted handler provided by the tool if it exists\n tool.onToolCompleted(toolCallId, additionalData);\n }\n // Call the onToolCompleted handler provided by the caller if it exists\n onToolCompleted?.(toolCallId, additionalData);\n },\n });\n return acc;\n },\n {},\n );\n}\n\nexport function createLocalChatTransportFactory({\n sessionId,\n store,\n defaultProvider,\n defaultModel,\n headers,\n getInstructions,\n getCustomModel,\n}: ChatTransportConfig) {\n return () => {\n const fetchImpl = async (_input: RequestInfo | URL, init?: RequestInit) => {\n // Parse caller-supplied body defensively to avoid breaking the stream\n const body = init?.body as string;\n let parsed: unknown = {};\n try {\n parsed = body ? JSON.parse(body) : {};\n } catch {\n parsed = {};\n }\n const parsedObj = (parsed as {messages?: unknown}) || {};\n\n // Resolve provider/model/apiKey/baseUrl at call time to pick up latest settings.\n const state = store.getState();\n const sessionFromBody = getSessionById(store, sessionId);\n const provider = sessionFromBody?.modelProvider || defaultProvider;\n const modelId = sessionFromBody?.model || defaultModel;\n\n // Fetch API key and base URL dynamically to pick up settings changes\n const apiKey = state.ai.getApiKeyFromSettings();\n const baseUrl = state.ai.getBaseUrlFromSettings();\n\n // Prefer a user-supplied model if available\n let model: LanguageModel | undefined = getCustomModel?.();\n\n // Fallback to OpenAI-compatible if no custom model provided\n if (!model) {\n const openai = createOpenAICompatible({\n apiKey,\n name: provider,\n baseURL: baseUrl ?? 'https://api.openai.com/v1',\n headers,\n });\n model = openai.chatModel(modelId);\n }\n\n const messagesCopy = Array.isArray(parsedObj.messages)\n ? (parsedObj.messages as UIMessage[])\n : [];\n\n const onToolCompleted = createOnToolCompletedHandler(store, sessionId);\n const tools = convertToAiSDKTools(state.ai.tools || {}, onToolCompleted);\n // Remove execute from tools for the model call so tool invocations are\n // handled exclusively by onChatToolCall. convertToAiSDKTools is expected\n // to return fresh tool objects; if that ever changes, clone before mutate.\n Object.values(tools).forEach((tool) => {\n tool.execute = undefined;\n });\n\n // get system instructions dynamically at request time to ensure fresh table schema\n const systemInstructions = getInstructions();\n\n const providerOptions = state.ai.getProviderOptions?.({\n provider,\n modelId,\n });\n\n // Get abort controller for the owning session (from body) if available\n const sessionAbortSignal = state.ai.getAbortController(sessionId)?.signal;\n // Also respect the request-level abort signal from useChat().stop()\n const abortSignal = mergeAbortSignals([\n init?.signal ?? undefined,\n sessionAbortSignal,\n ]);\n\n const result = streamText({\n model,\n messages: convertToModelMessages(sanitizeMessagesForLLM(messagesCopy)),\n tools,\n system: systemInstructions,\n abortSignal,\n temperature: AI_DEFAULT_TEMPERATURE,\n ...(providerOptions ? {providerOptions} : {}),\n });\n\n return result.toUIMessageStreamResponse();\n };\n\n return new DefaultChatTransport({fetch: fetchImpl});\n };\n}\n\nexport function createRemoteChatTransportFactory(params: {\n store: StoreApi<AiSliceStateForTransport>;\n defaultProvider: string;\n defaultModel: string;\n sessionId: string;\n}) {\n return (endpoint: string, headers?: Record<string, string>) => {\n const fetchImpl = async (input: RequestInfo | URL, init?: RequestInit) => {\n const {store, defaultProvider, defaultModel, sessionId} = params;\n // Get current session's model and provider at request time\n const state = store.getState();\n\n // Parse the existing body and add model information (defensive parsing)\n const body = init?.body as string;\n let parsed: unknown = {};\n try {\n parsed = body ? JSON.parse(body) : {};\n } catch {\n parsed = {};\n }\n\n const sessionFromBody = getSessionById(store, sessionId);\n const modelProvider = sessionFromBody?.modelProvider || defaultProvider;\n const model = sessionFromBody?.model || defaultModel;\n\n const parsedObj =\n typeof parsed === 'object' && parsed !== null\n ? (parsed as Record<string, unknown>)\n : {};\n const enhancedBody = {\n ...parsedObj,\n modelProvider,\n model,\n };\n\n // Merge request abort (useChat.stop) with per-session abort (cancelAnalysis)\n const sessionAbortSignal = state.ai.getAbortController(sessionId)?.signal;\n const abortSignal = mergeAbortSignals([\n init?.signal ?? undefined,\n sessionAbortSignal,\n ]);\n\n // Make the request with enhanced body\n return fetch(input, {\n ...init,\n signal: abortSignal,\n body: JSON.stringify(enhancedBody),\n });\n };\n\n return new DefaultChatTransport({\n api: endpoint,\n credentials: 'include',\n headers,\n fetch: fetchImpl,\n });\n };\n}\n\nexport function createChatHandlers({\n store,\n}: {\n store: StoreApi<AiSliceStateForTransport>;\n}) {\n return {\n onChatToolCall: async ({\n sessionId,\n toolCall,\n addToolResult,\n }: {\n sessionId: string;\n toolCall: ToolCall;\n addToolResult?: AddToolResult;\n }) => {\n const {input, toolCallId, toolName} = toolCall;\n try {\n const state = store.getState();\n const session = getSessionById(store, sessionId);\n state.ai.setToolCallSession(toolCallId, sessionId);\n\n const abortController = sessionId\n ? state.ai.getAbortController(sessionId)\n : undefined;\n if (abortController?.signal.aborted) {\n addToolResult?.({\n tool: toolName,\n toolCallId,\n state: 'output-error',\n errorText: TOOL_CALL_CANCELLED,\n });\n return;\n }\n\n const onToolCompleted = createOnToolCompletedHandler(store, sessionId);\n const tools = convertToAiSDKTools(\n state.ai.tools || {},\n onToolCompleted,\n );\n\n const tool = tools[toolName];\n if (tool && state.ai.tools[toolName]?.execute && tool.execute) {\n const sessionMessages = (session?.uiMessages ?? []) as UIMessage[];\n const llmResult = await tool.execute(input, {\n toolCallId,\n messages: convertToModelMessages(\n sanitizeMessagesForLLM(sessionMessages),\n ),\n abortSignal: abortController?.signal,\n });\n\n addToolResult?.({\n tool: toolName,\n toolCallId,\n output: llmResult,\n });\n state.ai.setToolCallSession(toolCallId, undefined);\n } else {\n // Tool has no execute function - wait for UI component to call addToolResult\n const hasToolComponent = !!state.ai.findToolComponent(toolName);\n if (hasToolComponent && state.ai.waitForToolResult) {\n try {\n await state.ai.waitForToolResult(\n sessionId,\n toolCallId,\n abortController?.signal,\n );\n state.ai.setToolCallSession(toolCallId, undefined);\n } catch (error) {\n if (addToolResult && error instanceof Error) {\n addToolResult({\n tool: toolName,\n toolCallId,\n state: 'output-error',\n errorText: error.message,\n });\n }\n throw error;\n }\n }\n }\n // If no ToolComponent, we still return (no-op) - the UI won't render anything\n // and the tool call will remain incomplete, which is fine for error handling\n } catch (error) {\n const isAbortError = error instanceof ToolAbortError;\n addToolResult?.({\n tool: toolName,\n toolCallId,\n state: 'output-error',\n errorText: isAbortError\n ? TOOL_CALL_CANCELLED\n : getErrorMessageForDisplay(error),\n });\n // ensure mapping cleared on error too\n store.getState().ai.setToolCallSession(toolCallId, undefined);\n }\n },\n onChatData: (sessionId: string, dataPart: DataUIPart<UIDataTypes>) => {\n if (\n dataPart.type === 'data-tool-additional-output' &&\n dataPart.data &&\n (dataPart.data as {toolCallId?: unknown}).toolCallId != null\n ) {\n const {toolCallId, output} = dataPart.data as {\n toolCallId: string;\n output: unknown;\n };\n if (sessionId) {\n store\n .getState()\n .ai.setSessionToolAdditionalData(sessionId, toolCallId, output);\n }\n }\n },\n onChatFinish: ({\n sessionId,\n messages,\n }: {\n sessionId: string;\n messages: UIMessage[];\n }) => {\n if (!sessionId) return;\n try {\n const state = store.getState();\n const abortController = state.ai.getAbortController(sessionId);\n\n // check if the analysis has been aborted, force-complete and clean up immediately\n const aborted = !!abortController?.signal.aborted;\n if (aborted) {\n const sessionMessages =\n (getSessionById(store, sessionId)?.uiMessages as UIMessage[]) || [];\n const sourceMessages =\n messages && messages.length > 0 ? messages : sessionMessages;\n const completedMessages = fixIncompleteToolCalls(sourceMessages);\n state.ai.setSessionUiMessages(sessionId, completedMessages);\n\n state.ai.setIsRunning(sessionId, false);\n state.ai.setAbortController(sessionId, undefined);\n\n // Ensure an analysis result exists and is marked as cancelled\n store.setState((stateToUpdate: AiSliceStateForTransport) =>\n produce(stateToUpdate, (draft: AiSliceStateForTransport) => {\n const targetSession = draft.ai.config.sessions.find(\n (s: AnalysisSessionSchema) => s.id === sessionId,\n );\n if (!targetSession) return;\n\n const lastUserMessage = completedMessages\n .filter((msg) => msg.role === 'user')\n .slice(-1)[0];\n if (!lastUserMessage) return;\n\n const promptText = lastUserMessage.parts\n .filter((part) => part.type === 'text')\n .map((part) => (part as {text: string}).text)\n .join('');\n\n const pendingIndex = targetSession.analysisResults.findIndex(\n (result) => result.id === ANALYSIS_PENDING_ID,\n );\n\n if (pendingIndex !== -1) {\n targetSession.analysisResults[pendingIndex] = {\n id: lastUserMessage.id,\n prompt: promptText,\n errorMessage: {error: TOOL_CALL_CANCELLED},\n isCompleted: true,\n };\n } else {\n const existing = targetSession.analysisResults.find(\n (r) => r.id === lastUserMessage.id,\n );\n if (!existing) {\n targetSession.analysisResults.push({\n id: lastUserMessage.id,\n prompt: promptText,\n errorMessage: {error: TOOL_CALL_CANCELLED},\n isCompleted: true,\n });\n }\n }\n }),\n );\n return;\n }\n\n // fix any incomplete tool-calls before saving (can happen with AbortController)\n const completedMessages = fixIncompleteToolCalls(messages);\n state.ai.setSessionUiMessages(sessionId, completedMessages);\n\n store.setState((stateToUpdate: AiSliceStateForTransport) =>\n produce(stateToUpdate, (draft: AiSliceStateForTransport) => {\n const targetSession = draft.ai.config.sessions.find(\n (s: AnalysisSessionSchema) => s.id === sessionId,\n );\n if (!targetSession) return;\n\n const lastUserMessage = completedMessages\n .filter((msg) => msg.role === 'user')\n .slice(-1)[0];\n\n if (lastUserMessage) {\n const promptText = lastUserMessage.parts\n .filter((part) => part.type === 'text')\n .map((part) => (part as {text: string}).text)\n .join('');\n\n const pendingIndex = targetSession.analysisResults.findIndex(\n (result) => result.id === ANALYSIS_PENDING_ID,\n );\n\n if (pendingIndex !== -1) {\n targetSession.analysisResults[pendingIndex] = {\n id: lastUserMessage.id,\n prompt: promptText,\n isCompleted: true,\n };\n } else {\n const existingResult = targetSession.analysisResults.find(\n (result) => result.id === lastUserMessage.id,\n );\n if (!existingResult) {\n targetSession.analysisResults.push({\n id: lastUserMessage.id,\n prompt: promptText,\n isCompleted: true,\n });\n }\n }\n }\n }),\n );\n\n const shouldAutoSendNext = lastAssistantMessageIsCompleteWithToolCalls({\n messages: completedMessages,\n });\n\n const lastMessage = completedMessages[completedMessages.length - 1];\n const isLastMessageAssistant = lastMessage?.role === 'assistant';\n let tailHasTool = false;\n if (isLastMessageAssistant) {\n const parts = lastMessage?.parts ?? [];\n let lastStepStartIndex = -1;\n for (let i = parts.length - 1; i >= 0; i--) {\n if (parts[i]?.type === 'step-start') {\n lastStepStartIndex = i;\n break;\n }\n }\n const tailParts = parts.slice(lastStepStartIndex + 1);\n tailHasTool = tailParts.some(\n (part) =>\n typeof part?.type === 'string' &&\n (part.type.startsWith('tool-') || part.type === 'dynamic-tool'),\n );\n }\n\n const shouldEndAnalysis =\n (isLastMessageAssistant && !shouldAutoSendNext && !tailHasTool) ||\n (!shouldAutoSendNext && !isLastMessageAssistant);\n\n if (shouldEndAnalysis) {\n state.ai.setIsRunning(sessionId, false);\n state.ai.setAbortController(sessionId, undefined);\n }\n } catch (err) {\n console.error('onChatFinish error:', err);\n throw err;\n }\n },\n onChatError: (sessionId: string, error: unknown) => {\n try {\n let errMsg = getErrorMessageForDisplay(error);\n if (!errMsg || errMsg.trim().length === 0) {\n errMsg = 'Unknown error';\n }\n\n // Detect API key errors (401/403 or common error messages)\n const isApiKeyError = isAuthenticationError(error, errMsg);\n if (isApiKeyError) {\n const session = getSessionById(store, sessionId);\n const provider = session?.modelProvider || 'openai';\n store.getState().ai.setApiKeyError(provider, true);\n }\n\n store.setState((state: AiSliceStateForTransport) =>\n produce(state, (draft: AiSliceStateForTransport) => {\n if (!sessionId) return;\n const targetSession = draft.ai.config.sessions.find(\n (s: AnalysisSessionSchema) => s.id === sessionId,\n );\n if (targetSession) {\n // fix any incomplete tool-calls before saving (can happen with AbortController)\n const existingMessages = (targetSession.uiMessages ||\n []) as UIMessage[];\n targetSession.uiMessages = fixIncompleteToolCalls(\n existingMessages,\n ) as AnalysisSessionSchema['uiMessages'];\n\n const uiMessages = targetSession.uiMessages as UIMessage[];\n const lastUserMessage = uiMessages\n .filter((msg) => msg.role === 'user')\n .slice(-1)[0];\n\n if (lastUserMessage) {\n const promptText = lastUserMessage.parts\n .filter((part) => part.type === 'text')\n .map((part) => (part as {text: string}).text)\n .join('');\n\n const pendingIndex = targetSession.analysisResults.findIndex(\n (result) => result.id === ANALYSIS_PENDING_ID,\n );\n\n if (pendingIndex !== -1) {\n targetSession.analysisResults[pendingIndex] = {\n id: lastUserMessage.id,\n prompt: promptText,\n errorMessage: {error: errMsg},\n isCompleted: true,\n };\n } else {\n const existingResult = targetSession.analysisResults.find(\n (result) => result.id === lastUserMessage.id,\n );\n\n if (!existingResult) {\n targetSession.analysisResults.push({\n id: lastUserMessage.id,\n prompt: promptText,\n errorMessage: {error: errMsg},\n isCompleted: true,\n });\n } else {\n existingResult.errorMessage = {error: errMsg};\n }\n }\n }\n }\n }),\n );\n\n store.getState().ai.setIsRunning(sessionId, false);\n store.getState().ai.setAbortController(sessionId, undefined);\n } catch (err) {\n console.error('Failed to store chat error:', err);\n throw err;\n }\n },\n };\n}\n\n/**\n * Detects if an error is related to API key authentication issues.\n * Checks for HTTP 401/403 status codes and common error message patterns.\n */\nfunction isAuthenticationError(error: unknown, errorMessage: string): boolean {\n // Check for HTTP status codes in the error object\n if (error && typeof error === 'object') {\n const err = error as Record<string, unknown>;\n const status =\n err.status ??\n err.statusCode ??\n (err.response as Record<string, unknown>)?.status;\n if (status === 401 || status === 403) {\n return true;\n }\n }\n\n // Check for common authentication error patterns in the message\n const lowerMsg = errorMessage.toLowerCase();\n const authPatterns = [\n 'invalid api key',\n 'incorrect api key',\n 'invalid_api_key',\n 'unauthorized',\n 'authentication failed',\n 'api key is invalid',\n 'api key not found',\n 'invalid authorization',\n 'invalid credentials',\n 'access denied',\n '401',\n '403',\n ];\n\n return authPatterns.some((pattern) => lowerMsg.includes(pattern));\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"ToolPartRenderer.d.ts","sourceRoot":"","sources":["../../src/components/ToolPartRenderer.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,qBAAqB,CAAC;AAwFvD;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,GAAI,2CAI9B;IACD,IAAI,EAAE,aAAa,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC9C,mDA+FA,CAAC"}
1
+ {"version":3,"file":"ToolPartRenderer.d.ts","sourceRoot":"","sources":["../../src/components/ToolPartRenderer.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,qBAAqB,CAAC;AAoFvD;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,GAAI,2CAI9B;IACD,IAAI,EAAE,aAAa,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC9C,mDA+FA,CAAC"}
@@ -10,7 +10,7 @@ import { ToolCallInfo } from './ToolCallInfo';
10
10
  */
11
11
  const AgentProgressRenderer = ({ agentToolCalls, finalOutput, reasoning }) => {
12
12
  const findToolComponent = useStoreWithAi((s) => s.ai.findToolComponent);
13
- return (_jsxs("div", { className: "mt-2 px-5 text-[0.9em]", children: [reasoning ? (_jsx("div", { className: "mb-2 text-sm text-gray-500 prose prose-sm dark:prose-invert max-w-none", children: _jsx(Markdown, { remarkPlugins: [remarkGfm], children: reasoning }) })) : null, _jsx("div", { className: "ml-3", children: agentToolCalls.map((toolCall) => {
13
+ return (_jsxs("div", { className: "mt-2 px-5 text-[0.9em]", children: [reasoning ? (_jsx("div", { className: "prose prose-sm dark:prose-invert mb-2 max-w-none text-sm text-gray-500", children: _jsx(Markdown, { remarkPlugins: [remarkGfm], children: reasoning }) })) : null, _jsx("div", { className: "ml-3", children: agentToolCalls.map((toolCall) => {
14
14
  const ToolComponent = findToolComponent(toolCall.toolName);
15
15
  const isSuccess = toolCall.state === 'success';
16
16
  const isError = toolCall.state === 'error';
@@ -18,8 +18,8 @@ const AgentProgressRenderer = ({ agentToolCalls, finalOutput, reasoning }) => {
18
18
  const hasObjectOutput = toolCall.output &&
19
19
  typeof toolCall.output === 'object' &&
20
20
  toolCall.output !== null;
21
- return (_jsxs("div", { className: `mb-2 ${isError ? 'text-red-700' : 'text-gray-600'}`, children: [_jsxs("div", { className: "mb-1 flex items-start", children: [_jsxs("span", { className: "mr-2 min-w-[16px]", children: [isSuccess && '✓', isError && '✗', toolCall.state === 'pending' && '○'] }), _jsxs("div", { className: "flex-1", children: [_jsx("span", { className: "font-medium", children: toolCall.toolName }), isError && toolCall.errorText && (_jsxs("div", { className: "mt-0.5 text-[0.9em] text-red-700", children: ["Error: ", toolCall.errorText] }))] })] }), isSuccess && hasComponent && hasObjectOutput ? (_jsx("div", { className: "mt-1 ml-6", children: _jsx(ToolComponent, { ...toolCall.output }) })) : null] }, toolCall.toolCallId));
22
- }) }), finalOutput && (_jsx("div", { className: "mt-3 pt-2", children: _jsx("div", { className: "text-gray-600 prose prose-sm dark:prose-invert max-w-none", children: _jsx(Markdown, { remarkPlugins: [remarkGfm], children: finalOutput }) }) }))] }));
21
+ return (_jsxs("div", { className: `mb-2 ${isError ? 'text-red-700' : 'text-gray-600'}`, children: [_jsxs("div", { className: "mb-1 flex items-start", children: [_jsxs("span", { className: "mr-2 min-w-[16px]", children: [isSuccess && '✓', isError && '✗', toolCall.state === 'pending' && '○'] }), _jsxs("div", { className: "flex-1", children: [_jsx("span", { className: "font-medium", children: toolCall.toolName }), isError && toolCall.errorText && (_jsxs("div", { className: "mt-0.5 text-[0.9em] text-red-700", children: ["Error: ", toolCall.errorText] }))] })] }), isSuccess && hasComponent && hasObjectOutput ? (_jsx("div", { className: "ml-6 mt-1", children: _jsx(ToolComponent, { ...toolCall.output }) })) : null] }, toolCall.toolCallId));
22
+ }) }), finalOutput && (_jsx("div", { className: "mt-3 pt-2", children: _jsx("div", { className: "prose prose-sm dark:prose-invert max-w-none text-gray-600", children: _jsx(Markdown, { remarkPlugins: [remarkGfm], children: finalOutput }) }) }))] }));
23
23
  };
24
24
  /**
25
25
  * Component that renders an individual tool part from a UI message.
@@ -1 +1 @@
1
- {"version":3,"file":"ToolPartRenderer.js","sourceRoot":"","sources":["../../src/components/ToolPartRenderer.tsx"],"names":[],"mappings":"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","sourcesContent":["import React from 'react';\nimport Markdown from 'react-markdown';\nimport remarkGfm from 'remark-gfm';\nimport type {UIMessagePart} from '@sqlrooms/ai-config';\nimport {useStoreWithAi} from '../AiSlice';\nimport {isDynamicToolPart, isToolPart} from '../utils';\nimport {ToolResult} from './tools/ToolResult';\nimport {ToolCallInfo} from './ToolCallInfo';\n\n/**\n * Component that renders agent tool execution progress\n */\nconst AgentProgressRenderer: React.FC<{\n agentToolCalls: Array<{\n toolCallId: string;\n toolName: string;\n output?: unknown;\n errorText?: string;\n state: 'pending' | 'success' | 'error';\n }>;\n finalOutput?: string;\n reasoning?: string;\n}> = ({agentToolCalls, finalOutput, reasoning}) => {\n const findToolComponent = useStoreWithAi((s) => s.ai.findToolComponent);\n\n return (\n <div className=\"mt-2 px-5 text-[0.9em]\">\n {reasoning ? (\n <div className=\"mb-2 text-sm text-gray-500 prose prose-sm dark:prose-invert max-w-none\">\n <Markdown remarkPlugins={[remarkGfm]}>\n {reasoning}\n </Markdown>\n </div>\n ) : null}\n <div className=\"ml-3\">\n {agentToolCalls.map((toolCall) => {\n const ToolComponent = findToolComponent(toolCall.toolName);\n const isSuccess = toolCall.state === 'success';\n const isError = toolCall.state === 'error';\n const hasComponent =\n ToolComponent && typeof ToolComponent === 'function';\n const hasObjectOutput =\n toolCall.output &&\n typeof toolCall.output === 'object' &&\n toolCall.output !== null;\n\n return (\n <div\n key={toolCall.toolCallId}\n className={`mb-2 ${isError ? 'text-red-700' : 'text-gray-600'}`}\n >\n <div className=\"mb-1 flex items-start\">\n <span className=\"mr-2 min-w-[16px]\">\n {isSuccess && '✓'}\n {isError && '✗'}\n {toolCall.state === 'pending' && '○'}\n </span>\n <div className=\"flex-1\">\n <span className=\"font-medium\">{toolCall.toolName}</span>\n {isError && toolCall.errorText && (\n <div className=\"mt-0.5 text-[0.9em] text-red-700\">\n Error: {toolCall.errorText}\n </div>\n )}\n </div>\n </div>\n\n {isSuccess && hasComponent && hasObjectOutput ? (\n <div className=\"mt-1 ml-6\">\n <ToolComponent\n {...(toolCall.output as Record<string, unknown>)}\n />\n </div>\n ) : null}\n </div>\n );\n })}\n </div>\n {finalOutput && (\n <div className=\"mt-3 pt-2\">\n <div className=\"text-gray-600 prose prose-sm dark:prose-invert max-w-none\">\n <Markdown remarkPlugins={[remarkGfm]}>\n {finalOutput}\n </Markdown>\n </div>\n </div>\n )}\n </div>\n );\n};\n\n/**\n * Component that renders an individual tool part from a UI message.\n * Handles both tools with execute functions and tools without (dynamic components).\n *\n * @component\n * @param props - Component props\n * @param props.part - The UI message part to render\n * @returns A React component displaying the tool part, or null if not a tool part\n */\nexport const ToolPartRenderer = ({\n part,\n toolCallId,\n toolAdditionalData = {},\n}: {\n part: UIMessagePart;\n toolCallId: string;\n toolAdditionalData?: Record<string, unknown>;\n}) => {\n const tools = useStoreWithAi((s) => s.ai.tools);\n\n if (!isToolPart(part) && !isDynamicToolPart(part)) return null;\n\n const {type, state, input} = part;\n const toolName =\n type === 'dynamic-tool'\n ? part.toolName || 'unknown'\n : type.replace(/^tool-/, '') || 'unknown';\n\n const output = state === 'output-available' ? part.output : undefined;\n const errorText = state === 'output-error' ? part.errorText : undefined;\n const isCompleted = state === 'output-available' || state === 'output-error';\n const additionalData = toolAdditionalData[toolCallId];\n\n if (\n !tools[toolName]?.execute &&\n (state === 'input-streaming' ||\n state === 'input-available' ||\n state === 'output-available')\n ) {\n const ToolComponent = tools[toolName]?.component as React.ComponentType;\n const props = {\n ...(input as Record<string, unknown>),\n ...({toolCallId, toolName, isCompleted} as Record<string, unknown>),\n };\n return (\n <div>\n {ToolComponent && typeof ToolComponent === 'function' && (\n <ToolComponent {...props} />\n )}\n </div>\n );\n }\n\n // Otherwise, render <ToolResult>\n if (tools[toolName]?.execute) {\n const isAgentTool = toolName.startsWith('agent-');\n const agentData = additionalData as {\n agentToolCalls?: Array<{\n toolCallId: string;\n toolName: string;\n output?: unknown;\n errorText?: string;\n state: 'pending' | 'success' | 'error';\n }>;\n finalOutput?: string;\n };\n const hasAgentProgress =\n isAgentTool &&\n agentData?.agentToolCalls &&\n agentData.agentToolCalls.length > 0;\n const reasoning =\n input instanceof Object && 'reasoning' in input\n ? (input.reasoning as string)\n : undefined;\n\n return (\n <div>\n <ToolCallInfo\n toolName={toolName}\n input={input}\n isCompleted={isCompleted}\n state={state}\n />\n <div data-tool-call-id={toolCallId}>\n {hasAgentProgress ? (\n <AgentProgressRenderer\n agentToolCalls={agentData.agentToolCalls!}\n finalOutput={agentData.finalOutput}\n reasoning={reasoning}\n />\n ) : (\n <ToolResult\n toolCallId={toolCallId}\n toolData={{\n toolCallId,\n name: toolName,\n state: state,\n args: input,\n result: output,\n errorText,\n }}\n additionalData={additionalData}\n isCompleted={isCompleted}\n errorMessage={state === 'output-error' ? errorText : undefined}\n />\n )}\n </div>\n </div>\n );\n }\n\n return null;\n};\n"]}
1
+ {"version":3,"file":"ToolPartRenderer.js","sourceRoot":"","sources":["../../src/components/ToolPartRenderer.tsx"],"names":[],"mappings":"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","sourcesContent":["import React from 'react';\nimport Markdown from 'react-markdown';\nimport remarkGfm from 'remark-gfm';\nimport type {UIMessagePart} from '@sqlrooms/ai-config';\nimport {useStoreWithAi} from '../AiSlice';\nimport {isDynamicToolPart, isToolPart} from '../utils';\nimport {ToolResult} from './tools/ToolResult';\nimport {ToolCallInfo} from './ToolCallInfo';\n\n/**\n * Component that renders agent tool execution progress\n */\nconst AgentProgressRenderer: React.FC<{\n agentToolCalls: Array<{\n toolCallId: string;\n toolName: string;\n output?: unknown;\n errorText?: string;\n state: 'pending' | 'success' | 'error';\n }>;\n finalOutput?: string;\n reasoning?: string;\n}> = ({agentToolCalls, finalOutput, reasoning}) => {\n const findToolComponent = useStoreWithAi((s) => s.ai.findToolComponent);\n\n return (\n <div className=\"mt-2 px-5 text-[0.9em]\">\n {reasoning ? (\n <div className=\"prose prose-sm dark:prose-invert mb-2 max-w-none text-sm text-gray-500\">\n <Markdown remarkPlugins={[remarkGfm]}>{reasoning}</Markdown>\n </div>\n ) : null}\n <div className=\"ml-3\">\n {agentToolCalls.map((toolCall) => {\n const ToolComponent = findToolComponent(toolCall.toolName);\n const isSuccess = toolCall.state === 'success';\n const isError = toolCall.state === 'error';\n const hasComponent =\n ToolComponent && typeof ToolComponent === 'function';\n const hasObjectOutput =\n toolCall.output &&\n typeof toolCall.output === 'object' &&\n toolCall.output !== null;\n\n return (\n <div\n key={toolCall.toolCallId}\n className={`mb-2 ${isError ? 'text-red-700' : 'text-gray-600'}`}\n >\n <div className=\"mb-1 flex items-start\">\n <span className=\"mr-2 min-w-[16px]\">\n {isSuccess && '✓'}\n {isError && '✗'}\n {toolCall.state === 'pending' && '○'}\n </span>\n <div className=\"flex-1\">\n <span className=\"font-medium\">{toolCall.toolName}</span>\n {isError && toolCall.errorText && (\n <div className=\"mt-0.5 text-[0.9em] text-red-700\">\n Error: {toolCall.errorText}\n </div>\n )}\n </div>\n </div>\n\n {isSuccess && hasComponent && hasObjectOutput ? (\n <div className=\"ml-6 mt-1\">\n <ToolComponent\n {...(toolCall.output as Record<string, unknown>)}\n />\n </div>\n ) : null}\n </div>\n );\n })}\n </div>\n {finalOutput && (\n <div className=\"mt-3 pt-2\">\n <div className=\"prose prose-sm dark:prose-invert max-w-none text-gray-600\">\n <Markdown remarkPlugins={[remarkGfm]}>{finalOutput}</Markdown>\n </div>\n </div>\n )}\n </div>\n );\n};\n\n/**\n * Component that renders an individual tool part from a UI message.\n * Handles both tools with execute functions and tools without (dynamic components).\n *\n * @component\n * @param props - Component props\n * @param props.part - The UI message part to render\n * @returns A React component displaying the tool part, or null if not a tool part\n */\nexport const ToolPartRenderer = ({\n part,\n toolCallId,\n toolAdditionalData = {},\n}: {\n part: UIMessagePart;\n toolCallId: string;\n toolAdditionalData?: Record<string, unknown>;\n}) => {\n const tools = useStoreWithAi((s) => s.ai.tools);\n\n if (!isToolPart(part) && !isDynamicToolPart(part)) return null;\n\n const {type, state, input} = part;\n const toolName =\n type === 'dynamic-tool'\n ? part.toolName || 'unknown'\n : type.replace(/^tool-/, '') || 'unknown';\n\n const output = state === 'output-available' ? part.output : undefined;\n const errorText = state === 'output-error' ? part.errorText : undefined;\n const isCompleted = state === 'output-available' || state === 'output-error';\n const additionalData = toolAdditionalData[toolCallId];\n\n if (\n !tools[toolName]?.execute &&\n (state === 'input-streaming' ||\n state === 'input-available' ||\n state === 'output-available')\n ) {\n const ToolComponent = tools[toolName]?.component as React.ComponentType;\n const props = {\n ...(input as Record<string, unknown>),\n ...({toolCallId, toolName, isCompleted} as Record<string, unknown>),\n };\n return (\n <div>\n {ToolComponent && typeof ToolComponent === 'function' && (\n <ToolComponent {...props} />\n )}\n </div>\n );\n }\n\n // Otherwise, render <ToolResult>\n if (tools[toolName]?.execute) {\n const isAgentTool = toolName.startsWith('agent-');\n const agentData = additionalData as {\n agentToolCalls?: Array<{\n toolCallId: string;\n toolName: string;\n output?: unknown;\n errorText?: string;\n state: 'pending' | 'success' | 'error';\n }>;\n finalOutput?: string;\n };\n const hasAgentProgress =\n isAgentTool &&\n agentData?.agentToolCalls &&\n agentData.agentToolCalls.length > 0;\n const reasoning =\n input instanceof Object && 'reasoning' in input\n ? (input.reasoning as string)\n : undefined;\n\n return (\n <div>\n <ToolCallInfo\n toolName={toolName}\n input={input}\n isCompleted={isCompleted}\n state={state}\n />\n <div data-tool-call-id={toolCallId}>\n {hasAgentProgress ? (\n <AgentProgressRenderer\n agentToolCalls={agentData.agentToolCalls!}\n finalOutput={agentData.finalOutput}\n reasoning={reasoning}\n />\n ) : (\n <ToolResult\n toolCallId={toolCallId}\n toolData={{\n toolCallId,\n name: toolName,\n state: state,\n args: input,\n result: output,\n errorText,\n }}\n additionalData={additionalData}\n isCompleted={isCompleted}\n errorMessage={state === 'output-error' ? errorText : undefined}\n />\n )}\n </div>\n </div>\n );\n }\n\n return null;\n};\n"]}
package/dist/utils.d.ts CHANGED
@@ -93,6 +93,17 @@ export declare function isDynamicToolPart(part: UIMessagePart): part is DynamicT
93
93
  * @returns The cleaned session with restored analysis results
94
94
  */
95
95
  export declare function cleanupPendingAnalysisResults(session: AnalysisSessionSchema): AnalysisSessionSchema;
96
+ /**
97
+ * Sanitizes UIMessages before sending to LLM APIs to prevent errors from malformed content.
98
+ *
99
+ * This handles issues that can occur when conversations are interrupted mid-stream:
100
+ * - Empty text parts (causes Bedrock error: "text field in ContentBlock is blank")
101
+ * - Assistant messages with no meaningful content after cleanup
102
+ *
103
+ * @param messages - The messages to sanitize
104
+ * @returns Sanitized messages safe to send to LLM APIs
105
+ */
106
+ export declare function sanitizeMessagesForLLM(messages: UIMessage[]): UIMessage[];
96
107
  /**
97
108
  * Validates and completes UIMessages to ensure all tool-call parts have corresponding tool-result parts.
98
109
  * This is important when canceling with AbortController, which may leave incomplete tool-calls.
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,qBAAqB,EAErB,qBAAqB,EACrB,aAAa,EACd,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAC,iBAAiB,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAC,MAAM,IAAI,CAAC;AAOxE;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,KAAK,CAAC,WAAW,GAAG,SAAS,CAAC,GACtC,WAAW,GAAG,SAAS,CA+BzB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,qBAAa,cAAe,SAAQ,KAAK;gBAC3B,OAAO,GAAE,MAAgC;CAQtD;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,qBAAqB,GAC5B,KAAK,CAAC;IACP,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf,CAAC,CA4BD;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,IAAI,UAAU,CAElE;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,aAAa,GAClB,IAAI,IAAI,OAAO,CAAC,aAAa,EAAE;IAAC,IAAI,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAC,CAAC,CAEnE;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,IAAI,UAAU,CAElE;AAED,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,aAAa,GAClB,IAAI,IAAI,iBAAiB,CAE3B;AAED;;;;;;;;;GASG;AACH,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,qBAAqB,GAC7B,qBAAqB,CAuDvB;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,SAAS,EAAE,GAAG,SAAS,EAAE,CAwEzE"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,qBAAqB,EAErB,qBAAqB,EACrB,aAAa,EACd,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAC,iBAAiB,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAC,MAAM,IAAI,CAAC;AAOxE;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,KAAK,CAAC,WAAW,GAAG,SAAS,CAAC,GACtC,WAAW,GAAG,SAAS,CA+BzB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,qBAAa,cAAe,SAAQ,KAAK;gBAC3B,OAAO,GAAE,MAAgC;CAQtD;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,qBAAqB,GAC5B,KAAK,CAAC;IACP,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf,CAAC,CA4BD;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,IAAI,UAAU,CAElE;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,aAAa,GAClB,IAAI,IAAI,OAAO,CAAC,aAAa,EAAE;IAAC,IAAI,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAC,CAAC,CAEnE;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,IAAI,UAAU,CAElE;AAED,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,aAAa,GAClB,IAAI,IAAI,iBAAiB,CAE3B;AAED;;;;;;;;;GASG;AACH,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,qBAAqB,GAC7B,qBAAqB,CAuDvB;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,SAAS,EAAE,GAAG,SAAS,EAAE,CAsCzE;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,SAAS,EAAE,GAAG,SAAS,EAAE,CAwEzE"}
package/dist/utils.js CHANGED
@@ -195,6 +195,52 @@ export function cleanupPendingAnalysisResults(session) {
195
195
  analysisResults: [...nonPendingResults, ...restoredResults],
196
196
  };
197
197
  }
198
+ /**
199
+ * Sanitizes UIMessages before sending to LLM APIs to prevent errors from malformed content.
200
+ *
201
+ * This handles issues that can occur when conversations are interrupted mid-stream:
202
+ * - Empty text parts (causes Bedrock error: "text field in ContentBlock is blank")
203
+ * - Assistant messages with no meaningful content after cleanup
204
+ *
205
+ * @param messages - The messages to sanitize
206
+ * @returns Sanitized messages safe to send to LLM APIs
207
+ */
208
+ export function sanitizeMessagesForLLM(messages) {
209
+ return messages
210
+ .map((message) => {
211
+ if (!message.parts || message.parts.length === 0) {
212
+ return message;
213
+ }
214
+ // Filter out empty text parts and empty reasoning parts
215
+ const sanitizedParts = message.parts.filter((part) => {
216
+ if (part.type === 'text') {
217
+ const textPart = part;
218
+ return textPart.text && textPart.text.trim().length > 0;
219
+ }
220
+ if (part.type === 'reasoning') {
221
+ const reasoningPart = part;
222
+ return reasoningPart.text && reasoningPart.text.trim().length > 0;
223
+ }
224
+ return true;
225
+ });
226
+ // If all parts were filtered out, add a placeholder for assistant messages
227
+ // to maintain conversation structure (user messages should always have content)
228
+ if (sanitizedParts.length === 0 && message.role === 'assistant') {
229
+ return {
230
+ ...message,
231
+ parts: [{ type: 'text', text: '[Response interrupted]' }],
232
+ };
233
+ }
234
+ return {
235
+ ...message,
236
+ parts: sanitizedParts,
237
+ };
238
+ })
239
+ .filter((message) => {
240
+ // Remove messages that have no parts (shouldn't happen after above logic, but safety check)
241
+ return message.parts && message.parts.length > 0;
242
+ });
243
+ }
198
244
  /**
199
245
  * Validates and completes UIMessages to ensure all tool-call parts have corresponding tool-result parts.
200
246
  * This is important when canceling with AbortController, which may leave incomplete tool-calls.
package/dist/utils.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Utility functions for AI Chat UI configuration\n */\n\nimport {\n AiSettingsSliceConfig,\n AnalysisResultSchema,\n AnalysisSessionSchema,\n UIMessagePart,\n} from '@sqlrooms/ai-config';\nimport {DynamicToolUIPart, TextUIPart, ToolUIPart, UIMessage} from 'ai';\nimport {\n ABORT_EVENT,\n ANALYSIS_PENDING_ID,\n TOOL_CALL_CANCELLED,\n} from './constants';\n\n/**\n * Merge multiple AbortSignals into a single signal.\n *\n * Why this exists:\n * - `@ai-sdk/react` (`useChat`) provides a request-level abort signal (e.g. when calling `stop()`).\n * - This app also has a per-session AbortController a.k.a the Stop button (e.g. `cancelAnalysis(sessionId)`).\n *\n * When either of those sources abort, we want downstream work (streaming / tools / fetch)\n * to see a *single* abort signal.\n *\n * Notes:\n * - If 0 signals are provided, returns `undefined` (callers can omit abort handling).\n * - If 1 signal is provided, returns it directly (no wrapping controller).\n * - If 2+ signals are provided, creates a new AbortController and aborts it when any input aborts.\n * - (not currently used) use native `AbortSignal.any()` to avoid per-request listener accumulation on long-lived signals.\n * -`{once: true}` listeners if `AbortSignal.any()` is unavailable.\n */\nexport function mergeAbortSignals(\n signals: Array<AbortSignal | undefined>,\n): AbortSignal | undefined {\n const present = signals.filter(Boolean) as AbortSignal[];\n if (present.length === 0) return undefined;\n if (present.length === 1) return present[0];\n\n // Prefer the platform implementation when available.\n // It avoids attaching JS event listeners to long-lived signals (e.g. per-session AbortController),\n // which would otherwise accumulate one listener per request if requests usually complete normally.\n //\n // Node >=22 and modern browsers support this.\n // We intentionally use an `any` cast to keep compatibility with older TS lib typings.\n // const anyFn = (AbortSignal as unknown as {any?: (signals: AbortSignal[]) => AbortSignal})\n // .any;\n // if (typeof anyFn === 'function') {\n // return anyFn(present);\n // }\n\n const controller = new AbortController();\n const abort = () => {\n if (!controller.signal.aborted) controller.abort();\n };\n\n for (const s of present) {\n if (s.aborted) {\n abort();\n break;\n }\n s.addEventListener(ABORT_EVENT, abort, {once: true});\n }\n\n return controller.signal;\n}\n\n/**\n * Custom error class for operation abort errors.\n * This allows for type-safe error handling when operations are cancelled by the user.\n *\n * Tools should throw this error when they detect an abort signal,\n * and error handlers can check for this specific error type to provide\n * appropriate user feedback.\n *\n * @example\n * ```ts\n * if (abortSignal?.aborted) {\n * throw new ToolAbortError('Operation was aborted');\n * }\n * ```\n *\n * @example\n * ```ts\n * try {\n * await someTool.execute(params, { abortSignal });\n * } catch (error) {\n * if (error instanceof ToolAbortError) {\n * console.log('User cancelled the operation');\n * }\n * }\n * ```\n */\nexport class ToolAbortError extends Error {\n constructor(message: string = 'Operation was aborted') {\n super(message);\n this.name = 'ToolAbortError';\n // Maintains proper stack trace for where our error was thrown (only available on V8)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, ToolAbortError);\n }\n }\n}\n\n/**\n * Extract models from aiSettings in the format expected by ModelSelector\n * @param config - The AI model configuration\n * @returns Array of models with provider, label, and value properties\n */\nexport function extractModelsFromSettings(\n config: AiSettingsSliceConfig,\n): Array<{\n provider: string;\n label: string;\n value: string;\n}> {\n const models: Array<{\n provider: string;\n label: string;\n value: string;\n }> = [];\n\n // Extract models from providers\n Object.entries(config.providers).forEach(([providerKey, provider]) => {\n provider.models.forEach((model) => {\n models.push({\n provider: providerKey,\n label: model.modelName,\n value: model.modelName,\n });\n });\n });\n\n // Add custom models\n config.customModels.forEach((customModel) => {\n models.push({\n provider: 'custom',\n label: customModel.modelName,\n value: customModel.modelName,\n });\n });\n\n return models;\n}\n\n/**\n * Type guard to check if a UIMessagePart is a text part\n * @param part - The message part to check\n * @returns True if the part is a text part\n */\nexport function isTextPart(part: UIMessagePart): part is TextUIPart {\n return part.type === 'text';\n}\n\n/**\n * Type guard to check if a UIMessagePart is a reasoning part\n * @param part - The message part to check\n * @returns True if the part is a reasoning part\n */\nexport function isReasoningPart(\n part: UIMessagePart,\n): part is Extract<UIMessagePart, {type: 'reasoning'; text: string}> {\n return part.type === 'reasoning';\n}\n\n/**\n * Type guard to check if a UIMessagePart is a tool part (type starts with 'tool-')\n * @param part - The message part to check\n * @returns True if the part is a tool part\n */\nexport function isToolPart(part: UIMessagePart): part is ToolUIPart {\n return typeof part.type === 'string' && part.type.startsWith('tool-');\n}\n\nexport function isDynamicToolPart(\n part: UIMessagePart,\n): part is DynamicToolUIPart {\n return part.type === 'dynamic-tool';\n}\n\n/**\n * Cleans up pending analysis results from interrupted conversations and restores them\n * with proper IDs from actual user messages. This handles the case where a page refresh\n * occurred during an active analysis, leaving orphaned \"__pending__\" results.\n *\n * Should be called once when loading persisted session data, not in migrations.\n *\n * @param session - The session to clean up\n * @returns The cleaned session with restored analysis results\n */\nexport function cleanupPendingAnalysisResults(\n session: AnalysisSessionSchema,\n): AnalysisSessionSchema {\n const {analysisResults, uiMessages} = session;\n\n if (!Array.isArray(analysisResults) || !Array.isArray(uiMessages)) {\n return session;\n }\n\n // Remove all pending results\n const nonPendingResults = analysisResults.filter(\n (result) => result.id !== ANALYSIS_PENDING_ID,\n );\n\n // Find all user messages that don't have a corresponding assistant response\n const orphanedUserMessages: Array<{id: string; prompt: string}> = [];\n\n for (let i = 0; i < uiMessages.length; i++) {\n const message = uiMessages[i];\n if (!message || message.role !== 'user') {\n continue;\n }\n\n // Check if there's an assistant message after this user message\n const hasAssistantResponse = uiMessages\n .slice(i + 1)\n .some((m) => m && m.role === 'assistant');\n\n if (!hasAssistantResponse) {\n // Extract text from message parts\n const prompt = message.parts\n .filter((part) => part.type === 'text')\n .map((part) => (part as {text: string}).text)\n .join('');\n\n orphanedUserMessages.push({\n id: message.id,\n prompt,\n });\n }\n }\n\n // For each orphaned user message, check if it already has an analysis result\n // If not, create one\n const existingResultIds = new Set(nonPendingResults.map((r) => r.id));\n const restoredResults: AnalysisResultSchema[] = orphanedUserMessages\n .filter(({id}) => !existingResultIds.has(id))\n .map(({id, prompt}) => ({\n id,\n prompt,\n isCompleted: true, // Mark as completed since the user did submit it\n }));\n\n return {\n ...session,\n analysisResults: [...nonPendingResults, ...restoredResults],\n };\n}\n\n/**\n * Validates and completes UIMessages to ensure all tool-call parts have corresponding tool-result parts.\n * This is important when canceling with AbortController, which may leave incomplete tool-calls.\n * Assumes sequential tool execution (only one tool runs at a time).\n *\n * @param messages - The messages to validate and complete\n * @returns Cleaned messages with completed tool-call/result pairs\n */\nexport function fixIncompleteToolCalls(messages: UIMessage[]): UIMessage[] {\n return messages.map((message) => {\n if (message.role !== 'assistant' || !message.parts) {\n return message;\n }\n\n // Walk backward and complete any TRAILING tool parts that lack output.\n // This covers multi-tool-step aborts where several tool calls were started\n // but the stream was cancelled before the outputs were emitted.\n type ToolPart = {\n type: string;\n toolCallId: string;\n toolName?: string;\n input?: unknown;\n state?: string;\n };\n const isToolPart = (part: unknown): part is ToolPart => {\n if (typeof part !== 'object' || part === null) return false;\n const p = part as Record<string, unknown> & {type?: unknown};\n const typeVal =\n typeof p.type === 'string' ? (p.type as string) : undefined;\n return (\n !!typeVal &&\n 'toolCallId' in p &&\n (typeVal === 'dynamic-tool' || typeVal.startsWith('tool-'))\n );\n };\n\n const updatedParts = [...message.parts];\n let sawAnyTool = false;\n for (let i = updatedParts.length - 1; i >= 0; i--) {\n const current = updatedParts[i] as unknown;\n if (!isToolPart(current)) {\n // Stop once we exit the trailing tool region\n if (sawAnyTool) break;\n continue;\n }\n sawAnyTool = true;\n const toolPart = current as ToolPart;\n const hasOutput = toolPart.state?.startsWith('output');\n if (hasOutput) {\n // Completed tool; continue checking earlier parts just in case\n continue;\n }\n\n // Synthesize a completed error result for the incomplete tool call\n const base = {\n toolCallId: toolPart.toolCallId,\n state: 'output-error' as const,\n input: toolPart.input ?? {},\n errorText: TOOL_CALL_CANCELLED,\n providerExecuted: false,\n };\n\n const syntheticPart =\n toolPart.type === 'dynamic-tool'\n ? {\n type: 'dynamic-tool' as const,\n toolName: toolPart.toolName || 'unknown',\n ...base,\n }\n : {type: toolPart.type as string, ...base};\n\n updatedParts[i] =\n syntheticPart as unknown as (typeof message.parts)[number];\n }\n\n return {\n ...message,\n parts: updatedParts,\n };\n });\n}\n"]}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Utility functions for AI Chat UI configuration\n */\n\nimport {\n AiSettingsSliceConfig,\n AnalysisResultSchema,\n AnalysisSessionSchema,\n UIMessagePart,\n} from '@sqlrooms/ai-config';\nimport {DynamicToolUIPart, TextUIPart, ToolUIPart, UIMessage} from 'ai';\nimport {\n ABORT_EVENT,\n ANALYSIS_PENDING_ID,\n TOOL_CALL_CANCELLED,\n} from './constants';\n\n/**\n * Merge multiple AbortSignals into a single signal.\n *\n * Why this exists:\n * - `@ai-sdk/react` (`useChat`) provides a request-level abort signal (e.g. when calling `stop()`).\n * - This app also has a per-session AbortController a.k.a the Stop button (e.g. `cancelAnalysis(sessionId)`).\n *\n * When either of those sources abort, we want downstream work (streaming / tools / fetch)\n * to see a *single* abort signal.\n *\n * Notes:\n * - If 0 signals are provided, returns `undefined` (callers can omit abort handling).\n * - If 1 signal is provided, returns it directly (no wrapping controller).\n * - If 2+ signals are provided, creates a new AbortController and aborts it when any input aborts.\n * - (not currently used) use native `AbortSignal.any()` to avoid per-request listener accumulation on long-lived signals.\n * -`{once: true}` listeners if `AbortSignal.any()` is unavailable.\n */\nexport function mergeAbortSignals(\n signals: Array<AbortSignal | undefined>,\n): AbortSignal | undefined {\n const present = signals.filter(Boolean) as AbortSignal[];\n if (present.length === 0) return undefined;\n if (present.length === 1) return present[0];\n\n // Prefer the platform implementation when available.\n // It avoids attaching JS event listeners to long-lived signals (e.g. per-session AbortController),\n // which would otherwise accumulate one listener per request if requests usually complete normally.\n //\n // Node >=22 and modern browsers support this.\n // We intentionally use an `any` cast to keep compatibility with older TS lib typings.\n // const anyFn = (AbortSignal as unknown as {any?: (signals: AbortSignal[]) => AbortSignal})\n // .any;\n // if (typeof anyFn === 'function') {\n // return anyFn(present);\n // }\n\n const controller = new AbortController();\n const abort = () => {\n if (!controller.signal.aborted) controller.abort();\n };\n\n for (const s of present) {\n if (s.aborted) {\n abort();\n break;\n }\n s.addEventListener(ABORT_EVENT, abort, {once: true});\n }\n\n return controller.signal;\n}\n\n/**\n * Custom error class for operation abort errors.\n * This allows for type-safe error handling when operations are cancelled by the user.\n *\n * Tools should throw this error when they detect an abort signal,\n * and error handlers can check for this specific error type to provide\n * appropriate user feedback.\n *\n * @example\n * ```ts\n * if (abortSignal?.aborted) {\n * throw new ToolAbortError('Operation was aborted');\n * }\n * ```\n *\n * @example\n * ```ts\n * try {\n * await someTool.execute(params, { abortSignal });\n * } catch (error) {\n * if (error instanceof ToolAbortError) {\n * console.log('User cancelled the operation');\n * }\n * }\n * ```\n */\nexport class ToolAbortError extends Error {\n constructor(message: string = 'Operation was aborted') {\n super(message);\n this.name = 'ToolAbortError';\n // Maintains proper stack trace for where our error was thrown (only available on V8)\n if ((Error as any).captureStackTrace) {\n (Error as any).captureStackTrace(this, ToolAbortError);\n }\n }\n}\n\n/**\n * Extract models from aiSettings in the format expected by ModelSelector\n * @param config - The AI model configuration\n * @returns Array of models with provider, label, and value properties\n */\nexport function extractModelsFromSettings(\n config: AiSettingsSliceConfig,\n): Array<{\n provider: string;\n label: string;\n value: string;\n}> {\n const models: Array<{\n provider: string;\n label: string;\n value: string;\n }> = [];\n\n // Extract models from providers\n Object.entries(config.providers).forEach(([providerKey, provider]) => {\n provider.models.forEach((model) => {\n models.push({\n provider: providerKey,\n label: model.modelName,\n value: model.modelName,\n });\n });\n });\n\n // Add custom models\n config.customModels.forEach((customModel) => {\n models.push({\n provider: 'custom',\n label: customModel.modelName,\n value: customModel.modelName,\n });\n });\n\n return models;\n}\n\n/**\n * Type guard to check if a UIMessagePart is a text part\n * @param part - The message part to check\n * @returns True if the part is a text part\n */\nexport function isTextPart(part: UIMessagePart): part is TextUIPart {\n return part.type === 'text';\n}\n\n/**\n * Type guard to check if a UIMessagePart is a reasoning part\n * @param part - The message part to check\n * @returns True if the part is a reasoning part\n */\nexport function isReasoningPart(\n part: UIMessagePart,\n): part is Extract<UIMessagePart, {type: 'reasoning'; text: string}> {\n return part.type === 'reasoning';\n}\n\n/**\n * Type guard to check if a UIMessagePart is a tool part (type starts with 'tool-')\n * @param part - The message part to check\n * @returns True if the part is a tool part\n */\nexport function isToolPart(part: UIMessagePart): part is ToolUIPart {\n return typeof part.type === 'string' && part.type.startsWith('tool-');\n}\n\nexport function isDynamicToolPart(\n part: UIMessagePart,\n): part is DynamicToolUIPart {\n return part.type === 'dynamic-tool';\n}\n\n/**\n * Cleans up pending analysis results from interrupted conversations and restores them\n * with proper IDs from actual user messages. This handles the case where a page refresh\n * occurred during an active analysis, leaving orphaned \"__pending__\" results.\n *\n * Should be called once when loading persisted session data, not in migrations.\n *\n * @param session - The session to clean up\n * @returns The cleaned session with restored analysis results\n */\nexport function cleanupPendingAnalysisResults(\n session: AnalysisSessionSchema,\n): AnalysisSessionSchema {\n const {analysisResults, uiMessages} = session;\n\n if (!Array.isArray(analysisResults) || !Array.isArray(uiMessages)) {\n return session;\n }\n\n // Remove all pending results\n const nonPendingResults = analysisResults.filter(\n (result) => result.id !== ANALYSIS_PENDING_ID,\n );\n\n // Find all user messages that don't have a corresponding assistant response\n const orphanedUserMessages: Array<{id: string; prompt: string}> = [];\n\n for (let i = 0; i < uiMessages.length; i++) {\n const message = uiMessages[i];\n if (!message || message.role !== 'user') {\n continue;\n }\n\n // Check if there's an assistant message after this user message\n const hasAssistantResponse = uiMessages\n .slice(i + 1)\n .some((m) => m && m.role === 'assistant');\n\n if (!hasAssistantResponse) {\n // Extract text from message parts\n const prompt = message.parts\n .filter((part) => part.type === 'text')\n .map((part) => (part as {text: string}).text)\n .join('');\n\n orphanedUserMessages.push({\n id: message.id,\n prompt,\n });\n }\n }\n\n // For each orphaned user message, check if it already has an analysis result\n // If not, create one\n const existingResultIds = new Set(nonPendingResults.map((r) => r.id));\n const restoredResults: AnalysisResultSchema[] = orphanedUserMessages\n .filter(({id}) => !existingResultIds.has(id))\n .map(({id, prompt}) => ({\n id,\n prompt,\n isCompleted: true, // Mark as completed since the user did submit it\n }));\n\n return {\n ...session,\n analysisResults: [...nonPendingResults, ...restoredResults],\n };\n}\n\n/**\n * Sanitizes UIMessages before sending to LLM APIs to prevent errors from malformed content.\n *\n * This handles issues that can occur when conversations are interrupted mid-stream:\n * - Empty text parts (causes Bedrock error: \"text field in ContentBlock is blank\")\n * - Assistant messages with no meaningful content after cleanup\n *\n * @param messages - The messages to sanitize\n * @returns Sanitized messages safe to send to LLM APIs\n */\nexport function sanitizeMessagesForLLM(messages: UIMessage[]): UIMessage[] {\n return messages\n .map((message) => {\n if (!message.parts || message.parts.length === 0) {\n return message;\n }\n\n // Filter out empty text parts and empty reasoning parts\n const sanitizedParts = message.parts.filter((part) => {\n if (part.type === 'text') {\n const textPart = part as {type: 'text'; text: string};\n return textPart.text && textPart.text.trim().length > 0;\n }\n if (part.type === 'reasoning') {\n const reasoningPart = part as {type: 'reasoning'; text: string};\n return reasoningPart.text && reasoningPart.text.trim().length > 0;\n }\n return true;\n });\n\n // If all parts were filtered out, add a placeholder for assistant messages\n // to maintain conversation structure (user messages should always have content)\n if (sanitizedParts.length === 0 && message.role === 'assistant') {\n return {\n ...message,\n parts: [{type: 'text' as const, text: '[Response interrupted]'}],\n };\n }\n\n return {\n ...message,\n parts: sanitizedParts,\n };\n })\n .filter((message) => {\n // Remove messages that have no parts (shouldn't happen after above logic, but safety check)\n return message.parts && message.parts.length > 0;\n });\n}\n\n/**\n * Validates and completes UIMessages to ensure all tool-call parts have corresponding tool-result parts.\n * This is important when canceling with AbortController, which may leave incomplete tool-calls.\n * Assumes sequential tool execution (only one tool runs at a time).\n *\n * @param messages - The messages to validate and complete\n * @returns Cleaned messages with completed tool-call/result pairs\n */\nexport function fixIncompleteToolCalls(messages: UIMessage[]): UIMessage[] {\n return messages.map((message) => {\n if (message.role !== 'assistant' || !message.parts) {\n return message;\n }\n\n // Walk backward and complete any TRAILING tool parts that lack output.\n // This covers multi-tool-step aborts where several tool calls were started\n // but the stream was cancelled before the outputs were emitted.\n type ToolPart = {\n type: string;\n toolCallId: string;\n toolName?: string;\n input?: unknown;\n state?: string;\n };\n const isToolPart = (part: unknown): part is ToolPart => {\n if (typeof part !== 'object' || part === null) return false;\n const p = part as Record<string, unknown> & {type?: unknown};\n const typeVal =\n typeof p.type === 'string' ? (p.type as string) : undefined;\n return (\n !!typeVal &&\n 'toolCallId' in p &&\n (typeVal === 'dynamic-tool' || typeVal.startsWith('tool-'))\n );\n };\n\n const updatedParts = [...message.parts];\n let sawAnyTool = false;\n for (let i = updatedParts.length - 1; i >= 0; i--) {\n const current = updatedParts[i] as unknown;\n if (!isToolPart(current)) {\n // Stop once we exit the trailing tool region\n if (sawAnyTool) break;\n continue;\n }\n sawAnyTool = true;\n const toolPart = current as ToolPart;\n const hasOutput = toolPart.state?.startsWith('output');\n if (hasOutput) {\n // Completed tool; continue checking earlier parts just in case\n continue;\n }\n\n // Synthesize a completed error result for the incomplete tool call\n const base = {\n toolCallId: toolPart.toolCallId,\n state: 'output-error' as const,\n input: toolPart.input ?? {},\n errorText: TOOL_CALL_CANCELLED,\n providerExecuted: false,\n };\n\n const syntheticPart =\n toolPart.type === 'dynamic-tool'\n ? {\n type: 'dynamic-tool' as const,\n toolName: toolPart.toolName || 'unknown',\n ...base,\n }\n : {type: toolPart.type as string, ...base};\n\n updatedParts[i] =\n syntheticPart as unknown as (typeof message.parts)[number];\n }\n\n return {\n ...message,\n parts: updatedParts,\n };\n });\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sqlrooms/ai-core",
3
- "version": "0.28.1-rc.0",
3
+ "version": "0.29.0-rc.1",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "module": "dist/index.js",
@@ -23,11 +23,11 @@
23
23
  "@ai-sdk/react": "^2.0.44",
24
24
  "@openassistant/utils": "1.0.0-alpha.0",
25
25
  "@paralleldrive/cuid2": "^3.0.0",
26
- "@sqlrooms/ai-config": "0.28.1-rc.0",
27
- "@sqlrooms/monaco-editor": "0.28.1-rc.0",
28
- "@sqlrooms/room-store": "0.28.1-rc.0",
29
- "@sqlrooms/ui": "0.28.1-rc.0",
30
- "@sqlrooms/utils": "0.28.1-rc.0",
26
+ "@sqlrooms/ai-config": "0.29.0-rc.1",
27
+ "@sqlrooms/monaco-editor": "0.29.0-rc.1",
28
+ "@sqlrooms/room-store": "0.29.0-rc.1",
29
+ "@sqlrooms/ui": "0.29.0-rc.1",
30
+ "@sqlrooms/utils": "0.29.0-rc.1",
31
31
  "ai": "^5.0.44",
32
32
  "immer": "^11.0.1",
33
33
  "lucide-react": "^0.556.0",
@@ -47,5 +47,5 @@
47
47
  "typecheck": "tsc --noEmit",
48
48
  "typedoc": "typedoc"
49
49
  },
50
- "gitHead": "1e0dcae95d1ccdbcd1b32df1d647d0f794b94e5e"
50
+ "gitHead": "69f127fd34bd7f2ce3d75d6098dbf8c1f5ab50f3"
51
51
  }