@sqlrooms/ai-core 0.27.0 → 0.28.0-rc.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":"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":"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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-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":";AAAA,OAAO,EAAC,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAC,MAAM,cAAc,CAAC;AACnD,OAAO,EAAC,WAAW,EAAE,UAAU,EAAE,SAAS,EAAC,MAAM,cAAc,CAAC;AAChE,OAAO,EAAC,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAC,MAAM,OAAO,CAAC;AACrD,OAAO,EAAC,cAAc,EAAC,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAC,mBAAmB,EAAE,mBAAmB,EAAC,MAAM,WAAW,CAAC;AAEnE;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,eAAe,GAGvB,CAAC,EAAC,SAAS,EAAE,QAAQ,EAAC,EAAE,EAAE;IAC7B,MAAM,QAAQ,GAAG,cAAc,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC7D,MAAM,gBAAgB,GAAG,cAAc,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;IAC7E,MAAM,mBAAmB,GAAG,cAAc,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC;IACrE,MAAM,aAAa,GAAG,cAAc,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC;IAChE,MAAM,aAAa,GAAG,cAAc,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC;IAChE,MAAM,aAAa,GAAG,cAAc,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC;IAChE,MAAM,aAAa,GAAG,cAAc,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC;IAChE,MAAM,QAAQ,GAAG,cAAc,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;IACpE,MAAM,WAAW,GAAG,cAAc,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAC;IAEnE,MAAM,CAAC,eAAe,EAAE,kBAAkB,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAC;IAC5E,MAAM,CAAC,eAAe,EAAE,kBAAkB,CAAC,GAAG,QAAQ,CAG5C,IAAI,CAAC,CAAC;IAEhB,2CAA2C;IAC3C,MAAM,IAAI,GAAG,OAAO,CAClB,GAAG,EAAE,CACH,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACnB,EAAE,EAAE,CAAC,CAAC,EAAE;QACR,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,YAAY,EAAE,CAAC,CAAC,YAAY;KAC7B,CAAC,CAAC,EACL,CAAC,QAAQ,CAAC,CACX,CAAC;IAEF,MAAM,WAAW,GAAG,WAAW,CAC7B,CAAC,SAAiB,EAAE,EAAE;QACpB,wCAAwC;QACxC,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,MAAM,IAAI,CAAC;YAAE,OAAO;QAE9C,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,KAAK,SAAS,CAAC,CAAC;QAC5D,WAAW,CAAC,SAAS,CAAC,CAAC;QAEvB,6DAA6D;QAC7D,IAAI,SAAS,KAAK,gBAAgB,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC3D,aAAa,CAAC,SAAS,CAAC,CAAC,CAAE,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC,EACD,CAAC,QAAQ,EAAE,gBAAgB,EAAE,aAAa,EAAE,WAAW,CAAC,CACzD,CAAC;IAEF,MAAM,YAAY,GAAG,WAAW,CAC9B,CAAC,SAAiB,EAAE,EAAE;QACpB,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,SAAS,CAAC,CAAC;QACzD,iEAAiE;QACjE,IAAI,CAAC,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC;YACjC,aAAa,CAAC,SAAS,CAAC,CAAC;QAC3B,CAAC;aAAM,CAAC;YACN,kBAAkB,CAAC,SAAS,CAAC,CAAC;QAChC,CAAC;IACH,CAAC,EACD,CAAC,QAAQ,EAAE,aAAa,CAAC,CAC1B,CAAC;IAEF,MAAM,mBAAmB,GAAG,WAAW,CAAC,GAAG,EAAE;QAC3C,IAAI,eAAe,EAAE,CAAC;YACpB,aAAa,CAAC,eAAe,CAAC,CAAC;YAC/B,kBAAkB,CAAC,IAAI,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC,EAAE,CAAC,eAAe,EAAE,aAAa,CAAC,CAAC,CAAC;IAErC,MAAM,uBAAuB,GAAG,WAAW,CAAC,GAAG,EAAE;QAC/C,kBAAkB,CAAC,IAAI,CAAC,CAAC;IAC3B,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,mBAAmB,GAAG,WAAW,CACrC,CAAC,SAAiB,EAAE,EAAE;QACpB,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,SAAS,CAAC,CAAC;QACzD,IAAI,OAAO,EAAE,CAAC;YACZ,kBAAkB,CAAC,EAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAC,CAAC,CAAC;QAC1D,CAAC;IACH,CAAC,EACD,CAAC,QAAQ,CAAC,CACX,CAAC;IAEF,MAAM,kBAAkB,GAAG,WAAW,CACpC,CAAC,OAAe,EAAE,EAAE;QAClB,IAAI,eAAe,EAAE,CAAC;YACpB,aAAa,CAAC,eAAe,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QAC7C,CAAC;QACD,kBAAkB,CAAC,IAAI,CAAC,CAAC;IAC3B,CAAC,EACD,CAAC,eAAe,EAAE,aAAa,CAAC,CACjC,CAAC;IAEF,6DAA6D;IAC7D,MAAM,cAAc,GAAG,WAAW,CAChC,CAAC,GAA+B,EAAE,EAAE,CAAC,CACnC,eAAK,SAAS,EAAC,yBAAyB,aACrC,mBAAmB,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAC9B,KAAC,OAAO,IAAC,SAAS,EAAC,0DAA0D,GAAG,CACjF,EACD,eAAM,SAAS,EAAC,UAAU,YAAE,GAAG,CAAC,IAAI,GAAQ,IACxC,CACP,EACD,CAAC,mBAAmB,CAAC,CACtB,CAAC;IAEF,MAAM,aAAa,GAAG,WAAW,CAC/B,CAAC,GAA+B,EAAE,EAAE,CAAC,CACnC,8BACE,MAAC,QAAQ,CAAC,QAAQ,IAAC,OAAO,EAAE,GAAG,EAAE,CAAC,mBAAmB,CAAC,GAAG,CAAC,EAAE,CAAC,aAC3D,KAAC,UAAU,IAAC,SAAS,EAAC,cAAc,GAAG,cAErB,EACnB,QAAQ,CAAC,MAAM,GAAG,CAAC,IAAI,CACtB,8BACE,KAAC,QAAQ,CAAC,aAAa,KAAG,EAC1B,MAAC,QAAQ,CAAC,QAAQ,IAChB,OAAO,EAAC,aAAa,EACrB,OAAO,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,aAEnC,KAAC,SAAS,IAAC,SAAS,EAAC,cAAc,GAAG,cAEpB,IACnB,CACJ,IACA,CACJ,EACD,CAAC,mBAAmB,EAAE,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,CACrD,CAAC;IAEF,MAAM,uBAAuB,GAAG,WAAW,CACzC,CAAC,GAA+B,EAAE,EAAE,CAAC,CACnC,8BACE,KAAC,QAAQ,CAAC,gBAAgB,IACxB,IAAI,EAAE,KAAC,UAAU,IAAC,SAAS,EAAC,SAAS,GAAG,gBAC5B,UAAU,GAAG,CAAC,IAAI,EAAE,EAChC,OAAO,EAAE,GAAG,EAAE,CAAC,mBAAmB,CAAC,GAAG,CAAC,EAAE,CAAC,GAC1C,EACD,QAAQ,CAAC,MAAM,GAAG,CAAC,IAAI,CACtB,KAAC,QAAQ,CAAC,gBAAgB,IACxB,IAAI,EAAE,KAAC,SAAS,IAAC,SAAS,EAAC,SAAS,GAAG,gBAC3B,UAAU,GAAG,CAAC,IAAI,EAAE,EAChC,OAAO,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,GACnC,CACH,IACA,CACJ,EACD,CAAC,mBAAmB,EAAE,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,CACrD,CAAC;IAEF,OAAO,CACL,8BACE,eACE,SAAS,EAAE,EAAE,CACX,2EAA2E,EAC3E,SAAS,CACV,aAED,cAAK,SAAS,EAAC,wCAAwC,YACrD,MAAC,QAAQ,IACP,SAAS,EAAC,eAAe,EACzB,IAAI,EAAE,IAAI,EACV,mBAAmB,QACnB,QAAQ,EAAE,QAAQ,EAClB,aAAa,EAAE,gBAAgB,EAC/B,OAAO,EAAE,WAAW,EACpB,gBAAgB,EAAE,WAAW,EAC7B,QAAQ,EAAE,aAAa,EACvB,QAAQ,EAAE,GAAG,EAAE,CAAC,aAAa,EAAE,EAC/B,QAAQ,EAAE,aAAa,EACvB,cAAc,EAAE,cAAc,EAC9B,aAAa,EAAE,aAAa,EAC5B,uBAAuB,EAAE,uBAAuB,aAEhD,KAAC,QAAQ,CAAC,cAAc,IACtB,WAAW,EAAE,KAAC,WAAW,IAAC,SAAS,EAAC,SAAS,GAAG,EAChD,OAAO,EAAC,iBAAiB,EACzB,eAAe,EAAC,QAAQ,EACxB,kBAAkB,EAAE,CAAC,GAAG,EAAE,EAAE,CAC1B,GAAG,CAAC,YAAkC,GAExC,EACF,KAAC,QAAQ,CAAC,IAAI,IAAC,YAAY,EAAC,yCAAyC,GAAG,EACxE,KAAC,QAAQ,CAAC,SAAS,IAAC,OAAO,EAAC,aAAa,GAAG,IACnC,GACP,EAEL,QAAQ,IACL,EAEN,KAAC,mBAAmB,IAClB,MAAM,EAAE,eAAe,KAAK,IAAI,EAChC,OAAO,EAAE,uBAAuB,EAChC,QAAQ,EAAE,mBAAmB,GAC7B,EACF,KAAC,mBAAmB,IAClB,MAAM,EAAE,eAAe,KAAK,IAAI,EAChC,OAAO,EAAE,GAAG,EAAE,CAAC,kBAAkB,CAAC,IAAI,CAAC,EACvC,WAAW,EAAE,eAAe,EAAE,IAAI,IAAI,EAAE,EACxC,QAAQ,EAAE,kBAAkB,GAC5B,IACD,CACJ,CAAC;AACJ,CAAC,CAAC","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"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sqlrooms/ai-core",
3
- "version": "0.27.0",
3
+ "version": "0.28.0-rc.0",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "module": "dist/index.js",
@@ -23,11 +23,11 @@
23
23
  "@ai-sdk/react": "^2.0.44",
24
24
  "@openassistant/utils": "1.0.0-alpha.0",
25
25
  "@paralleldrive/cuid2": "^3.0.0",
26
- "@sqlrooms/ai-config": "0.27.0",
27
- "@sqlrooms/monaco-editor": "0.27.0",
28
- "@sqlrooms/room-store": "0.27.0",
29
- "@sqlrooms/ui": "0.27.0",
30
- "@sqlrooms/utils": "0.27.0",
26
+ "@sqlrooms/ai-config": "0.28.0-rc.0",
27
+ "@sqlrooms/monaco-editor": "0.28.0-rc.0",
28
+ "@sqlrooms/room-store": "0.28.0-rc.0",
29
+ "@sqlrooms/ui": "0.28.0-rc.0",
30
+ "@sqlrooms/utils": "0.28.0-rc.0",
31
31
  "ai": "^5.0.44",
32
32
  "immer": "^11.0.1",
33
33
  "lucide-react": "^0.556.0",
@@ -47,5 +47,5 @@
47
47
  "typecheck": "tsc --noEmit",
48
48
  "typedoc": "typedoc"
49
49
  },
50
- "gitHead": "f215995ab4adeac4c58171739261a15cbba9e82b"
50
+ "gitHead": "87a478edbff690e04c38cc717db8e11e844565c8"
51
51
  }