@sqlrooms/ai-core 0.27.0 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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 {xai} from \"@ai-sdk/xai\";\n * getCustomModel: () => xai('grok-4')\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 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 +1 @@
1
- {"version":3,"file":"AnalysisResultsContainer.d.ts","sourceRoot":"","sources":["../../src/components/AnalysisResultsContainer.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA0B,MAAM,OAAO,CAAC;AAC/C,OAAO,EAAC,UAAU,EAAC,MAAM,gBAAgB,CAAC;AAK1C,OAAO,KAAK,EAAC,0BAA0B,EAAC,MAAM,gBAAgB,CAAC;AAE/D,eAAO,MAAM,wBAAwB,EAAE,KAAK,CAAC,EAAE,CAAC;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,wBAAwB,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IAC/C,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC/B,qBAAqB,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,0BAA0B,CAAC,CAAC;CACzE,CAyEA,CAAC"}
1
+ {"version":3,"file":"AnalysisResultsContainer.d.ts","sourceRoot":"","sources":["../../src/components/AnalysisResultsContainer.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA0B,MAAM,OAAO,CAAC;AAC/C,OAAO,EAAC,UAAU,EAAC,MAAM,gBAAgB,CAAC;AAK1C,OAAO,KAAK,EAAC,0BAA0B,EAAC,MAAM,gBAAgB,CAAC;AAE/D,eAAO,MAAM,wBAAwB,EAAE,KAAK,CAAC,EAAE,CAAC;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,wBAAwB,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IAC/C,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC/B,qBAAqB,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,0BAA0B,CAAC,CAAC;CACzE,CAuEA,CAAC"}
@@ -25,6 +25,6 @@ export const AnalysisResultsContainer = ({ className, enableReasoningBox = false
25
25
  scrollToBottom();
26
26
  }
27
27
  }, [isRunning, scrollToBottom]);
28
- return (_jsxs("div", { className: cn('relative flex h-full w-full flex-col', className), children: [_jsxs(ScrollArea, { viewportRef: containerRef, className: "flex w-full flex-grow flex-col gap-5", children: [currentAnalysisResults?.map((analysisResult) => (_jsx(AnalysisResult, { analysisResult: analysisResult, enableReasoningBox: enableReasoningBox, customMarkdownComponents: customMarkdownComponents, excludeFromGrouping: excludeFromGrouping, ErrorMessageComponent: ErrorMessageComponent }, analysisResult.id))), isRunning && (_jsx(AiThinkingDots, { className: "text-muted-foreground p-4" })), _jsx("div", { ref: endRef, className: "h-10 w-full shrink-0" }), _jsx(ScrollBar, { orientation: "vertical" }), _jsx(ScrollBar, { orientation: "horizontal" })] }), _jsx("div", { className: "pointer-events-none absolute inset-x-0 bottom-0 flex justify-center", children: _jsx("button", { onClick: scrollToBottom, className: cn('bg-primary hover:bg-primary/90 text-primary-foreground pointer-events-auto z-50', 'mb-6 translate-y-4 rounded-full p-2 opacity-0 shadow-md transition-all duration-200', showScrollButton && 'translate-y-0 opacity-100'), "aria-label": "Scroll to bottom", children: _jsx(ChevronDown, { className: "h-5 w-5" }) }) })] }));
28
+ return (_jsxs("div", { className: cn('relative flex h-full w-full flex-col', className), children: [_jsxs(ScrollArea, { viewportRef: containerRef, className: "flex w-full grow flex-col gap-5", children: [currentAnalysisResults?.map((analysisResult) => (_jsx(AnalysisResult, { analysisResult: analysisResult, enableReasoningBox: enableReasoningBox, customMarkdownComponents: customMarkdownComponents, excludeFromGrouping: excludeFromGrouping, ErrorMessageComponent: ErrorMessageComponent }, analysisResult.id))), isRunning && _jsx(AiThinkingDots, { className: "text-muted-foreground p-4" }), _jsx("div", { ref: endRef, className: "h-10 w-full shrink-0" }), _jsx(ScrollBar, { orientation: "vertical" }), _jsx(ScrollBar, { orientation: "horizontal" })] }), _jsx("div", { className: "pointer-events-none absolute inset-x-0 bottom-0 flex justify-center", children: _jsx("button", { onClick: scrollToBottom, className: cn('bg-primary hover:bg-primary/90 text-primary-foreground pointer-events-auto z-50', 'mb-6 translate-y-4 rounded-full p-2 opacity-0 shadow-md transition-all duration-200', showScrollButton && 'translate-y-0 opacity-100'), "aria-label": "Scroll to bottom", children: _jsx(ChevronDown, { className: "h-5 w-5" }) }) })] }));
29
29
  };
30
30
  //# sourceMappingURL=AnalysisResultsContainer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AnalysisResultsContainer.js","sourceRoot":"","sources":["../../src/components/AnalysisResultsContainer.tsx"],"names":[],"mappings":"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","sourcesContent":["import {cn, ScrollArea, ScrollBar} from '@sqlrooms/ui';\nimport {ChevronDown} from 'lucide-react';\nimport React, {useEffect, useRef} from 'react';\nimport {Components} from 'react-markdown';\nimport {useStoreWithAi} from '../AiSlice';\nimport {useScrollToBottom} from '../hooks/useScrollToBottom';\nimport {AnalysisResult} from './AnalysisResult';\nimport {AiThinkingDots} from './AiThinkingDots';\nimport type {ErrorMessageComponentProps} from './ErrorMessage';\n\nexport const AnalysisResultsContainer: React.FC<{\n className?: string;\n enableReasoningBox?: boolean;\n customMarkdownComponents?: Partial<Components>;\n excludeFromGrouping?: string[];\n ErrorMessageComponent?: React.ComponentType<ErrorMessageComponentProps>;\n}> = ({\n className,\n enableReasoningBox = false,\n customMarkdownComponents,\n excludeFromGrouping: excludeFromGrouping,\n ErrorMessageComponent,\n}) => {\n const currentSession = useStoreWithAi((s) => s.ai.getCurrentSession());\n const sessionId = currentSession?.id;\n const isRunning = useStoreWithAi((s) =>\n sessionId ? s.ai.getIsRunning(sessionId) : false,\n );\n const currentAnalysisResults = useStoreWithAi((s) =>\n s.ai.getAnalysisResults(),\n );\n const uiMessages = useStoreWithAi(\n (s) => s.ai.getCurrentSession()?.uiMessages,\n );\n\n const containerRef = useRef<HTMLDivElement>(null);\n const endRef = useRef<HTMLDivElement>(null);\n const {showScrollButton, scrollToBottom} = useScrollToBottom({\n containerRef,\n endRef,\n dataToObserve: uiMessages,\n });\n\n // Scroll to bottom when analysis starts\n useEffect(() => {\n if (isRunning) {\n scrollToBottom();\n }\n }, [isRunning, scrollToBottom]);\n\n return (\n <div className={cn('relative flex h-full w-full flex-col', className)}>\n <ScrollArea\n viewportRef={containerRef}\n className=\"flex w-full flex-grow flex-col gap-5\"\n >\n {/* Render analysis results */}\n {currentAnalysisResults?.map((analysisResult) => (\n <AnalysisResult\n key={analysisResult.id}\n analysisResult={analysisResult}\n enableReasoningBox={enableReasoningBox}\n customMarkdownComponents={customMarkdownComponents}\n excludeFromGrouping={excludeFromGrouping}\n ErrorMessageComponent={ErrorMessageComponent}\n />\n ))}\n {isRunning && (\n <AiThinkingDots className=\"text-muted-foreground p-4\" />\n )}\n <div ref={endRef} className=\"h-10 w-full shrink-0\" />\n <ScrollBar orientation=\"vertical\" />\n <ScrollBar orientation=\"horizontal\" />\n </ScrollArea>\n <div className=\"pointer-events-none absolute inset-x-0 bottom-0 flex justify-center\">\n <button\n onClick={scrollToBottom}\n className={cn(\n 'bg-primary hover:bg-primary/90 text-primary-foreground pointer-events-auto z-50',\n 'mb-6 translate-y-4 rounded-full p-2 opacity-0 shadow-md transition-all duration-200',\n showScrollButton && 'translate-y-0 opacity-100',\n )}\n aria-label=\"Scroll to bottom\"\n >\n <ChevronDown className=\"h-5 w-5\" />\n </button>\n </div>\n </div>\n );\n};\n"]}
1
+ {"version":3,"file":"AnalysisResultsContainer.js","sourceRoot":"","sources":["../../src/components/AnalysisResultsContainer.tsx"],"names":[],"mappings":"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","sourcesContent":["import {cn, ScrollArea, ScrollBar} from '@sqlrooms/ui';\nimport {ChevronDown} from 'lucide-react';\nimport React, {useEffect, useRef} from 'react';\nimport {Components} from 'react-markdown';\nimport {useStoreWithAi} from '../AiSlice';\nimport {useScrollToBottom} from '../hooks/useScrollToBottom';\nimport {AnalysisResult} from './AnalysisResult';\nimport {AiThinkingDots} from './AiThinkingDots';\nimport type {ErrorMessageComponentProps} from './ErrorMessage';\n\nexport const AnalysisResultsContainer: React.FC<{\n className?: string;\n enableReasoningBox?: boolean;\n customMarkdownComponents?: Partial<Components>;\n excludeFromGrouping?: string[];\n ErrorMessageComponent?: React.ComponentType<ErrorMessageComponentProps>;\n}> = ({\n className,\n enableReasoningBox = false,\n customMarkdownComponents,\n excludeFromGrouping: excludeFromGrouping,\n ErrorMessageComponent,\n}) => {\n const currentSession = useStoreWithAi((s) => s.ai.getCurrentSession());\n const sessionId = currentSession?.id;\n const isRunning = useStoreWithAi((s) =>\n sessionId ? s.ai.getIsRunning(sessionId) : false,\n );\n const currentAnalysisResults = useStoreWithAi((s) =>\n s.ai.getAnalysisResults(),\n );\n const uiMessages = useStoreWithAi(\n (s) => s.ai.getCurrentSession()?.uiMessages,\n );\n\n const containerRef = useRef<HTMLDivElement>(null);\n const endRef = useRef<HTMLDivElement>(null);\n const {showScrollButton, scrollToBottom} = useScrollToBottom({\n containerRef,\n endRef,\n dataToObserve: uiMessages,\n });\n\n // Scroll to bottom when analysis starts\n useEffect(() => {\n if (isRunning) {\n scrollToBottom();\n }\n }, [isRunning, scrollToBottom]);\n\n return (\n <div className={cn('relative flex h-full w-full flex-col', className)}>\n <ScrollArea\n viewportRef={containerRef}\n className=\"flex w-full grow flex-col gap-5\"\n >\n {/* Render analysis results */}\n {currentAnalysisResults?.map((analysisResult) => (\n <AnalysisResult\n key={analysisResult.id}\n analysisResult={analysisResult}\n enableReasoningBox={enableReasoningBox}\n customMarkdownComponents={customMarkdownComponents}\n excludeFromGrouping={excludeFromGrouping}\n ErrorMessageComponent={ErrorMessageComponent}\n />\n ))}\n {isRunning && <AiThinkingDots className=\"text-muted-foreground p-4\" />}\n <div ref={endRef} className=\"h-10 w-full shrink-0\" />\n <ScrollBar orientation=\"vertical\" />\n <ScrollBar orientation=\"horizontal\" />\n </ScrollArea>\n <div className=\"pointer-events-none absolute inset-x-0 bottom-0 flex justify-center\">\n <button\n onClick={scrollToBottom}\n className={cn(\n 'bg-primary hover:bg-primary/90 text-primary-foreground pointer-events-auto z-50',\n 'mb-6 translate-y-4 rounded-full p-2 opacity-0 shadow-md transition-all duration-200',\n showScrollButton && 'translate-y-0 opacity-100',\n )}\n aria-label=\"Scroll to bottom\"\n >\n <ChevronDown className=\"h-5 w-5\" />\n </button>\n </div>\n </div>\n );\n};\n"]}
@@ -19,7 +19,7 @@ const Container = ({ isLoading = false, className, children, }) => {
19
19
  }
20
20
  return (_jsx(TooltipProvider, { children: _jsx("div", { className: cn('w-full py-1', className), children: _jsxs("div", { className: "flex h-full w-full gap-2", children: [_jsx(ScrollableRow, { className: "min-w-0 flex-1", scrollClassName: "flex flex-1 snap-x snap-mandatory scroll-pl-7 scroll-pr-7 gap-2 overflow-x-auto overflow-y-hidden px-1 py-1 [-ms-overflow-style:none] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden", arrowVisibility: "always", arrowIconClassName: "h-4 w-4 opacity-80", children: isLoading
21
21
  ? // Show placeholder buttons with spinners while loading
22
- Array.from({ length: 3 }).map((_, index) => (_jsx("div", { className: "shrink-0 snap-start", children: _jsx(Button, { disabled: true, className: cn('bg-muted/50 border-border border', 'rounded-lg', 'text-muted-foreground text-xs', 'relative', 'flex items-center justify-center', 'px-4 py-2', 'h-18 max-h-18 min-h-18 w-48 min-w-48 max-w-48'), type: "button", children: _jsx(Spinner, { className: "text-muted-foreground h-3.5 w-3.5" }) }) }, index)))
22
+ Array.from({ length: 3 }).map((_, index) => (_jsx("div", { className: "shrink-0 snap-start", children: _jsx(Button, { disabled: true, className: cn('bg-muted/50 border-border border', 'rounded-lg', 'text-muted-foreground text-xs', 'relative', 'flex items-center justify-center', 'px-4 py-2', 'h-18 max-h-18 min-h-18 w-48 max-w-48 min-w-48'), type: "button", children: _jsx(Spinner, { className: "text-muted-foreground h-3.5 w-3.5" }) }) }, index)))
23
23
  : children }), _jsx("div", { className: "flex shrink-0 items-center pr-1", children: _jsx(Button, { onClick: toggleVisibility, variant: "ghost", size: "icon", className: "text-muted-foreground hover:text-foreground h-6 w-6 shrink-0", title: "Hide prompt suggestions", children: _jsx(X, { className: "h-4 w-4" }) }) })] }) }) }));
24
24
  };
25
25
  /**
@@ -41,7 +41,7 @@ const Item = ({ text, className, icon, }) => {
41
41
  inline: 'nearest',
42
42
  });
43
43
  }, [text, setPrompt, currentSession]);
44
- return (_jsx("div", { className: "shrink-0 snap-start", children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs(Button, { ref: buttonRef, onClick: handleClick, className: cn('bg-muted/50 hover:bg-muted hover:shadow-lg', 'border-border hover:border-primary/50 border', 'rounded-lg', 'text-muted-foreground hover:text-foreground text-xs', 'transition-all duration-200 ease-in-out', 'hover:-translate-y-0.5 hover:scale-[1.02]', 'cursor-pointer', 'relative', 'flex items-start justify-start', 'text-left', 'overflow-hidden', 'py-2 pl-8 pr-4', 'h-18 max-h-18 min-h-18 w-48 min-w-48 max-w-48', className), type: "button", title: text, children: [_jsx("span", { className: "absolute left-2 top-3 opacity-60", children: icon ?? _jsx(Lightbulb, { className: "h-3.5 w-3.5" }) }), _jsx("span", { className: "line-clamp-2 text-wrap break-words", children: truncate(text, 40) })] }) }), _jsx(TooltipContent, { children: _jsx("p", { className: "max-w-xs", children: text }) })] }) }));
44
+ return (_jsx("div", { className: "shrink-0 snap-start", children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs(Button, { ref: buttonRef, onClick: handleClick, className: cn('bg-muted/50 hover:bg-muted hover:shadow-lg', 'border-border hover:border-primary/50 border', 'rounded-lg', 'text-muted-foreground hover:text-foreground text-xs', 'transition-all duration-200 ease-in-out', 'hover:-translate-y-0.5 hover:scale-[1.02]', 'cursor-pointer', 'relative', 'flex items-start justify-start', 'text-left', 'overflow-hidden', 'py-2 pr-4 pl-8', 'h-18 max-h-18 min-h-18 w-48 max-w-48 min-w-48', className), type: "button", title: text, children: [_jsx("span", { className: "absolute top-3 left-2 opacity-60", children: icon ?? _jsx(Lightbulb, { className: "h-3.5 w-3.5" }) }), _jsx("span", { className: "line-clamp-2 text-wrap wrap-break-word", children: truncate(text, 40) })] }) }), _jsx(TooltipContent, { children: _jsx("p", { className: "max-w-xs", children: text }) })] }) }));
45
45
  };
46
46
  /**
47
47
  * Toggle button for showing/hiding prompt suggestions
@@ -1 +1 @@
1
- {"version":3,"file":"PromptSuggestions.js","sourceRoot":"","sources":["../../src/components/PromptSuggestions.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n cn,\n Button,\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger,\n Spinner,\n ScrollableRow,\n} from '@sqlrooms/ui';\nimport {Lightbulb, X} from 'lucide-react';\nimport {PropsWithChildren, useCallback, useRef} from 'react';\nimport {useStoreWithAi} from '../AiSlice';\nimport {truncate} from '@sqlrooms/utils';\n\ntype PromptSuggestionsContainerProps = PropsWithChildren<{\n isLoading?: boolean;\n className?: string;\n}>;\n\n/**\n * Container component for prompt suggestions\n * Shows suggestions when visible, returns null when not visible\n */\nconst Container: React.FC<PromptSuggestionsContainerProps> = ({\n isLoading = false,\n className,\n children,\n}) => {\n const isVisible = useStoreWithAi((s) => s.ai.promptSuggestionsVisible);\n const setIsVisible = useStoreWithAi((s) => s.ai.setPromptSuggestionsVisible);\n\n const toggleVisibility = useCallback(() => {\n setIsVisible(!isVisible);\n }, [isVisible, setIsVisible]);\n\n if (!isVisible) {\n return null;\n }\n\n return (\n <TooltipProvider>\n <div className={cn('w-full py-1', className)}>\n {/* Container with scrollable suggestions and hide button */}\n <div className=\"flex h-full w-full gap-2\">\n <ScrollableRow\n className=\"min-w-0 flex-1\"\n scrollClassName=\"flex flex-1 snap-x snap-mandatory scroll-pl-7 scroll-pr-7 gap-2 overflow-x-auto overflow-y-hidden px-1 py-1 [-ms-overflow-style:none] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden\"\n arrowVisibility=\"always\"\n arrowIconClassName=\"h-4 w-4 opacity-80\"\n >\n {isLoading\n ? // Show placeholder buttons with spinners while loading\n Array.from({length: 3}).map((_, index) => (\n <div key={index} className=\"shrink-0 snap-start\">\n <Button\n disabled\n className={cn(\n 'bg-muted/50 border-border border',\n 'rounded-lg',\n 'text-muted-foreground text-xs',\n 'relative',\n 'flex items-center justify-center',\n 'px-4 py-2',\n 'h-18 max-h-18 min-h-18 w-48 min-w-48 max-w-48',\n )}\n type=\"button\"\n >\n <Spinner className=\"text-muted-foreground h-3.5 w-3.5\" />\n </Button>\n </div>\n ))\n : children}\n </ScrollableRow>\n\n <div className=\"flex shrink-0 items-center pr-1\">\n <Button\n onClick={toggleVisibility}\n variant=\"ghost\"\n size=\"icon\"\n className=\"text-muted-foreground hover:text-foreground h-6 w-6 shrink-0\"\n title=\"Hide prompt suggestions\"\n >\n <X className=\"h-4 w-4\" />\n </Button>\n </div>\n </div>\n </div>\n </TooltipProvider>\n );\n};\n\ntype PromptSuggestionsItemProps = {\n text: string;\n className?: string;\n icon?: React.ReactNode;\n};\n\n/**\n * Individual prompt suggestion item component\n * Displays a single prompt suggestion and handles click events\n */\nconst Item: React.FC<PromptSuggestionsItemProps> = ({\n text,\n className,\n icon,\n}) => {\n const currentSession = useStoreWithAi((s) => s.ai.getCurrentSession());\n const setPrompt = useStoreWithAi((s) => s.ai.setPrompt);\n const buttonRef = useRef<HTMLButtonElement>(null);\n\n const handleClick = useCallback(() => {\n if (currentSession?.id) {\n setPrompt(currentSession.id, text);\n }\n // Scroll the clicked item into view\n buttonRef.current?.scrollIntoView({\n behavior: 'smooth',\n block: 'nearest',\n inline: 'nearest',\n });\n }, [text, setPrompt, currentSession]);\n\n return (\n <div className=\"shrink-0 snap-start\">\n <Tooltip>\n <TooltipTrigger asChild>\n <Button\n ref={buttonRef}\n onClick={handleClick}\n className={cn(\n 'bg-muted/50 hover:bg-muted hover:shadow-lg',\n 'border-border hover:border-primary/50 border',\n 'rounded-lg',\n 'text-muted-foreground hover:text-foreground text-xs',\n 'transition-all duration-200 ease-in-out',\n 'hover:-translate-y-0.5 hover:scale-[1.02]',\n 'cursor-pointer',\n 'relative',\n 'flex items-start justify-start',\n 'text-left',\n 'overflow-hidden',\n 'py-2 pl-8 pr-4',\n 'h-18 max-h-18 min-h-18 w-48 min-w-48 max-w-48',\n className,\n )}\n type=\"button\"\n title={text}\n >\n <span className=\"absolute left-2 top-3 opacity-60\">\n {icon ?? <Lightbulb className=\"h-3.5 w-3.5\" />}\n </span>\n <span className=\"line-clamp-2 text-wrap break-words\">\n {truncate(text, 40)}\n </span>\n </Button>\n </TooltipTrigger>\n <TooltipContent>\n <p className=\"max-w-xs\">{text}</p>\n </TooltipContent>\n </Tooltip>\n </div>\n );\n};\n\ntype PromptSuggestionsVisibilityToggleProps = {\n className?: string;\n icon?: React.ReactNode;\n};\n\n/**\n * Toggle button for showing/hiding prompt suggestions\n * Can be placed anywhere in the UI\n * Always shows a Lightbulb icon with styling that changes based on state\n */\nconst VisibilityToggle: React.FC<PromptSuggestionsVisibilityToggleProps> = ({\n className,\n icon,\n}) => {\n const isVisible = useStoreWithAi((s) => s.ai.promptSuggestionsVisible);\n const setIsVisible = useStoreWithAi((s) => s.ai.setPromptSuggestionsVisible);\n\n const toggleVisibility = useCallback(() => {\n setIsVisible(!isVisible);\n }, [isVisible, setIsVisible]);\n\n return (\n <Tooltip>\n <TooltipTrigger asChild>\n <Button\n onClick={toggleVisibility}\n variant=\"ghost\"\n size=\"icon\"\n className={cn(\n 'h-6 w-6 shrink-0',\n isVisible\n ? 'bg-secondary text-secondary-foreground hover:bg-secondary/80'\n : 'text-muted-foreground hover:text-foreground',\n className,\n )}\n title={\n isVisible ? 'Hide prompt suggestions' : 'Show prompt suggestions'\n }\n >\n {icon ?? <Lightbulb className=\"h-4 w-4\" />}\n </Button>\n </TooltipTrigger>\n <TooltipContent>\n <p>\n {isVisible ? 'Hide prompt suggestions' : 'Show prompt suggestions'}\n </p>\n </TooltipContent>\n </Tooltip>\n );\n};\n\n/**\n * Composable PromptSuggestions component with Container, Item, and VisibilityToggle subcomponents\n *\n * @example\n * ```tsx\n * <PromptSuggestions.Container isLoading={false}>\n * <PromptSuggestions.Item text=\"What are the top selling products?\" />\n * <PromptSuggestions.Item text=\"Show me the revenue trends\" />\n * </PromptSuggestions.Container>\n *\n * <PromptSuggestions.VisibilityToggle />\n * ```\n */\nexport const PromptSuggestions = {\n Container,\n Item,\n VisibilityToggle,\n};\n"]}
1
+ {"version":3,"file":"PromptSuggestions.js","sourceRoot":"","sources":["../../src/components/PromptSuggestions.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n cn,\n Button,\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger,\n Spinner,\n ScrollableRow,\n} from '@sqlrooms/ui';\nimport {Lightbulb, X} from 'lucide-react';\nimport {PropsWithChildren, useCallback, useRef} from 'react';\nimport {useStoreWithAi} from '../AiSlice';\nimport {truncate} from '@sqlrooms/utils';\n\ntype PromptSuggestionsContainerProps = PropsWithChildren<{\n isLoading?: boolean;\n className?: string;\n}>;\n\n/**\n * Container component for prompt suggestions\n * Shows suggestions when visible, returns null when not visible\n */\nconst Container: React.FC<PromptSuggestionsContainerProps> = ({\n isLoading = false,\n className,\n children,\n}) => {\n const isVisible = useStoreWithAi((s) => s.ai.promptSuggestionsVisible);\n const setIsVisible = useStoreWithAi((s) => s.ai.setPromptSuggestionsVisible);\n\n const toggleVisibility = useCallback(() => {\n setIsVisible(!isVisible);\n }, [isVisible, setIsVisible]);\n\n if (!isVisible) {\n return null;\n }\n\n return (\n <TooltipProvider>\n <div className={cn('w-full py-1', className)}>\n {/* Container with scrollable suggestions and hide button */}\n <div className=\"flex h-full w-full gap-2\">\n <ScrollableRow\n className=\"min-w-0 flex-1\"\n scrollClassName=\"flex flex-1 snap-x snap-mandatory scroll-pl-7 scroll-pr-7 gap-2 overflow-x-auto overflow-y-hidden px-1 py-1 [-ms-overflow-style:none] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden\"\n arrowVisibility=\"always\"\n arrowIconClassName=\"h-4 w-4 opacity-80\"\n >\n {isLoading\n ? // Show placeholder buttons with spinners while loading\n Array.from({length: 3}).map((_, index) => (\n <div key={index} className=\"shrink-0 snap-start\">\n <Button\n disabled\n className={cn(\n 'bg-muted/50 border-border border',\n 'rounded-lg',\n 'text-muted-foreground text-xs',\n 'relative',\n 'flex items-center justify-center',\n 'px-4 py-2',\n 'h-18 max-h-18 min-h-18 w-48 max-w-48 min-w-48',\n )}\n type=\"button\"\n >\n <Spinner className=\"text-muted-foreground h-3.5 w-3.5\" />\n </Button>\n </div>\n ))\n : children}\n </ScrollableRow>\n\n <div className=\"flex shrink-0 items-center pr-1\">\n <Button\n onClick={toggleVisibility}\n variant=\"ghost\"\n size=\"icon\"\n className=\"text-muted-foreground hover:text-foreground h-6 w-6 shrink-0\"\n title=\"Hide prompt suggestions\"\n >\n <X className=\"h-4 w-4\" />\n </Button>\n </div>\n </div>\n </div>\n </TooltipProvider>\n );\n};\n\ntype PromptSuggestionsItemProps = {\n text: string;\n className?: string;\n icon?: React.ReactNode;\n};\n\n/**\n * Individual prompt suggestion item component\n * Displays a single prompt suggestion and handles click events\n */\nconst Item: React.FC<PromptSuggestionsItemProps> = ({\n text,\n className,\n icon,\n}) => {\n const currentSession = useStoreWithAi((s) => s.ai.getCurrentSession());\n const setPrompt = useStoreWithAi((s) => s.ai.setPrompt);\n const buttonRef = useRef<HTMLButtonElement>(null);\n\n const handleClick = useCallback(() => {\n if (currentSession?.id) {\n setPrompt(currentSession.id, text);\n }\n // Scroll the clicked item into view\n buttonRef.current?.scrollIntoView({\n behavior: 'smooth',\n block: 'nearest',\n inline: 'nearest',\n });\n }, [text, setPrompt, currentSession]);\n\n return (\n <div className=\"shrink-0 snap-start\">\n <Tooltip>\n <TooltipTrigger asChild>\n <Button\n ref={buttonRef}\n onClick={handleClick}\n className={cn(\n 'bg-muted/50 hover:bg-muted hover:shadow-lg',\n 'border-border hover:border-primary/50 border',\n 'rounded-lg',\n 'text-muted-foreground hover:text-foreground text-xs',\n 'transition-all duration-200 ease-in-out',\n 'hover:-translate-y-0.5 hover:scale-[1.02]',\n 'cursor-pointer',\n 'relative',\n 'flex items-start justify-start',\n 'text-left',\n 'overflow-hidden',\n 'py-2 pr-4 pl-8',\n 'h-18 max-h-18 min-h-18 w-48 max-w-48 min-w-48',\n className,\n )}\n type=\"button\"\n title={text}\n >\n <span className=\"absolute top-3 left-2 opacity-60\">\n {icon ?? <Lightbulb className=\"h-3.5 w-3.5\" />}\n </span>\n <span className=\"line-clamp-2 text-wrap wrap-break-word\">\n {truncate(text, 40)}\n </span>\n </Button>\n </TooltipTrigger>\n <TooltipContent>\n <p className=\"max-w-xs\">{text}</p>\n </TooltipContent>\n </Tooltip>\n </div>\n );\n};\n\ntype PromptSuggestionsVisibilityToggleProps = {\n className?: string;\n icon?: React.ReactNode;\n};\n\n/**\n * Toggle button for showing/hiding prompt suggestions\n * Can be placed anywhere in the UI\n * Always shows a Lightbulb icon with styling that changes based on state\n */\nconst VisibilityToggle: React.FC<PromptSuggestionsVisibilityToggleProps> = ({\n className,\n icon,\n}) => {\n const isVisible = useStoreWithAi((s) => s.ai.promptSuggestionsVisible);\n const setIsVisible = useStoreWithAi((s) => s.ai.setPromptSuggestionsVisible);\n\n const toggleVisibility = useCallback(() => {\n setIsVisible(!isVisible);\n }, [isVisible, setIsVisible]);\n\n return (\n <Tooltip>\n <TooltipTrigger asChild>\n <Button\n onClick={toggleVisibility}\n variant=\"ghost\"\n size=\"icon\"\n className={cn(\n 'h-6 w-6 shrink-0',\n isVisible\n ? 'bg-secondary text-secondary-foreground hover:bg-secondary/80'\n : 'text-muted-foreground hover:text-foreground',\n className,\n )}\n title={\n isVisible ? 'Hide prompt suggestions' : 'Show prompt suggestions'\n }\n >\n {icon ?? <Lightbulb className=\"h-4 w-4\" />}\n </Button>\n </TooltipTrigger>\n <TooltipContent>\n <p>\n {isVisible ? 'Hide prompt suggestions' : 'Show prompt suggestions'}\n </p>\n </TooltipContent>\n </Tooltip>\n );\n};\n\n/**\n * Composable PromptSuggestions component with Container, Item, and VisibilityToggle subcomponents\n *\n * @example\n * ```tsx\n * <PromptSuggestions.Container isLoading={false}>\n * <PromptSuggestions.Item text=\"What are the top selling products?\" />\n * <PromptSuggestions.Item text=\"Show me the revenue trends\" />\n * </PromptSuggestions.Container>\n *\n * <PromptSuggestions.VisibilityToggle />\n * ```\n */\nexport const PromptSuggestions = {\n Container,\n Item,\n VisibilityToggle,\n};\n"]}
@@ -83,7 +83,7 @@ export const QueryControls = ({ className, placeholder = 'What would you like to
83
83
  return (_jsx("div", { className: cn('flex w-full flex-col items-center justify-center gap-2', className), children: _jsx("div", { className: "bg-muted/50 flex h-full w-full flex-row items-center gap-2 rounded-md border", children: _jsx("div", { className: "flex w-full flex-col gap-1 overflow-hidden", children: _jsx(InlineApiKeyInputRenderer, { inlineApiKeyInput: inlineApiKeyInput, children: otherChildren }) }) }) }));
84
84
  }
85
85
  // Render the normal prompt mode
86
- return (_jsx("div", { className: cn('flex w-full flex-col items-center justify-center gap-2', className), children: _jsx("div", { className: "bg-muted/50 flex h-full w-full flex-row items-center gap-2 rounded-md border", children: _jsxs("div", { className: "flex w-full flex-col gap-1 overflow-hidden", children: [_jsx(Textarea, { ref: textareaRef, className: "max-h-[min(300px,40vh)] min-h-[30px] resize-none border-none p-2 text-sm outline-none focus-visible:ring-0", autoResize: true, value: prompt, onChange: (e) => {
86
+ return (_jsx("div", { className: cn('flex w-full flex-col items-center justify-center gap-2', className), children: _jsx("div", { className: "bg-muted/50 flex h-full w-full flex-row items-center gap-2 rounded-md border", children: _jsxs("div", { className: "flex w-full flex-col gap-1 overflow-hidden", children: [_jsx(Textarea, { ref: textareaRef, className: "max-h-[min(300px,40vh)] min-h-[30px] resize-none border-none p-2 text-sm outline-hidden focus-visible:ring-0", autoResize: true, value: prompt, onChange: (e) => {
87
87
  if (sessionId) {
88
88
  setPrompt(sessionId, e.target.value);
89
89
  }
@@ -1 +1 @@
1
- {"version":3,"file":"QueryControls.js","sourceRoot":"","sources":["../../src/components/QueryControls.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAC,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAC,MAAM,cAAc,CAAC;AAClD,OAAO,EAAC,WAAW,EAAE,YAAY,EAAC,MAAM,cAAc,CAAC;AACvD,OAAO,EAEL,WAAW,EACX,MAAM,EACN,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,cAAc,GAEf,MAAM,OAAO,CAAC;AACf,OAAO,EAAC,cAAc,EAAC,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAC,iBAAiB,EAAE,uBAAuB,EAAC,MAAM,qBAAqB,CAAC;AAS/E;;GAEG;AACH,SAAS,mBAAmB,CAC1B,KAAgB;IAEhB,OAAO,cAAc,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,iBAAiB,CAAC;AACnE,CAAC;AAED;;GAEG;AACH,SAAS,wBAAwB,CAAC,QAAmB;IAMnD,IAAI,iBAAiB,GAEV,IAAI,CAAC;IAChB,MAAM,aAAa,GAAgB,EAAE,CAAC;IAEtC,QAAQ,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE;QACnC,IAAI,mBAAmB,CAAC,KAAK,CAAC,EAAE,CAAC;YAC/B,iBAAiB,GAAG,KAAK,CAAC;QAC5B,CAAC;aAAM,CAAC;YACN,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,EAAC,iBAAiB,EAAE,aAAa,EAAC,CAAC;AAC5C,CAAC;AAED,MAAM,CAAC,MAAM,aAAa,GAAiC,CAAC,EAC1D,SAAS,EACT,WAAW,GAAG,8CAA8C,EAC5D,QAAQ,EACR,KAAK,EACL,QAAQ,GACT,EAAE,EAAE;IACH,MAAM,WAAW,GAAG,MAAM,CAAsB,IAAI,CAAC,CAAC;IAEtD,MAAM,cAAc,GAAG,cAAc,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,iBAAiB,EAAE,CAAC,CAAC;IACvE,MAAM,SAAS,GAAG,cAAc,EAAE,EAAE,CAAC;IACrC,MAAM,KAAK,GAAG,cAAc,EAAE,KAAK,CAAC;IAEpC,MAAM,MAAM,GAAG,cAAc,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,qBAAqB,EAAE,CAAC,CAAC;IACnE,MAAM,cAAc,GAAG,cAAc,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,cAAc,EAAE,CAAC,CAAC;IAEpE,0CAA0C;IAC1C,MAAM,EAAC,iBAAiB,EAAE,aAAa,EAAC,GAAG,wBAAwB,CAAC,QAAQ,CAAC,CAAC;IAE9E,kEAAkE;IAClE,0BAA0B;IAC1B,2CAA2C;IAC3C,MAAM,eAAe,GACnB,iBAAiB,KAAK,IAAI;QAC1B,CAAC,CAAC,MAAM,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,IAAI,cAAc,CAAC,CAAC;IAE5D,MAAM,SAAS,GAAG,cAAc,CAAC,CAAC,CAAC,EAAE,EAAE,CACrC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,CACjD,CAAC;IACF,MAAM,MAAM,GAAG,cAAc,CAAC,CAAC,CAAC,EAAE,EAAE,CAClC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAC3C,CAAC;IACF,MAAM,SAAS,GAAG,cAAc,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC;IACxD,MAAM,WAAW,GAAG,cAAc,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC;IAC9D,MAAM,cAAc,GAAG,cAAc,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,cAAc,CAAC,CAAC;IAElE,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,eAAe;YAAE,OAAO;QAC5B,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YAC5B,WAAW,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC;QAC/B,CAAC,EAAE,GAAG,CAAC,CAAC;QACR,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IACnC,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC,CAAC;IAEtB,MAAM,aAAa,GAAG,WAAW,CAC/B,CAAC,CAA2C,EAAE,EAAE;QAC9C,IACE,CAAC,CAAC,GAAG,KAAK,OAAO;YACjB,CAAC,CAAC,CAAC,QAAQ;YACX,CAAC,CAAC,CAAC,OAAO;YACV,CAAC,CAAC,CAAC,MAAM;YACT,CAAC,CAAC,CAAC,OAAO,EACV,CAAC;YACD,CAAC,CAAC,cAAc,EAAE,CAAC;YACnB,IAAI,CAAC,SAAS,IAAI,SAAS,IAAI,KAAK,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC;gBAC7D,WAAW,CAAC,SAAS,CAAC,CAAC;YACzB,CAAC;QACH,CAAC;IACH,CAAC,EACD,CAAC,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC,CACnD,CAAC;IAEF,MAAM,QAAQ,GAAG,OAAO,CAAC,SAAS,IAAI,KAAK,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,CAAC;IAErE,MAAM,sBAAsB,GAAG,WAAW,CAAC,GAAG,EAAE;QAC9C,IAAI,CAAC,SAAS;YAAE,OAAO;QACvB,IAAI,SAAS,EAAE,CAAC;YACd,cAAc,CAAC,SAAS,CAAC,CAAC;YAC1B,QAAQ,EAAE,EAAE,CAAC;QACf,CAAC;aAAM,CAAC;YACN,WAAW,CAAC,SAAS,CAAC,CAAC;YACvB,KAAK,EAAE,EAAE,CAAC;QACZ,CAAC;IACH,CAAC,EAAE,CAAC,SAAS,EAAE,SAAS,EAAE,cAAc,EAAE,QAAQ,EAAE,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC;IAEzE,gCAAgC;IAChC,IAAI,eAAe,IAAI,iBAAiB,EAAE,CAAC;QACzC,OAAO,CACL,cACE,SAAS,EAAE,EAAE,CACX,wDAAwD,EACxD,SAAS,CACV,YAED,cAAK,SAAS,EAAC,8EAA8E,YAC3F,cAAK,SAAS,EAAC,4CAA4C,YAEzD,KAAC,yBAAyB,IAAC,iBAAiB,EAAE,iBAAiB,YAC5D,aAAa,GACY,GACxB,GACF,GACF,CACP,CAAC;IACJ,CAAC;IAED,gCAAgC;IAChC,OAAO,CACL,cACE,SAAS,EAAE,EAAE,CACX,wDAAwD,EACxD,SAAS,CACV,YAED,cAAK,SAAS,EAAC,8EAA8E,YAC3F,eAAK,SAAS,EAAC,4CAA4C,aACzD,KAAC,QAAQ,IACP,GAAG,EAAE,WAAW,EAChB,SAAS,EAAC,4GAA4G,EACtH,UAAU,QACV,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE;4BACd,IAAI,SAAS,EAAE,CAAC;gCACd,SAAS,CAAC,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;4BACvC,CAAC;wBACH,CAAC,EACD,SAAS,EAAE,aAAa,EACxB,WAAW,EAAE,WAAW,EACxB,SAAS,SACT,EACF,cAAK,SAAS,EAAC,8DAA8D,YAC3E,eAAK,SAAS,EAAC,+DAA+D,aAC5E,cAAK,SAAS,EAAC,gCAAgC,YAC7C,cAAK,SAAS,EAAC,+DAA+D,YAC3E,aAAa,GACV,GACF,EACN,cAAK,SAAS,EAAC,4BAA4B,YACzC,KAAC,MAAM,IACL,SAAS,EAAC,sBAAsB,EAChC,OAAO,EAAC,SAAS,EACjB,IAAI,EAAC,MAAM,EACX,OAAO,EAAE,sBAAsB,EAC/B,QAAQ,EAAE,CAAC,SAAS,IAAI,CAAC,QAAQ,YAEhC,SAAS,CAAC,CAAC,CAAC,KAAC,YAAY,KAAG,CAAC,CAAC,CAAC,KAAC,WAAW,KAAG,GACxC,GACL,IACF,GACF,IACF,GACF,GACF,CACP,CAAC;AACJ,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,yBAAyB,GAK1B,CAAC,EAAC,iBAAiB,EAAE,QAAQ,EAAC,EAAE,EAAE;IACrC,MAAM,QAAQ,GAAG,MAAM,CAAmB,IAAI,CAAC,CAAC;IAChD,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IAEnD,MAAM,aAAa,GAAG,cAAc,CAClC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,iBAAiB,EAAE,EAAE,aAAa,IAAI,QAAQ,CAC3D,CAAC;IACF,MAAM,cAAc,GAAG,cAAc,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,cAAc,CAAC,CAAC;IAElE,MAAM,EAAC,YAAY,EAAC,GAAG,iBAAiB,CAAC,KAAK,CAAC;IAE/C,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YAC5B,QAAQ,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC;QAC5B,CAAC,EAAE,GAAG,CAAC,CAAC;QACR,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IACnC,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,aAAa,GAAG,WAAW,CAC/B,CAAC,QAAgB,EAAE,MAAc,EAAE,EAAE;QACnC,kEAAkE;QAClE,cAAc,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QAChC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACjC,CAAC,EACD,CAAC,YAAY,EAAE,cAAc,CAAC,CAC/B,CAAC;IAEF,MAAM,aAAa,GAAG,WAAW,CAC/B,CAAC,CAAwC,EAAE,EAAE;QAC3C,IACE,CAAC,CAAC,GAAG,KAAK,OAAO;YACjB,CAAC,CAAC,CAAC,QAAQ;YACX,CAAC,CAAC,CAAC,OAAO;YACV,CAAC,CAAC,CAAC,MAAM;YACT,CAAC,CAAC,CAAC,OAAO,EACV,CAAC;YACD,CAAC,CAAC,cAAc,EAAE,CAAC;YACnB,IAAI,WAAW,CAAC,IAAI,EAAE,IAAI,aAAa,EAAE,CAAC;gBACxC,aAAa,CAAC,aAAa,EAAE,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC;gBACjD,cAAc,CAAC,EAAE,CAAC,CAAC;YACrB,CAAC;QACH,CAAC;IACH,CAAC,EACD,CAAC,WAAW,EAAE,aAAa,EAAE,aAAa,CAAC,CAC5C,CAAC;IAEF,MAAM,UAAU,GAAG,WAAW,CAAC,GAAG,EAAE;QAClC,IAAI,WAAW,CAAC,IAAI,EAAE,IAAI,aAAa,EAAE,CAAC;YACxC,aAAa,CAAC,aAAa,EAAE,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC;YACjD,cAAc,CAAC,EAAE,CAAC,CAAC;QACrB,CAAC;IACH,CAAC,EAAE,CAAC,WAAW,EAAE,aAAa,EAAE,aAAa,CAAC,CAAC,CAAC;IAEhD,MAAM,OAAO,GAAG,OAAO,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,MAAM,IAAI,aAAa,CAAC,CAAC;IAEpE,MAAM,mBAAmB,GAAG,CAAC,QAAgB,EAAE,EAAE,CAC/C,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAEvD,OAAO,CACL,8BACE,gBACE,GAAG,EAAE,QAAQ,EACb,IAAI,EAAC,UAAU,EACf,SAAS,EAAC,8FAA8F,EACxG,KAAK,EAAE,WAAW,EAClB,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAC/C,SAAS,EAAE,aAAa,EACxB,WAAW,EAAE,cAAc,mBAAmB,CAAC,aAAa,CAAC,aAAa,EAC1E,SAAS,QACT,YAAY,EAAC,KAAK,GAClB,EACF,cAAK,SAAS,EAAC,8DAA8D,YAC3E,eAAK,SAAS,EAAC,+DAA+D,aAC5E,cAAK,SAAS,EAAC,gCAAgC,YAC7C,cAAK,SAAS,EAAC,+DAA+D,YAC3E,QAAQ,GACL,GACF,EACN,cAAK,SAAS,EAAC,4BAA4B,YACzC,KAAC,uBAAuB,IAAC,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,OAAO,GAAI,GAC/D,IACF,GACF,IACL,CACJ,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import {Button, cn, Textarea} from '@sqlrooms/ui';\nimport {ArrowUpIcon, OctagonXIcon} from 'lucide-react';\nimport {\n PropsWithChildren,\n useCallback,\n useRef,\n useEffect,\n useState,\n Children,\n isValidElement,\n ReactNode,\n} from 'react';\nimport {useStoreWithAi} from '../AiSlice';\nimport {InlineApiKeyInput, InlineApiKeyInputButton} from './InlineApiKeyInput';\n\ntype QueryControlsProps = PropsWithChildren<{\n className?: string;\n placeholder?: string;\n onRun?: () => void;\n onCancel?: () => void;\n}>;\n\n/**\n * Checks if a child is an InlineApiKeyInput component\n */\nfunction isInlineApiKeyInput(\n child: ReactNode,\n): child is React.ReactElement<React.ComponentProps<typeof InlineApiKeyInput>> {\n return isValidElement(child) && child.type === InlineApiKeyInput;\n}\n\n/**\n * Extracts InlineApiKeyInput from children and returns the rest\n */\nfunction extractInlineApiKeyInput(children: ReactNode): {\n inlineApiKeyInput: React.ReactElement<\n React.ComponentProps<typeof InlineApiKeyInput>\n > | null;\n otherChildren: ReactNode[];\n} {\n let inlineApiKeyInput: React.ReactElement<\n React.ComponentProps<typeof InlineApiKeyInput>\n > | null = null;\n const otherChildren: ReactNode[] = [];\n\n Children.forEach(children, (child) => {\n if (isInlineApiKeyInput(child)) {\n inlineApiKeyInput = child;\n } else {\n otherChildren.push(child);\n }\n });\n\n return {inlineApiKeyInput, otherChildren};\n}\n\nexport const QueryControls: React.FC<QueryControlsProps> = ({\n className,\n placeholder = 'What would you like to learn about the data?',\n children,\n onRun,\n onCancel,\n}) => {\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n\n const currentSession = useStoreWithAi((s) => s.ai.getCurrentSession());\n const sessionId = currentSession?.id;\n const model = currentSession?.model;\n\n const apiKey = useStoreWithAi((s) => s.ai.getApiKeyFromSettings());\n const hasApiKeyError = useStoreWithAi((s) => s.ai.hasApiKeyError());\n\n // Extract InlineApiKeyInput from children\n const {inlineApiKeyInput, otherChildren} = extractInlineApiKeyInput(children);\n\n // Show API key input if InlineApiKeyInput is provided and either:\n // - No API key is set, OR\n // - There's an API key error (invalid key)\n const showApiKeyInput =\n inlineApiKeyInput !== null &&\n (!apiKey || apiKey.trim().length === 0 || hasApiKeyError);\n\n const isRunning = useStoreWithAi((s) =>\n sessionId ? s.ai.getIsRunning(sessionId) : false,\n );\n const prompt = useStoreWithAi((s) =>\n sessionId ? s.ai.getPrompt(sessionId) : '',\n );\n const setPrompt = useStoreWithAi((s) => s.ai.setPrompt);\n const runAnalysis = useStoreWithAi((s) => s.ai.startAnalysis);\n const cancelAnalysis = useStoreWithAi((s) => s.ai.cancelAnalysis);\n\n useEffect(() => {\n if (showApiKeyInput) return;\n const timer = setTimeout(() => {\n textareaRef.current?.focus();\n }, 500);\n return () => clearTimeout(timer);\n }, [showApiKeyInput]);\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (\n e.key === 'Enter' &&\n !e.shiftKey &&\n !e.ctrlKey &&\n !e.altKey &&\n !e.metaKey\n ) {\n e.preventDefault();\n if (!isRunning && sessionId && model && prompt.trim().length) {\n runAnalysis(sessionId);\n }\n }\n },\n [isRunning, sessionId, model, prompt, runAnalysis],\n );\n\n const canStart = Boolean(sessionId && model && prompt.trim().length);\n\n const handleClickRunOrCancel = useCallback(() => {\n if (!sessionId) return;\n if (isRunning) {\n cancelAnalysis(sessionId);\n onCancel?.();\n } else {\n runAnalysis(sessionId);\n onRun?.();\n }\n }, [sessionId, isRunning, cancelAnalysis, onCancel, runAnalysis, onRun]);\n\n // Render the API key input mode\n if (showApiKeyInput && inlineApiKeyInput) {\n return (\n <div\n className={cn(\n 'flex w-full flex-col items-center justify-center gap-2',\n className,\n )}\n >\n <div className=\"bg-muted/50 flex h-full w-full flex-row items-center gap-2 rounded-md border\">\n <div className=\"flex w-full flex-col gap-1 overflow-hidden\">\n {/* Render the InlineApiKeyInput which provides Input + Button */}\n <InlineApiKeyInputRenderer inlineApiKeyInput={inlineApiKeyInput}>\n {otherChildren}\n </InlineApiKeyInputRenderer>\n </div>\n </div>\n </div>\n );\n }\n\n // Render the normal prompt mode\n return (\n <div\n className={cn(\n 'flex w-full flex-col items-center justify-center gap-2',\n className,\n )}\n >\n <div className=\"bg-muted/50 flex h-full w-full flex-row items-center gap-2 rounded-md border\">\n <div className=\"flex w-full flex-col gap-1 overflow-hidden\">\n <Textarea\n ref={textareaRef}\n className=\"max-h-[min(300px,40vh)] min-h-[30px] resize-none border-none p-2 text-sm outline-none focus-visible:ring-0\"\n autoResize\n value={prompt}\n onChange={(e) => {\n if (sessionId) {\n setPrompt(sessionId, e.target.value);\n }\n }}\n onKeyDown={handleKeyDown}\n placeholder={placeholder}\n autoFocus\n />\n <div className=\"align-stretch flex w-full items-center gap-2 overflow-hidden\">\n <div className=\"flex h-full w-full min-w-0 items-center gap-2 overflow-hidden\">\n <div className=\"min-w-0 flex-1 overflow-hidden\">\n <div className=\"flex flex-nowrap items-center gap-2 overflow-x-auto py-1 pl-2\">\n {otherChildren}\n </div>\n </div>\n <div className=\"ml-auto shrink-0 gap-2 p-2\">\n <Button\n className=\"h-8 w-8 rounded-full\"\n variant=\"default\"\n size=\"icon\"\n onClick={handleClickRunOrCancel}\n disabled={!isRunning && !canStart}\n >\n {isRunning ? <OctagonXIcon /> : <ArrowUpIcon />}\n </Button>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n );\n};\n\n/**\n * Internal component that renders the InlineApiKeyInput with proper layout\n */\nconst InlineApiKeyInputRenderer: React.FC<{\n inlineApiKeyInput: React.ReactElement<\n React.ComponentProps<typeof InlineApiKeyInput>\n >;\n children: ReactNode;\n}> = ({inlineApiKeyInput, children}) => {\n const inputRef = useRef<HTMLInputElement>(null);\n const [apiKeyInput, setApiKeyInput] = useState('');\n\n const modelProvider = useStoreWithAi(\n (s) => s.ai.getCurrentSession()?.modelProvider || 'openai',\n );\n const setApiKeyError = useStoreWithAi((s) => s.ai.setApiKeyError);\n\n const {onSaveApiKey} = inlineApiKeyInput.props;\n\n useEffect(() => {\n const timer = setTimeout(() => {\n inputRef.current?.focus();\n }, 500);\n return () => clearTimeout(timer);\n }, []);\n\n const handleSaveKey = useCallback(\n (provider: string, apiKey: string) => {\n // Clear the API key error for this provider when saving a new key\n setApiKeyError(provider, false);\n onSaveApiKey(provider, apiKey);\n },\n [onSaveApiKey, setApiKeyError],\n );\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent<HTMLInputElement>) => {\n if (\n e.key === 'Enter' &&\n !e.shiftKey &&\n !e.ctrlKey &&\n !e.altKey &&\n !e.metaKey\n ) {\n e.preventDefault();\n if (apiKeyInput.trim() && modelProvider) {\n handleSaveKey(modelProvider, apiKeyInput.trim());\n setApiKeyInput('');\n }\n }\n },\n [apiKeyInput, modelProvider, handleSaveKey],\n );\n\n const handleSave = useCallback(() => {\n if (apiKeyInput.trim() && modelProvider) {\n handleSaveKey(modelProvider, apiKeyInput.trim());\n setApiKeyInput('');\n }\n }, [apiKeyInput, modelProvider, handleSaveKey]);\n\n const canSave = Boolean(apiKeyInput.trim().length && modelProvider);\n\n const formatProviderLabel = (provider: string) =>\n provider.charAt(0).toUpperCase() + provider.slice(1);\n\n return (\n <>\n <input\n ref={inputRef}\n type=\"password\"\n className=\"min-h-[30px] flex-1 border-none bg-transparent p-2 text-sm outline-none focus-visible:ring-0\"\n value={apiKeyInput}\n onChange={(e) => setApiKeyInput(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder={`Enter your ${formatProviderLabel(modelProvider)} API key...`}\n autoFocus\n autoComplete=\"off\"\n />\n <div className=\"align-stretch flex w-full items-center gap-2 overflow-hidden\">\n <div className=\"flex h-full w-full min-w-0 items-center gap-2 overflow-hidden\">\n <div className=\"min-w-0 flex-1 overflow-hidden\">\n <div className=\"flex flex-nowrap items-center gap-2 overflow-x-auto py-1 pl-2\">\n {children}\n </div>\n </div>\n <div className=\"ml-auto shrink-0 gap-2 p-2\">\n <InlineApiKeyInputButton onSave={handleSave} disabled={!canSave} />\n </div>\n </div>\n </div>\n </>\n );\n};\n"]}
1
+ {"version":3,"file":"QueryControls.js","sourceRoot":"","sources":["../../src/components/QueryControls.tsx"],"names":[],"mappings":"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","sourcesContent":["import {Button, cn, Textarea} from '@sqlrooms/ui';\nimport {ArrowUpIcon, OctagonXIcon} from 'lucide-react';\nimport {\n PropsWithChildren,\n useCallback,\n useRef,\n useEffect,\n useState,\n Children,\n isValidElement,\n ReactNode,\n} from 'react';\nimport {useStoreWithAi} from '../AiSlice';\nimport {InlineApiKeyInput, InlineApiKeyInputButton} from './InlineApiKeyInput';\n\ntype QueryControlsProps = PropsWithChildren<{\n className?: string;\n placeholder?: string;\n onRun?: () => void;\n onCancel?: () => void;\n}>;\n\n/**\n * Checks if a child is an InlineApiKeyInput component\n */\nfunction isInlineApiKeyInput(\n child: ReactNode,\n): child is React.ReactElement<React.ComponentProps<typeof InlineApiKeyInput>> {\n return isValidElement(child) && child.type === InlineApiKeyInput;\n}\n\n/**\n * Extracts InlineApiKeyInput from children and returns the rest\n */\nfunction extractInlineApiKeyInput(children: ReactNode): {\n inlineApiKeyInput: React.ReactElement<\n React.ComponentProps<typeof InlineApiKeyInput>\n > | null;\n otherChildren: ReactNode[];\n} {\n let inlineApiKeyInput: React.ReactElement<\n React.ComponentProps<typeof InlineApiKeyInput>\n > | null = null;\n const otherChildren: ReactNode[] = [];\n\n Children.forEach(children, (child) => {\n if (isInlineApiKeyInput(child)) {\n inlineApiKeyInput = child;\n } else {\n otherChildren.push(child);\n }\n });\n\n return {inlineApiKeyInput, otherChildren};\n}\n\nexport const QueryControls: React.FC<QueryControlsProps> = ({\n className,\n placeholder = 'What would you like to learn about the data?',\n children,\n onRun,\n onCancel,\n}) => {\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n\n const currentSession = useStoreWithAi((s) => s.ai.getCurrentSession());\n const sessionId = currentSession?.id;\n const model = currentSession?.model;\n\n const apiKey = useStoreWithAi((s) => s.ai.getApiKeyFromSettings());\n const hasApiKeyError = useStoreWithAi((s) => s.ai.hasApiKeyError());\n\n // Extract InlineApiKeyInput from children\n const {inlineApiKeyInput, otherChildren} = extractInlineApiKeyInput(children);\n\n // Show API key input if InlineApiKeyInput is provided and either:\n // - No API key is set, OR\n // - There's an API key error (invalid key)\n const showApiKeyInput =\n inlineApiKeyInput !== null &&\n (!apiKey || apiKey.trim().length === 0 || hasApiKeyError);\n\n const isRunning = useStoreWithAi((s) =>\n sessionId ? s.ai.getIsRunning(sessionId) : false,\n );\n const prompt = useStoreWithAi((s) =>\n sessionId ? s.ai.getPrompt(sessionId) : '',\n );\n const setPrompt = useStoreWithAi((s) => s.ai.setPrompt);\n const runAnalysis = useStoreWithAi((s) => s.ai.startAnalysis);\n const cancelAnalysis = useStoreWithAi((s) => s.ai.cancelAnalysis);\n\n useEffect(() => {\n if (showApiKeyInput) return;\n const timer = setTimeout(() => {\n textareaRef.current?.focus();\n }, 500);\n return () => clearTimeout(timer);\n }, [showApiKeyInput]);\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (\n e.key === 'Enter' &&\n !e.shiftKey &&\n !e.ctrlKey &&\n !e.altKey &&\n !e.metaKey\n ) {\n e.preventDefault();\n if (!isRunning && sessionId && model && prompt.trim().length) {\n runAnalysis(sessionId);\n }\n }\n },\n [isRunning, sessionId, model, prompt, runAnalysis],\n );\n\n const canStart = Boolean(sessionId && model && prompt.trim().length);\n\n const handleClickRunOrCancel = useCallback(() => {\n if (!sessionId) return;\n if (isRunning) {\n cancelAnalysis(sessionId);\n onCancel?.();\n } else {\n runAnalysis(sessionId);\n onRun?.();\n }\n }, [sessionId, isRunning, cancelAnalysis, onCancel, runAnalysis, onRun]);\n\n // Render the API key input mode\n if (showApiKeyInput && inlineApiKeyInput) {\n return (\n <div\n className={cn(\n 'flex w-full flex-col items-center justify-center gap-2',\n className,\n )}\n >\n <div className=\"bg-muted/50 flex h-full w-full flex-row items-center gap-2 rounded-md border\">\n <div className=\"flex w-full flex-col gap-1 overflow-hidden\">\n {/* Render the InlineApiKeyInput which provides Input + Button */}\n <InlineApiKeyInputRenderer inlineApiKeyInput={inlineApiKeyInput}>\n {otherChildren}\n </InlineApiKeyInputRenderer>\n </div>\n </div>\n </div>\n );\n }\n\n // Render the normal prompt mode\n return (\n <div\n className={cn(\n 'flex w-full flex-col items-center justify-center gap-2',\n className,\n )}\n >\n <div className=\"bg-muted/50 flex h-full w-full flex-row items-center gap-2 rounded-md border\">\n <div className=\"flex w-full flex-col gap-1 overflow-hidden\">\n <Textarea\n ref={textareaRef}\n className=\"max-h-[min(300px,40vh)] min-h-[30px] resize-none border-none p-2 text-sm outline-hidden focus-visible:ring-0\"\n autoResize\n value={prompt}\n onChange={(e) => {\n if (sessionId) {\n setPrompt(sessionId, e.target.value);\n }\n }}\n onKeyDown={handleKeyDown}\n placeholder={placeholder}\n autoFocus\n />\n <div className=\"align-stretch flex w-full items-center gap-2 overflow-hidden\">\n <div className=\"flex h-full w-full min-w-0 items-center gap-2 overflow-hidden\">\n <div className=\"min-w-0 flex-1 overflow-hidden\">\n <div className=\"flex flex-nowrap items-center gap-2 overflow-x-auto py-1 pl-2\">\n {otherChildren}\n </div>\n </div>\n <div className=\"ml-auto shrink-0 gap-2 p-2\">\n <Button\n className=\"h-8 w-8 rounded-full\"\n variant=\"default\"\n size=\"icon\"\n onClick={handleClickRunOrCancel}\n disabled={!isRunning && !canStart}\n >\n {isRunning ? <OctagonXIcon /> : <ArrowUpIcon />}\n </Button>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n );\n};\n\n/**\n * Internal component that renders the InlineApiKeyInput with proper layout\n */\nconst InlineApiKeyInputRenderer: React.FC<{\n inlineApiKeyInput: React.ReactElement<\n React.ComponentProps<typeof InlineApiKeyInput>\n >;\n children: ReactNode;\n}> = ({inlineApiKeyInput, children}) => {\n const inputRef = useRef<HTMLInputElement>(null);\n const [apiKeyInput, setApiKeyInput] = useState('');\n\n const modelProvider = useStoreWithAi(\n (s) => s.ai.getCurrentSession()?.modelProvider || 'openai',\n );\n const setApiKeyError = useStoreWithAi((s) => s.ai.setApiKeyError);\n\n const {onSaveApiKey} = inlineApiKeyInput.props;\n\n useEffect(() => {\n const timer = setTimeout(() => {\n inputRef.current?.focus();\n }, 500);\n return () => clearTimeout(timer);\n }, []);\n\n const handleSaveKey = useCallback(\n (provider: string, apiKey: string) => {\n // Clear the API key error for this provider when saving a new key\n setApiKeyError(provider, false);\n onSaveApiKey(provider, apiKey);\n },\n [onSaveApiKey, setApiKeyError],\n );\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent<HTMLInputElement>) => {\n if (\n e.key === 'Enter' &&\n !e.shiftKey &&\n !e.ctrlKey &&\n !e.altKey &&\n !e.metaKey\n ) {\n e.preventDefault();\n if (apiKeyInput.trim() && modelProvider) {\n handleSaveKey(modelProvider, apiKeyInput.trim());\n setApiKeyInput('');\n }\n }\n },\n [apiKeyInput, modelProvider, handleSaveKey],\n );\n\n const handleSave = useCallback(() => {\n if (apiKeyInput.trim() && modelProvider) {\n handleSaveKey(modelProvider, apiKeyInput.trim());\n setApiKeyInput('');\n }\n }, [apiKeyInput, modelProvider, handleSaveKey]);\n\n const canSave = Boolean(apiKeyInput.trim().length && modelProvider);\n\n const formatProviderLabel = (provider: string) =>\n provider.charAt(0).toUpperCase() + provider.slice(1);\n\n return (\n <>\n <input\n ref={inputRef}\n type=\"password\"\n className=\"min-h-[30px] flex-1 border-none bg-transparent p-2 text-sm outline-none focus-visible:ring-0\"\n value={apiKeyInput}\n onChange={(e) => setApiKeyInput(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder={`Enter your ${formatProviderLabel(modelProvider)} API key...`}\n autoFocus\n autoComplete=\"off\"\n />\n <div className=\"align-stretch flex w-full items-center gap-2 overflow-hidden\">\n <div className=\"flex h-full w-full min-w-0 items-center gap-2 overflow-hidden\">\n <div className=\"min-w-0 flex-1 overflow-hidden\">\n <div className=\"flex flex-nowrap items-center gap-2 overflow-x-auto py-1 pl-2\">\n {children}\n </div>\n </div>\n <div className=\"ml-auto shrink-0 gap-2 p-2\">\n <InlineApiKeyInputButton onSave={handleSave} disabled={!canSave} />\n </div>\n </div>\n </div>\n </>\n );\n};\n"]}
@@ -76,7 +76,7 @@ export const SessionControls = ({ className, children }) => {
76
76
  setSessionToRename(null);
77
77
  }, [sessionToRename, renameSession]);
78
78
  // Memoize render functions to prevent unnecessary re-renders
79
- const renderTabLabel = useCallback((tab) => (_jsxs("div", { className: "flex items-center gap-2", children: [getIsSessionRunning(tab.id) && (_jsx(Spinner, { className: "text-muted-foreground h-4 w-4 flex-shrink-0 animate-spin" })), _jsx("span", { className: "truncate", children: tab.name })] })), [getIsSessionRunning]);
79
+ const renderTabLabel = useCallback((tab) => (_jsxs("div", { className: "flex items-center gap-2", children: [getIsSessionRunning(tab.id) && (_jsx(Spinner, { className: "text-muted-foreground h-4 w-4 shrink-0 animate-spin" })), _jsx("span", { className: "truncate", children: tab.name })] })), [getIsSessionRunning]);
80
80
  const renderTabMenu = useCallback((tab) => (_jsxs(_Fragment, { children: [_jsxs(TabStrip.MenuItem, { onClick: () => handleRenameRequest(tab.id), children: [_jsx(PencilIcon, { className: "mr-2 h-4 w-4" }), "Rename"] }), sessions.length > 1 && (_jsxs(_Fragment, { children: [_jsx(TabStrip.MenuSeparator, {}), _jsxs(TabStrip.MenuItem, { variant: "destructive", onClick: () => handleDelete(tab.id), children: [_jsx(TrashIcon, { className: "mr-2 h-4 w-4" }), "Delete"] })] }))] })), [handleRenameRequest, handleDelete, sessions.length]);
81
81
  const renderSearchItemActions = useCallback((tab) => (_jsxs(_Fragment, { children: [_jsx(TabStrip.SearchItemAction, { icon: _jsx(PencilIcon, { className: "h-3 w-3" }), "aria-label": `Rename ${tab.name}`, onClick: () => handleRenameRequest(tab.id) }), sessions.length > 1 && (_jsx(TabStrip.SearchItemAction, { icon: _jsx(TrashIcon, { className: "h-3 w-3" }), "aria-label": `Delete ${tab.name}`, onClick: () => handleDelete(tab.id) }))] })), [handleRenameRequest, handleDelete, sessions.length]);
82
82
  return (_jsxs(_Fragment, { children: [_jsxs("div", { className: cn('flex w-full flex-wrap items-center justify-between gap-2 overflow-visible', className), children: [_jsx("div", { className: "flex w-full min-w-0 items-center gap-3", children: _jsxs(TabStrip, { className: "bg-background", tabs: tabs, preventCloseLastTab: true, openTabs: openTabs, selectedTabId: currentSessionId, onClose: handleClose, onOpenTabsChange: setOpenTabs, onSelect: switchSession, onCreate: () => createSession(), onRename: renameSession, renderTabLabel: renderTabLabel, renderTabMenu: renderTabMenu, renderSearchItemActions: renderSearchItemActions, children: [_jsx(TabStrip.SearchDropdown, { triggerIcon: _jsx(HistoryIcon, { className: "h-4 w-4" }), tooltip: "Session history", sortSearchItems: "recent", getTabLastOpenedAt: (tab) => tab.lastOpenedAt }), _jsx(TabStrip.Tabs, { tabClassName: "rounded-md data-[state=active]:bg-muted" }), _jsx(TabStrip.NewButton, { tooltip: "New session" })] }) }), children] }), _jsx(DeleteSessionDialog, { isOpen: sessionToDelete !== null, onClose: handleCloseDeleteDialog, onDelete: handleConfirmDelete }), _jsx(RenameSessionDialog, { isOpen: sessionToRename !== null, onClose: () => setSessionToRename(null), initialName: sessionToRename?.name ?? '', onRename: handleFinishRename })] }));
@@ -1 +1 @@
1
- {"version":3,"file":"SessionControls.js","sourceRoot":"","sources":["../../src/components/SessionControls.tsx"],"names":[],"mappings":"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","sourcesContent":["import {cn, Spinner, TabStrip} from '@sqlrooms/ui';\nimport {HistoryIcon, PencilIcon, TrashIcon} from 'lucide-react';\nimport {useCallback, useMemo, useState} from 'react';\nimport {useStoreWithAi} from '../AiSlice';\nimport {DeleteSessionDialog, RenameSessionDialog} from './session';\n\n/**\n * Main component for managing AI sessions.\n * Uses TabStrip for session management with dropdown for switching sessions.\n *\n * @example\n * ```tsx\n * <SessionControls className=\"p-4 border-b\">\n * <Button>Custom Button</Button>\n * </SessionControls>\n * ```\n */\nexport const SessionControls: React.FC<{\n className?: string;\n children?: React.ReactNode;\n}> = ({className, children}) => {\n const sessions = useStoreWithAi((s) => s.ai.config.sessions);\n const currentSessionId = useStoreWithAi((s) => s.ai.config.currentSessionId);\n const getIsSessionRunning = useStoreWithAi((s) => s.ai.getIsRunning);\n const switchSession = useStoreWithAi((s) => s.ai.switchSession);\n const createSession = useStoreWithAi((s) => s.ai.createSession);\n const renameSession = useStoreWithAi((s) => s.ai.renameSession);\n const deleteSession = useStoreWithAi((s) => s.ai.deleteSession);\n const openTabs = useStoreWithAi((s) => s.ai.config.openSessionTabs);\n const setOpenTabs = useStoreWithAi((s) => s.ai.setOpenSessionTabs);\n\n const [sessionToDelete, setSessionToDelete] = useState<string | null>(null);\n const [sessionToRename, setSessionToRename] = useState<{\n id: string;\n name: string;\n } | null>(null);\n\n // Convert sessions to TabDescriptor format\n const tabs = useMemo(\n () =>\n sessions.map((s) => ({\n id: s.id,\n name: s.name,\n lastOpenedAt: s.lastOpenedAt,\n })),\n [sessions],\n );\n\n const handleClose = useCallback(\n (sessionId: string) => {\n // Don't close if it's the only open tab\n if (!openTabs || openTabs.length <= 1) return;\n\n const remaining = openTabs.filter((id) => id !== sessionId);\n setOpenTabs(remaining);\n\n // If closing the current session, switch to another open one\n if (sessionId === currentSessionId && remaining.length > 0) {\n switchSession(remaining[0]!);\n }\n },\n [openTabs, currentSessionId, switchSession, setOpenTabs],\n );\n\n const handleDelete = useCallback(\n (sessionId: string) => {\n const session = sessions.find((s) => s.id === sessionId);\n // If session is empty (no messages), delete without confirmation\n if (!session?.uiMessages?.length) {\n deleteSession(sessionId);\n } else {\n setSessionToDelete(sessionId);\n }\n },\n [sessions, deleteSession],\n );\n\n const handleConfirmDelete = useCallback(() => {\n if (sessionToDelete) {\n deleteSession(sessionToDelete);\n setSessionToDelete(null);\n }\n }, [sessionToDelete, deleteSession]);\n\n const handleCloseDeleteDialog = useCallback(() => {\n setSessionToDelete(null);\n }, []);\n\n const handleRenameRequest = useCallback(\n (sessionId: string) => {\n const session = sessions.find((s) => s.id === sessionId);\n if (session) {\n setSessionToRename({id: sessionId, name: session.name});\n }\n },\n [sessions],\n );\n\n const handleFinishRename = useCallback(\n (newName: string) => {\n if (sessionToRename) {\n renameSession(sessionToRename.id, newName);\n }\n setSessionToRename(null);\n },\n [sessionToRename, renameSession],\n );\n\n // Memoize render functions to prevent unnecessary re-renders\n const renderTabLabel = useCallback(\n (tab: {id: string; name: string}) => (\n <div className=\"flex items-center gap-2\">\n {getIsSessionRunning(tab.id) && (\n <Spinner className=\"text-muted-foreground h-4 w-4 flex-shrink-0 animate-spin\" />\n )}\n <span className=\"truncate\">{tab.name}</span>\n </div>\n ),\n [getIsSessionRunning],\n );\n\n const renderTabMenu = useCallback(\n (tab: {id: string; name: string}) => (\n <>\n <TabStrip.MenuItem onClick={() => handleRenameRequest(tab.id)}>\n <PencilIcon className=\"mr-2 h-4 w-4\" />\n Rename\n </TabStrip.MenuItem>\n {sessions.length > 1 && (\n <>\n <TabStrip.MenuSeparator />\n <TabStrip.MenuItem\n variant=\"destructive\"\n onClick={() => handleDelete(tab.id)}\n >\n <TrashIcon className=\"mr-2 h-4 w-4\" />\n Delete\n </TabStrip.MenuItem>\n </>\n )}\n </>\n ),\n [handleRenameRequest, handleDelete, sessions.length],\n );\n\n const renderSearchItemActions = useCallback(\n (tab: {id: string; name: string}) => (\n <>\n <TabStrip.SearchItemAction\n icon={<PencilIcon className=\"h-3 w-3\" />}\n aria-label={`Rename ${tab.name}`}\n onClick={() => handleRenameRequest(tab.id)}\n />\n {sessions.length > 1 && (\n <TabStrip.SearchItemAction\n icon={<TrashIcon className=\"h-3 w-3\" />}\n aria-label={`Delete ${tab.name}`}\n onClick={() => handleDelete(tab.id)}\n />\n )}\n </>\n ),\n [handleRenameRequest, handleDelete, sessions.length],\n );\n\n return (\n <>\n <div\n className={cn(\n 'flex w-full flex-wrap items-center justify-between gap-2 overflow-visible',\n className,\n )}\n >\n <div className=\"flex w-full min-w-0 items-center gap-3\">\n <TabStrip\n className=\"bg-background\"\n tabs={tabs}\n preventCloseLastTab\n openTabs={openTabs}\n selectedTabId={currentSessionId}\n onClose={handleClose}\n onOpenTabsChange={setOpenTabs}\n onSelect={switchSession}\n onCreate={() => createSession()}\n onRename={renameSession}\n renderTabLabel={renderTabLabel}\n renderTabMenu={renderTabMenu}\n renderSearchItemActions={renderSearchItemActions}\n >\n <TabStrip.SearchDropdown\n triggerIcon={<HistoryIcon className=\"h-4 w-4\" />}\n tooltip=\"Session history\"\n sortSearchItems=\"recent\"\n getTabLastOpenedAt={(tab) =>\n tab.lastOpenedAt as number | undefined\n }\n />\n <TabStrip.Tabs tabClassName=\"rounded-md data-[state=active]:bg-muted\" />\n <TabStrip.NewButton tooltip=\"New session\" />\n </TabStrip>\n </div>\n\n {children}\n </div>\n\n <DeleteSessionDialog\n isOpen={sessionToDelete !== null}\n onClose={handleCloseDeleteDialog}\n onDelete={handleConfirmDelete}\n />\n <RenameSessionDialog\n isOpen={sessionToRename !== null}\n onClose={() => setSessionToRename(null)}\n initialName={sessionToRename?.name ?? ''}\n onRename={handleFinishRename}\n />\n </>\n );\n};\n"]}
1
+ {"version":3,"file":"SessionControls.js","sourceRoot":"","sources":["../../src/components/SessionControls.tsx"],"names":[],"mappings":"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","sourcesContent":["import {cn, Spinner, TabStrip} from '@sqlrooms/ui';\nimport {HistoryIcon, PencilIcon, TrashIcon} from 'lucide-react';\nimport {useCallback, useMemo, useState} from 'react';\nimport {useStoreWithAi} from '../AiSlice';\nimport {DeleteSessionDialog, RenameSessionDialog} from './session';\n\n/**\n * Main component for managing AI sessions.\n * Uses TabStrip for session management with dropdown for switching sessions.\n *\n * @example\n * ```tsx\n * <SessionControls className=\"p-4 border-b\">\n * <Button>Custom Button</Button>\n * </SessionControls>\n * ```\n */\nexport const SessionControls: React.FC<{\n className?: string;\n children?: React.ReactNode;\n}> = ({className, children}) => {\n const sessions = useStoreWithAi((s) => s.ai.config.sessions);\n const currentSessionId = useStoreWithAi((s) => s.ai.config.currentSessionId);\n const getIsSessionRunning = useStoreWithAi((s) => s.ai.getIsRunning);\n const switchSession = useStoreWithAi((s) => s.ai.switchSession);\n const createSession = useStoreWithAi((s) => s.ai.createSession);\n const renameSession = useStoreWithAi((s) => s.ai.renameSession);\n const deleteSession = useStoreWithAi((s) => s.ai.deleteSession);\n const openTabs = useStoreWithAi((s) => s.ai.config.openSessionTabs);\n const setOpenTabs = useStoreWithAi((s) => s.ai.setOpenSessionTabs);\n\n const [sessionToDelete, setSessionToDelete] = useState<string | null>(null);\n const [sessionToRename, setSessionToRename] = useState<{\n id: string;\n name: string;\n } | null>(null);\n\n // Convert sessions to TabDescriptor format\n const tabs = useMemo(\n () =>\n sessions.map((s) => ({\n id: s.id,\n name: s.name,\n lastOpenedAt: s.lastOpenedAt,\n })),\n [sessions],\n );\n\n const handleClose = useCallback(\n (sessionId: string) => {\n // Don't close if it's the only open tab\n if (!openTabs || openTabs.length <= 1) return;\n\n const remaining = openTabs.filter((id) => id !== sessionId);\n setOpenTabs(remaining);\n\n // If closing the current session, switch to another open one\n if (sessionId === currentSessionId && remaining.length > 0) {\n switchSession(remaining[0]!);\n }\n },\n [openTabs, currentSessionId, switchSession, setOpenTabs],\n );\n\n const handleDelete = useCallback(\n (sessionId: string) => {\n const session = sessions.find((s) => s.id === sessionId);\n // If session is empty (no messages), delete without confirmation\n if (!session?.uiMessages?.length) {\n deleteSession(sessionId);\n } else {\n setSessionToDelete(sessionId);\n }\n },\n [sessions, deleteSession],\n );\n\n const handleConfirmDelete = useCallback(() => {\n if (sessionToDelete) {\n deleteSession(sessionToDelete);\n setSessionToDelete(null);\n }\n }, [sessionToDelete, deleteSession]);\n\n const handleCloseDeleteDialog = useCallback(() => {\n setSessionToDelete(null);\n }, []);\n\n const handleRenameRequest = useCallback(\n (sessionId: string) => {\n const session = sessions.find((s) => s.id === sessionId);\n if (session) {\n setSessionToRename({id: sessionId, name: session.name});\n }\n },\n [sessions],\n );\n\n const handleFinishRename = useCallback(\n (newName: string) => {\n if (sessionToRename) {\n renameSession(sessionToRename.id, newName);\n }\n setSessionToRename(null);\n },\n [sessionToRename, renameSession],\n );\n\n // Memoize render functions to prevent unnecessary re-renders\n const renderTabLabel = useCallback(\n (tab: {id: string; name: string}) => (\n <div className=\"flex items-center gap-2\">\n {getIsSessionRunning(tab.id) && (\n <Spinner className=\"text-muted-foreground h-4 w-4 shrink-0 animate-spin\" />\n )}\n <span className=\"truncate\">{tab.name}</span>\n </div>\n ),\n [getIsSessionRunning],\n );\n\n const renderTabMenu = useCallback(\n (tab: {id: string; name: string}) => (\n <>\n <TabStrip.MenuItem onClick={() => handleRenameRequest(tab.id)}>\n <PencilIcon className=\"mr-2 h-4 w-4\" />\n Rename\n </TabStrip.MenuItem>\n {sessions.length > 1 && (\n <>\n <TabStrip.MenuSeparator />\n <TabStrip.MenuItem\n variant=\"destructive\"\n onClick={() => handleDelete(tab.id)}\n >\n <TrashIcon className=\"mr-2 h-4 w-4\" />\n Delete\n </TabStrip.MenuItem>\n </>\n )}\n </>\n ),\n [handleRenameRequest, handleDelete, sessions.length],\n );\n\n const renderSearchItemActions = useCallback(\n (tab: {id: string; name: string}) => (\n <>\n <TabStrip.SearchItemAction\n icon={<PencilIcon className=\"h-3 w-3\" />}\n aria-label={`Rename ${tab.name}`}\n onClick={() => handleRenameRequest(tab.id)}\n />\n {sessions.length > 1 && (\n <TabStrip.SearchItemAction\n icon={<TrashIcon className=\"h-3 w-3\" />}\n aria-label={`Delete ${tab.name}`}\n onClick={() => handleDelete(tab.id)}\n />\n )}\n </>\n ),\n [handleRenameRequest, handleDelete, sessions.length],\n );\n\n return (\n <>\n <div\n className={cn(\n 'flex w-full flex-wrap items-center justify-between gap-2 overflow-visible',\n className,\n )}\n >\n <div className=\"flex w-full min-w-0 items-center gap-3\">\n <TabStrip\n className=\"bg-background\"\n tabs={tabs}\n preventCloseLastTab\n openTabs={openTabs}\n selectedTabId={currentSessionId}\n onClose={handleClose}\n onOpenTabsChange={setOpenTabs}\n onSelect={switchSession}\n onCreate={() => createSession()}\n onRename={renameSession}\n renderTabLabel={renderTabLabel}\n renderTabMenu={renderTabMenu}\n renderSearchItemActions={renderSearchItemActions}\n >\n <TabStrip.SearchDropdown\n triggerIcon={<HistoryIcon className=\"h-4 w-4\" />}\n tooltip=\"Session history\"\n sortSearchItems=\"recent\"\n getTabLastOpenedAt={(tab) =>\n tab.lastOpenedAt as number | undefined\n }\n />\n <TabStrip.Tabs tabClassName=\"rounded-md data-[state=active]:bg-muted\" />\n <TabStrip.NewButton tooltip=\"New session\" />\n </TabStrip>\n </div>\n\n {children}\n </div>\n\n <DeleteSessionDialog\n isOpen={sessionToDelete !== null}\n onClose={handleCloseDeleteDialog}\n onDelete={handleConfirmDelete}\n />\n <RenameSessionDialog\n isOpen={sessionToRename !== null}\n onClose={() => setSessionToRename(null)}\n initialName={sessionToRename?.name ?? ''}\n onRename={handleFinishRename}\n />\n </>\n );\n};\n"]}
@@ -17,6 +17,6 @@ import { cn } from '@sqlrooms/ui';
17
17
  */
18
18
  export const ToolCallInfo = ({ toolName, input, isCompleted, state, }) => {
19
19
  const [isExpanded, setIsExpanded] = useState(false);
20
- return (_jsxs("div", { className: "flex flex-col gap-1", children: [_jsxs("div", { className: "flex items-center gap-2 pl-2 text-xs text-gray-700 dark:text-gray-300", children: [state !== 'output-available' && state !== 'output-error' ? (_jsx(Loader2, { className: "h-4 w-4 shrink-0 animate-spin text-gray-400 dark:text-gray-500" })) : (_jsx(CircleArrowRightIcon, { className: "h-4 w-4 shrink-0 text-gray-400 dark:text-gray-500" })), _jsxs("button", { onClick: () => setIsExpanded(!isExpanded), className: cn('flex items-center gap-1 rounded px-1 py-0.5 font-medium transition-colors', 'text-gray-700'), children: [isExpanded ? (_jsx(ChevronDownIcon, { className: "h-3 w-3" })) : (_jsx(ChevronRightIcon, { className: "h-3 w-3" })), _jsx("span", { children: toolName })] })] }), isExpanded && (_jsx("div", { className: "px-5 py-2", children: _jsx("pre", { className: "text-muted-foreground bg-muted m-0 max-h-24 overflow-auto whitespace-pre-wrap break-words rounded-md p-2 font-mono text-xs", children: JSON.stringify(input, null, 2) }) }))] }));
20
+ return (_jsxs("div", { className: "flex flex-col gap-1", children: [_jsxs("div", { className: "flex items-center gap-2 pl-2 text-xs text-gray-700 dark:text-gray-300", children: [state !== 'output-available' && state !== 'output-error' ? (_jsx(Loader2, { className: "h-4 w-4 shrink-0 animate-spin text-gray-400 dark:text-gray-500" })) : (_jsx(CircleArrowRightIcon, { className: "h-4 w-4 shrink-0 text-gray-400 dark:text-gray-500" })), _jsxs("button", { onClick: () => setIsExpanded(!isExpanded), className: cn('flex items-center gap-1 rounded px-1 py-0.5 font-medium transition-colors', 'text-gray-700'), children: [isExpanded ? (_jsx(ChevronDownIcon, { className: "h-3 w-3" })) : (_jsx(ChevronRightIcon, { className: "h-3 w-3" })), _jsx("span", { children: toolName })] })] }), isExpanded && (_jsx("div", { className: "px-5 py-2", children: _jsx("pre", { className: "text-muted-foreground bg-muted m-0 max-h-24 overflow-auto rounded-md p-2 font-mono text-xs wrap-break-word whitespace-pre-wrap", children: JSON.stringify(input, null, 2) }) }))] }));
21
21
  };
22
22
  //# sourceMappingURL=ToolCallInfo.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ToolCallInfo.js","sourceRoot":"","sources":["../../src/components/ToolCallInfo.tsx"],"names":[],"mappings":";AAAA,OAAO,EACL,oBAAoB,EACpB,eAAe,EACf,gBAAgB,EAChB,OAAO,GACR,MAAM,cAAc,CAAC;AACtB,OAAO,EAAC,QAAQ,EAAC,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAC,EAAE,EAAC,MAAM,cAAc,CAAC;AAgBhC;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,YAAY,GAAgC,CAAC,EACxD,QAAQ,EACR,KAAK,EACL,WAAW,EACX,KAAK,GACN,EAAE,EAAE;IACH,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAEpD,OAAO,CACL,eAAK,SAAS,EAAC,qBAAqB,aAClC,eAAK,SAAS,EAAC,uEAAuE,aAEnF,KAAK,KAAK,kBAAkB,IAAI,KAAK,KAAK,cAAc,CAAC,CAAC,CAAC,CAC1D,KAAC,OAAO,IAAC,SAAS,EAAC,gEAAgE,GAAG,CACvF,CAAC,CAAC,CAAC,CACF,KAAC,oBAAoB,IAAC,SAAS,EAAC,mDAAmD,GAAG,CACvF,EAGD,kBACE,OAAO,EAAE,GAAG,EAAE,CAAC,aAAa,CAAC,CAAC,UAAU,CAAC,EACzC,SAAS,EAAE,EAAE,CACX,2EAA2E,EAC3E,eAAe,CAChB,aAEA,UAAU,CAAC,CAAC,CAAC,CACZ,KAAC,eAAe,IAAC,SAAS,EAAC,SAAS,GAAG,CACxC,CAAC,CAAC,CAAC,CACF,KAAC,gBAAgB,IAAC,SAAS,EAAC,SAAS,GAAG,CACzC,EACD,yBAAO,QAAQ,GAAQ,IAChB,IACL,EAGL,UAAU,IAAI,CACb,cAAK,SAAS,EAAC,WAAW,YACxB,cAAK,SAAS,EAAC,4HAA4H,YACxI,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,GAC3B,GACF,CACP,IACG,CACP,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import {\n CircleArrowRightIcon,\n ChevronDownIcon,\n ChevronRightIcon,\n Loader2,\n} from 'lucide-react';\nimport {useState} from 'react';\nimport {cn} from '@sqlrooms/ui';\n\n/**\n * Props for the ToolCallInfoBox component\n */\ntype ToolCallInfoProps = {\n toolName: string;\n input: unknown;\n isCompleted: boolean;\n state:\n | 'input-streaming'\n | 'input-available'\n | 'output-available'\n | 'output-error';\n};\n\n/**\n * Component that renders a tool call is running\n * Shows the tool name and truncated arguments by default.\n * Click on the tool name to expand and see full arguments.\n *\n * @component\n * @param props - Component props\n * @param props.toolName - Name of the tool being called\n * @param props.input - Input arguments passed to the tool\n * @param props.isCompleted - Whether the tool call has completed\n * @param props.state - Current state of the tool call\n * @returns A React component displaying the tool call details\n */\nexport const ToolCallInfo: React.FC<ToolCallInfoProps> = ({\n toolName,\n input,\n isCompleted,\n state,\n}) => {\n const [isExpanded, setIsExpanded] = useState(false);\n\n return (\n <div className=\"flex flex-col gap-1\">\n <div className=\"flex items-center gap-2 pl-2 text-xs text-gray-700 dark:text-gray-300\">\n {/* Loading/Completed Indicator */}\n {state !== 'output-available' && state !== 'output-error' ? (\n <Loader2 className=\"h-4 w-4 shrink-0 animate-spin text-gray-400 dark:text-gray-500\" />\n ) : (\n <CircleArrowRightIcon className=\"h-4 w-4 shrink-0 text-gray-400 dark:text-gray-500\" />\n )}\n\n {/* Clickable Tool Name */}\n <button\n onClick={() => setIsExpanded(!isExpanded)}\n className={cn(\n 'flex items-center gap-1 rounded px-1 py-0.5 font-medium transition-colors',\n 'text-gray-700',\n )}\n >\n {isExpanded ? (\n <ChevronDownIcon className=\"h-3 w-3\" />\n ) : (\n <ChevronRightIcon className=\"h-3 w-3\" />\n )}\n <span>{toolName}</span>\n </button>\n </div>\n\n {/* Expanded Arguments */}\n {isExpanded && (\n <div className=\"px-5 py-2\">\n <pre className=\"text-muted-foreground bg-muted m-0 max-h-24 overflow-auto whitespace-pre-wrap break-words rounded-md p-2 font-mono text-xs\">\n {JSON.stringify(input, null, 2)}\n </pre>\n </div>\n )}\n </div>\n );\n};\n"]}
1
+ {"version":3,"file":"ToolCallInfo.js","sourceRoot":"","sources":["../../src/components/ToolCallInfo.tsx"],"names":[],"mappings":";AAAA,OAAO,EACL,oBAAoB,EACpB,eAAe,EACf,gBAAgB,EAChB,OAAO,GACR,MAAM,cAAc,CAAC;AACtB,OAAO,EAAC,QAAQ,EAAC,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAC,EAAE,EAAC,MAAM,cAAc,CAAC;AAgBhC;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,YAAY,GAAgC,CAAC,EACxD,QAAQ,EACR,KAAK,EACL,WAAW,EACX,KAAK,GACN,EAAE,EAAE;IACH,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAEpD,OAAO,CACL,eAAK,SAAS,EAAC,qBAAqB,aAClC,eAAK,SAAS,EAAC,uEAAuE,aAEnF,KAAK,KAAK,kBAAkB,IAAI,KAAK,KAAK,cAAc,CAAC,CAAC,CAAC,CAC1D,KAAC,OAAO,IAAC,SAAS,EAAC,gEAAgE,GAAG,CACvF,CAAC,CAAC,CAAC,CACF,KAAC,oBAAoB,IAAC,SAAS,EAAC,mDAAmD,GAAG,CACvF,EAGD,kBACE,OAAO,EAAE,GAAG,EAAE,CAAC,aAAa,CAAC,CAAC,UAAU,CAAC,EACzC,SAAS,EAAE,EAAE,CACX,2EAA2E,EAC3E,eAAe,CAChB,aAEA,UAAU,CAAC,CAAC,CAAC,CACZ,KAAC,eAAe,IAAC,SAAS,EAAC,SAAS,GAAG,CACxC,CAAC,CAAC,CAAC,CACF,KAAC,gBAAgB,IAAC,SAAS,EAAC,SAAS,GAAG,CACzC,EACD,yBAAO,QAAQ,GAAQ,IAChB,IACL,EAGL,UAAU,IAAI,CACb,cAAK,SAAS,EAAC,WAAW,YACxB,cAAK,SAAS,EAAC,gIAAgI,YAC5I,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,GAC3B,GACF,CACP,IACG,CACP,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import {\n CircleArrowRightIcon,\n ChevronDownIcon,\n ChevronRightIcon,\n Loader2,\n} from 'lucide-react';\nimport {useState} from 'react';\nimport {cn} from '@sqlrooms/ui';\n\n/**\n * Props for the ToolCallInfoBox component\n */\ntype ToolCallInfoProps = {\n toolName: string;\n input: unknown;\n isCompleted: boolean;\n state:\n | 'input-streaming'\n | 'input-available'\n | 'output-available'\n | 'output-error';\n};\n\n/**\n * Component that renders a tool call is running\n * Shows the tool name and truncated arguments by default.\n * Click on the tool name to expand and see full arguments.\n *\n * @component\n * @param props - Component props\n * @param props.toolName - Name of the tool being called\n * @param props.input - Input arguments passed to the tool\n * @param props.isCompleted - Whether the tool call has completed\n * @param props.state - Current state of the tool call\n * @returns A React component displaying the tool call details\n */\nexport const ToolCallInfo: React.FC<ToolCallInfoProps> = ({\n toolName,\n input,\n isCompleted,\n state,\n}) => {\n const [isExpanded, setIsExpanded] = useState(false);\n\n return (\n <div className=\"flex flex-col gap-1\">\n <div className=\"flex items-center gap-2 pl-2 text-xs text-gray-700 dark:text-gray-300\">\n {/* Loading/Completed Indicator */}\n {state !== 'output-available' && state !== 'output-error' ? (\n <Loader2 className=\"h-4 w-4 shrink-0 animate-spin text-gray-400 dark:text-gray-500\" />\n ) : (\n <CircleArrowRightIcon className=\"h-4 w-4 shrink-0 text-gray-400 dark:text-gray-500\" />\n )}\n\n {/* Clickable Tool Name */}\n <button\n onClick={() => setIsExpanded(!isExpanded)}\n className={cn(\n 'flex items-center gap-1 rounded px-1 py-0.5 font-medium transition-colors',\n 'text-gray-700',\n )}\n >\n {isExpanded ? (\n <ChevronDownIcon className=\"h-3 w-3\" />\n ) : (\n <ChevronRightIcon className=\"h-3 w-3\" />\n )}\n <span>{toolName}</span>\n </button>\n </div>\n\n {/* Expanded Arguments */}\n {isExpanded && (\n <div className=\"px-5 py-2\">\n <pre className=\"text-muted-foreground bg-muted m-0 max-h-24 overflow-auto rounded-md p-2 font-mono text-xs wrap-break-word whitespace-pre-wrap\">\n {JSON.stringify(input, null, 2)}\n </pre>\n </div>\n )}\n </div>\n );\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"ToolErrorMessage.d.ts","sourceRoot":"","sources":["../../../src/components/tools/ToolErrorMessage.tsx"],"names":[],"mappings":"AA6EA,MAAM,WAAW,qBAAqB;IACpC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;IACnC,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,KAAK,EACL,OAAO,EACP,KAAyB,EACzB,YAAsC,EACtC,KAAe,EACf,cAAoB,GACrB,EAAE,qBAAqB,2CAiCvB"}
1
+ {"version":3,"file":"ToolErrorMessage.d.ts","sourceRoot":"","sources":["../../../src/components/tools/ToolErrorMessage.tsx"],"names":[],"mappings":"AAmFA,MAAM,WAAW,qBAAqB;IACpC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;IACnC,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,KAAK,EACL,OAAO,EACP,KAAyB,EACzB,YAAsC,EACtC,KAAe,EACf,cAAoB,GACrB,EAAE,qBAAqB,2CAiCvB"}
@@ -3,15 +3,16 @@ import { JsonMonacoEditor } from '@sqlrooms/monaco-editor';
3
3
  import { Button, Popover, PopoverContent, PopoverTrigger, Tabs, TabsContent, TabsList, TabsTrigger, useDisclosure, } from '@sqlrooms/ui';
4
4
  import { TriangleAlertIcon } from 'lucide-react';
5
5
  import { memo, useMemo } from 'react';
6
- const ToolErrorMessageContent = memo(({ title, errorText, details, editorHeightPx }) => {
6
+ const ToolErrorMessageContent = memo(({ title, errorText, details, editorHeightPx, }) => {
7
7
  const hasErrorText = errorText.length > 0;
8
8
  const hasDetails = details != null;
9
9
  const defaultTab = hasErrorText ? 'error' : 'details';
10
- return (_jsxs(Tabs, { defaultValue: defaultTab, children: [_jsxs(TabsList, { className: "mb-2 h-8 gap-1", children: [hasErrorText && (_jsx(TabsTrigger, { value: "error", className: "h-6 px-2 text-xs", children: title })), hasDetails && (_jsx(TabsTrigger, { value: "details", className: "h-6 px-2 text-xs", children: "Details" }))] }), _jsx(TabsContent, { value: "error", className: "mt-0", children: _jsx("div", { className: "max-h-[300px] overflow-auto whitespace-pre-wrap font-mono text-xs", children: errorText }) }), _jsx(TabsContent, { value: "details", className: "mt-0", children: _jsx("div", { className: "w-full overflow-hidden rounded-md border", style: { height: editorHeightPx }, children: _jsx(JsonMonacoEditor, { className: "h-full", value: details, readOnly: true, options: {
10
+ return (_jsxs(Tabs, { defaultValue: defaultTab, children: [_jsxs(TabsList, { className: "mb-2 h-8 gap-1", children: [hasErrorText && (_jsx(TabsTrigger, { value: "error", className: "h-6 px-2 text-xs", children: title })), hasDetails && (_jsx(TabsTrigger, { value: "details", className: "h-6 px-2 text-xs", children: "Details" }))] }), _jsx(TabsContent, { value: "error", className: "mt-0", children: _jsx("div", { className: "max-h-[300px] overflow-auto font-mono text-xs whitespace-pre-wrap", children: errorText }) }), _jsx(TabsContent, { value: "details", className: "mt-0", children: _jsx("div", { className: "w-full overflow-hidden rounded-md border", style: { height: editorHeightPx }, children: _jsx(JsonMonacoEditor, { className: "h-full", value: details, readOnly: true, options: {
11
11
  lineNumbers: 'off',
12
12
  minimap: { enabled: false },
13
13
  scrollBeyondLastLine: false,
14
14
  wordWrap: 'on',
15
+ fixedOverflowWidgets: false,
15
16
  } }) }) })] }));
16
17
  });
17
18
  ToolErrorMessageContent.displayName = 'ToolErrorMessageContent';