@sqlrooms/ai-core 0.26.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.
- package/LICENSE.md +9 -0
- package/README.md +488 -0
- package/dist/AiSlice.d.ts +52 -0
- package/dist/AiSlice.d.ts.map +1 -0
- package/dist/AiSlice.js +367 -0
- package/dist/AiSlice.js.map +1 -0
- package/dist/analysis.d.ts +51 -0
- package/dist/analysis.d.ts.map +1 -0
- package/dist/analysis.js +43 -0
- package/dist/analysis.js.map +1 -0
- package/dist/components/AnalysisAnswer.d.ts +15 -0
- package/dist/components/AnalysisAnswer.d.ts.map +1 -0
- package/dist/components/AnalysisAnswer.js +102 -0
- package/dist/components/AnalysisAnswer.js.map +1 -0
- package/dist/components/AnalysisResult.d.ts +22 -0
- package/dist/components/AnalysisResult.d.ts.map +1 -0
- package/dist/components/AnalysisResult.js +39 -0
- package/dist/components/AnalysisResult.js.map +1 -0
- package/dist/components/AnalysisResultsContainer.d.ts +5 -0
- package/dist/components/AnalysisResultsContainer.d.ts.map +1 -0
- package/dist/components/AnalysisResultsContainer.js +26 -0
- package/dist/components/AnalysisResultsContainer.js.map +1 -0
- package/dist/components/ErrorMessage.d.ts +4 -0
- package/dist/components/ErrorMessage.d.ts.map +1 -0
- package/dist/components/ErrorMessage.js +8 -0
- package/dist/components/ErrorMessage.js.map +1 -0
- package/dist/components/MessageContainer.d.ts +10 -0
- package/dist/components/MessageContainer.d.ts.map +1 -0
- package/dist/components/MessageContainer.js +9 -0
- package/dist/components/MessageContainer.js.map +1 -0
- package/dist/components/ModelSelector.d.ts +13 -0
- package/dist/components/ModelSelector.d.ts.map +1 -0
- package/dist/components/ModelSelector.js +34 -0
- package/dist/components/ModelSelector.js.map +1 -0
- package/dist/components/QueryControls.d.ts +10 -0
- package/dist/components/QueryControls.d.ts.map +1 -0
- package/dist/components/QueryControls.js +52 -0
- package/dist/components/QueryControls.js.map +1 -0
- package/dist/components/SessionControls.d.ts +17 -0
- package/dist/components/SessionControls.d.ts.map +1 -0
- package/dist/components/SessionControls.js +20 -0
- package/dist/components/SessionControls.js.map +1 -0
- package/dist/components/session/DeleteSessionButton.d.ts +19 -0
- package/dist/components/session/DeleteSessionButton.d.ts.map +1 -0
- package/dist/components/session/DeleteSessionButton.js +54 -0
- package/dist/components/session/DeleteSessionButton.js.map +1 -0
- package/dist/components/session/DeleteSessionDialog.d.ts +27 -0
- package/dist/components/session/DeleteSessionDialog.d.ts.map +1 -0
- package/dist/components/session/DeleteSessionDialog.js +19 -0
- package/dist/components/session/DeleteSessionDialog.js.map +1 -0
- package/dist/components/session/SessionActions.d.ts +18 -0
- package/dist/components/session/SessionActions.d.ts.map +1 -0
- package/dist/components/session/SessionActions.js +19 -0
- package/dist/components/session/SessionActions.js.map +1 -0
- package/dist/components/session/SessionDropdown.d.ts +18 -0
- package/dist/components/session/SessionDropdown.d.ts.map +1 -0
- package/dist/components/session/SessionDropdown.js +21 -0
- package/dist/components/session/SessionDropdown.js.map +1 -0
- package/dist/components/session/SessionTitle.d.ts +18 -0
- package/dist/components/session/SessionTitle.d.ts.map +1 -0
- package/dist/components/session/SessionTitle.js +22 -0
- package/dist/components/session/SessionTitle.js.map +1 -0
- package/dist/components/session/SessionType.d.ts +24 -0
- package/dist/components/session/SessionType.d.ts.map +1 -0
- package/dist/components/session/SessionType.js +2 -0
- package/dist/components/session/SessionType.js.map +1 -0
- package/dist/components/session/index.d.ts +7 -0
- package/dist/components/session/index.d.ts.map +1 -0
- package/dist/components/session/index.js +7 -0
- package/dist/components/session/index.js.map +1 -0
- package/dist/components/tools/ToolErrorMessage.d.ts +39 -0
- package/dist/components/tools/ToolErrorMessage.d.ts.map +1 -0
- package/dist/components/tools/ToolErrorMessage.js +20 -0
- package/dist/components/tools/ToolErrorMessage.js.map +1 -0
- package/dist/components/tools/ToolResult.d.ts +11 -0
- package/dist/components/tools/ToolResult.d.ts.map +1 -0
- package/dist/components/tools/ToolResult.js +29 -0
- package/dist/components/tools/ToolResult.js.map +1 -0
- package/dist/components/tools/ToolResultErrorBoundary.d.ts +19 -0
- package/dist/components/tools/ToolResultErrorBoundary.d.ts.map +1 -0
- package/dist/components/tools/ToolResultErrorBoundary.js +24 -0
- package/dist/components/tools/ToolResultErrorBoundary.js.map +1 -0
- package/dist/hasAiSettingsConfig.d.ts +13 -0
- package/dist/hasAiSettingsConfig.d.ts.map +1 -0
- package/dist/hasAiSettingsConfig.js +16 -0
- package/dist/hasAiSettingsConfig.js.map +1 -0
- package/dist/hooks/useScrollToBottom.d.ts +82 -0
- package/dist/hooks/useScrollToBottom.d.ts.map +1 -0
- package/dist/hooks/useScrollToBottom.js +142 -0
- package/dist/hooks/useScrollToBottom.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/utils.d.ts +15 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +31 -0
- package/dist/utils.js.map +1 -0
- package/package.json +51 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React, { useState, useCallback, useMemo } from 'react';
|
|
3
|
+
import Markdown from 'react-markdown';
|
|
4
|
+
import remarkGfm from 'remark-gfm';
|
|
5
|
+
import rehypeRaw from 'rehype-raw';
|
|
6
|
+
import { truncate } from '@sqlrooms/utils';
|
|
7
|
+
import { MessageContainer } from './MessageContainer';
|
|
8
|
+
import { BrainIcon } from 'lucide-react';
|
|
9
|
+
import { cn } from '@sqlrooms/ui';
|
|
10
|
+
// Constants moved outside component to prevent recreation
|
|
11
|
+
const THINK_WORD_LIMIT = 10;
|
|
12
|
+
const COMPLETE_THINK_REGEX = /<think>([\s\S]*?)<\/think>/g;
|
|
13
|
+
const INCOMPLETE_THINK_REGEX = /<think>([\s\S]*)$/;
|
|
14
|
+
/**
|
|
15
|
+
* Processes content and extracts think content in one pass
|
|
16
|
+
*/
|
|
17
|
+
const processContent = (originalContent) => {
|
|
18
|
+
const thinkContents = [];
|
|
19
|
+
let processedContent = originalContent;
|
|
20
|
+
let index = 0;
|
|
21
|
+
// Replace complete think tags
|
|
22
|
+
processedContent = processedContent.replace(COMPLETE_THINK_REGEX, (match, content) => {
|
|
23
|
+
if (content) {
|
|
24
|
+
thinkContents.push({
|
|
25
|
+
content: content.trim(),
|
|
26
|
+
isComplete: true,
|
|
27
|
+
index: index++,
|
|
28
|
+
});
|
|
29
|
+
return `\n\n<think-block data-index="${index - 1}"></think-block>\n\n`;
|
|
30
|
+
}
|
|
31
|
+
return match;
|
|
32
|
+
});
|
|
33
|
+
// Replace incomplete think tags (no closing tag)
|
|
34
|
+
processedContent = processedContent.replace(INCOMPLETE_THINK_REGEX, (match, content) => {
|
|
35
|
+
if (content) {
|
|
36
|
+
thinkContents.push({
|
|
37
|
+
content: content.trim(),
|
|
38
|
+
isComplete: false,
|
|
39
|
+
index: index++,
|
|
40
|
+
});
|
|
41
|
+
return `\n\n<think-block data-index="${index - 1}"></think-block>\n\n`;
|
|
42
|
+
}
|
|
43
|
+
return match;
|
|
44
|
+
});
|
|
45
|
+
return { processedContent, thinkContents };
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* ThinkBlock component for rendering individual think blocks
|
|
49
|
+
*/
|
|
50
|
+
const ThinkBlock = React.memo(({ thinkContent, isExpanded, onToggleExpansion, className }) => {
|
|
51
|
+
const { content, isComplete, index } = thinkContent;
|
|
52
|
+
const displayText = isComplete && !isExpanded ? truncate(content, THINK_WORD_LIMIT) : content;
|
|
53
|
+
const needsTruncation = isComplete && content.split(' ').length > THINK_WORD_LIMIT;
|
|
54
|
+
return (_jsxs("span", { className: cn('inline-block rounded-lg px-3 py-2 text-xs font-normal text-gray-100 dark:text-gray-400', isExpanded && 'bg-gray-50 dark:bg-gray-800/50', className), children: [_jsx("span", { className: "inline-flex items-start gap-2", children: _jsxs("span", { className: "text-gray-400", children: [_jsx(BrainIcon, { className: "mb-1 inline-block opacity-60 grayscale", size: 12 }), ' ', displayText] }) }), ' ', needsTruncation && (_jsx("button", { onClick: () => onToggleExpansion(content), className: "text-xs text-gray-500 underline hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300", children: isExpanded ? 'Show less' : 'Show more thinking' }))] }, `think-${index}`));
|
|
55
|
+
});
|
|
56
|
+
ThinkBlock.displayName = 'ThinkBlock';
|
|
57
|
+
/**
|
|
58
|
+
* Renders an analysis answer with markdown content of the final streaming response.
|
|
59
|
+
* Supports streaming think content that may arrive in chunks (e.g., "<think>Hello" before "</think>").
|
|
60
|
+
*
|
|
61
|
+
* @param {AnalysisAnswerProps} props - The component props. See {@link AnalysisAnswerProps} for more details.
|
|
62
|
+
* @returns {JSX.Element} The rendered answer tool call
|
|
63
|
+
*/
|
|
64
|
+
export const AnalysisAnswer = React.memo(function AnalysisAnswer(props) {
|
|
65
|
+
const [expandedThink, setExpandedThink] = useState(new Set());
|
|
66
|
+
const toggleThinkExpansion = useCallback((content) => {
|
|
67
|
+
setExpandedThink((prev) => {
|
|
68
|
+
const newExpanded = new Set(prev);
|
|
69
|
+
if (newExpanded.has(content)) {
|
|
70
|
+
newExpanded.delete(content);
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
newExpanded.add(content);
|
|
74
|
+
}
|
|
75
|
+
return newExpanded;
|
|
76
|
+
});
|
|
77
|
+
}, []);
|
|
78
|
+
// Memoize content processing to avoid recalculation on every render
|
|
79
|
+
const { processedContent, thinkContents } = useMemo(() => processContent(props.content), [props.content]);
|
|
80
|
+
// Memoize the think-block component to prevent unnecessary re-renders
|
|
81
|
+
const thinkBlockComponent = useCallback((thinkBlock) => {
|
|
82
|
+
try {
|
|
83
|
+
const index = parseInt(thinkBlock.props?.['data-index'] || '0', 10);
|
|
84
|
+
const thinkContent = thinkContents[index];
|
|
85
|
+
if (!thinkContent) {
|
|
86
|
+
console.warn(`Think content not found for index: ${index}`);
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
const isExpanded = expandedThink.has(thinkContent.content);
|
|
90
|
+
return (_jsx(ThinkBlock, { thinkContent: thinkContent, isExpanded: isExpanded, onToggleExpansion: toggleThinkExpansion }));
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
console.error('Error rendering think block:', error);
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
}, [thinkContents, expandedThink, toggleThinkExpansion]);
|
|
97
|
+
return (_jsx("div", { className: "flex flex-col gap-5", children: _jsx(MessageContainer, { isSuccess: true, type: props.isAnswer ? 'answer' : 'thinking', content: props, children: _jsx("div", { className: "prose dark:prose-invert max-w-none text-sm", children: _jsx(Markdown, { remarkPlugins: [remarkGfm], rehypePlugins: [rehypeRaw], components: {
|
|
98
|
+
// @ts-expect-error - Custom HTML element not in react-markdown types
|
|
99
|
+
'think-block': thinkBlockComponent,
|
|
100
|
+
}, children: processedContent }) }) }) }));
|
|
101
|
+
});
|
|
102
|
+
//# sourceMappingURL=AnalysisAnswer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AnalysisAnswer.js","sourceRoot":"","sources":["../../src/components/AnalysisAnswer.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, {useState, useCallback, useMemo} from 'react';\nimport Markdown from 'react-markdown';\nimport remarkGfm from 'remark-gfm';\nimport rehypeRaw from 'rehype-raw';\nimport {truncate} from '@sqlrooms/utils';\nimport {MessageContainer} from './MessageContainer';\nimport {BrainIcon} from 'lucide-react';\nimport {cn} from '@sqlrooms/ui';\n\ntype AnalysisAnswerProps = {\n content: string;\n isAnswer: boolean;\n};\n\ntype ThinkContent = {\n content: string;\n isComplete: boolean;\n index: number;\n};\n\n// Constants moved outside component to prevent recreation\nconst THINK_WORD_LIMIT = 10;\nconst COMPLETE_THINK_REGEX = /<think>([\\s\\S]*?)<\\/think>/g;\nconst INCOMPLETE_THINK_REGEX = /<think>([\\s\\S]*)$/;\n\n/**\n * Processes content and extracts think content in one pass\n */\nconst processContent = (\n originalContent: string,\n): {\n processedContent: string;\n thinkContents: ThinkContent[];\n} => {\n const thinkContents: ThinkContent[] = [];\n let processedContent = originalContent;\n let index = 0;\n\n // Replace complete think tags\n processedContent = processedContent.replace(\n COMPLETE_THINK_REGEX,\n (match, content) => {\n if (content) {\n thinkContents.push({\n content: content.trim(),\n isComplete: true,\n index: index++,\n });\n return `\\n\\n<think-block data-index=\"${index - 1}\"></think-block>\\n\\n`;\n }\n return match;\n },\n );\n\n // Replace incomplete think tags (no closing tag)\n processedContent = processedContent.replace(\n INCOMPLETE_THINK_REGEX,\n (match, content) => {\n if (content) {\n thinkContents.push({\n content: content.trim(),\n isComplete: false,\n index: index++,\n });\n return `\\n\\n<think-block data-index=\"${index - 1}\"></think-block>\\n\\n`;\n }\n return match;\n },\n );\n\n return {processedContent, thinkContents};\n};\n\n/**\n * ThinkBlock component for rendering individual think blocks\n */\nconst ThinkBlock = React.memo<{\n className?: string;\n thinkContent: ThinkContent;\n isExpanded: boolean;\n onToggleExpansion: (content: string) => void;\n}>(({thinkContent, isExpanded, onToggleExpansion, className}) => {\n const {content, isComplete, index} = thinkContent;\n\n const displayText =\n isComplete && !isExpanded ? truncate(content, THINK_WORD_LIMIT) : content;\n const needsTruncation =\n isComplete && content.split(' ').length > THINK_WORD_LIMIT;\n\n return (\n <span\n key={`think-${index}`}\n className={cn(\n 'inline-block rounded-lg px-3 py-2 text-xs font-normal text-gray-100 dark:text-gray-400',\n isExpanded && 'bg-gray-50 dark:bg-gray-800/50',\n className,\n )}\n >\n <span className=\"inline-flex items-start gap-2\">\n <span className=\"text-gray-400\">\n <BrainIcon\n className=\"mb-1 inline-block opacity-60 grayscale\"\n size={12}\n />{' '}\n {displayText}\n </span>\n </span>{' '}\n {needsTruncation && (\n <button\n onClick={() => onToggleExpansion(content)}\n className=\"text-xs text-gray-500 underline hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300\"\n >\n {isExpanded ? 'Show less' : 'Show more thinking'}\n </button>\n )}\n </span>\n );\n});\n\nThinkBlock.displayName = 'ThinkBlock';\n\n/**\n * Renders an analysis answer with markdown content of the final streaming response.\n * Supports streaming think content that may arrive in chunks (e.g., \"<think>Hello\" before \"</think>\").\n *\n * @param {AnalysisAnswerProps} props - The component props. See {@link AnalysisAnswerProps} for more details.\n * @returns {JSX.Element} The rendered answer tool call\n */\nexport const AnalysisAnswer = React.memo(function AnalysisAnswer(\n props: AnalysisAnswerProps,\n) {\n const [expandedThink, setExpandedThink] = useState<Set<string>>(new Set());\n\n const toggleThinkExpansion = useCallback((content: string) => {\n setExpandedThink((prev) => {\n const newExpanded = new Set(prev);\n if (newExpanded.has(content)) {\n newExpanded.delete(content);\n } else {\n newExpanded.add(content);\n }\n return newExpanded;\n });\n }, []);\n\n // Memoize content processing to avoid recalculation on every render\n const {processedContent, thinkContents} = useMemo(\n () => processContent(props.content),\n [props.content],\n );\n\n // Memoize the think-block component to prevent unnecessary re-renders\n const thinkBlockComponent = useCallback(\n (thinkBlock: any) => {\n try {\n const index = parseInt(thinkBlock.props?.['data-index'] || '0', 10);\n const thinkContent = thinkContents[index];\n\n if (!thinkContent) {\n console.warn(`Think content not found for index: ${index}`);\n return null;\n }\n\n const isExpanded = expandedThink.has(thinkContent.content);\n\n return (\n <ThinkBlock\n thinkContent={thinkContent}\n isExpanded={isExpanded}\n onToggleExpansion={toggleThinkExpansion}\n />\n );\n } catch (error) {\n console.error('Error rendering think block:', error);\n return null;\n }\n },\n [thinkContents, expandedThink, toggleThinkExpansion],\n );\n\n return (\n <div className=\"flex flex-col gap-5\">\n <MessageContainer\n isSuccess={true}\n type={props.isAnswer ? 'answer' : 'thinking'}\n content={props}\n >\n <div className=\"prose dark:prose-invert max-w-none text-sm\">\n <Markdown\n remarkPlugins={[remarkGfm]}\n rehypePlugins={[rehypeRaw]}\n components={{\n // @ts-expect-error - Custom HTML element not in react-markdown types\n 'think-block': thinkBlockComponent,\n }}\n >\n {processedContent}\n </Markdown>\n </div>\n </MessageContainer>\n </div>\n );\n});\n"]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { AnalysisResultSchema } from '@sqlrooms/ai-config';
|
|
2
|
+
/**
|
|
3
|
+
* Props for the AnalysisResult component
|
|
4
|
+
* @property {AnalysisResultSchema} result - The result of the analysis containing prompt, tool calls, and analysis data
|
|
5
|
+
*/
|
|
6
|
+
type AnalysisResultProps = {
|
|
7
|
+
result: AnalysisResultSchema;
|
|
8
|
+
onDeleteAnalysisResult: (id: string) => void;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Component that displays the results of an AI analysis.
|
|
12
|
+
* Shows the original prompt, intermediate tool calls, final analysis text,
|
|
13
|
+
* and any tool results.
|
|
14
|
+
*
|
|
15
|
+
* @component
|
|
16
|
+
* @param props - Component props
|
|
17
|
+
* @param props.result - The analysis result data to display
|
|
18
|
+
* @returns A React component displaying the analysis results
|
|
19
|
+
*/
|
|
20
|
+
export declare const AnalysisResult: React.FC<AnalysisResultProps>;
|
|
21
|
+
export {};
|
|
22
|
+
//# sourceMappingURL=AnalysisResult.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AnalysisResult.d.ts","sourceRoot":"","sources":["../../src/components/AnalysisResult.tsx"],"names":[],"mappings":"AACA,OAAO,EAAC,oBAAoB,EAAC,MAAM,qBAAqB,CAAC;AAiBzD;;;GAGG;AACH,KAAK,mBAAmB,GAAG;IACzB,MAAM,EAAE,oBAAoB,CAAC;IAC7B,sBAAsB,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9C,CAAC;AAaF;;;;;;;;;GASG;AACH,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CA8FxD,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Button, CopyButton, Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from '@sqlrooms/ui';
|
|
3
|
+
import { SquareTerminalIcon, TrashIcon } from 'lucide-react';
|
|
4
|
+
import { useState } from 'react';
|
|
5
|
+
import { AnalysisAnswer } from './AnalysisAnswer';
|
|
6
|
+
import { ErrorMessage } from './ErrorMessage';
|
|
7
|
+
import { ToolResult } from './tools/ToolResult';
|
|
8
|
+
/**
|
|
9
|
+
* Stringify the result of the analysis, excluding toolCallMessages.
|
|
10
|
+
* Used to display raw result data in a code view.
|
|
11
|
+
*
|
|
12
|
+
* @param result - The complete analysis result
|
|
13
|
+
* @returns A JSON string representation of the result without toolCallMessages
|
|
14
|
+
*/
|
|
15
|
+
const stringifyResult = (result) => {
|
|
16
|
+
return JSON.stringify(result, null, 2);
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Component that displays the results of an AI analysis.
|
|
20
|
+
* Shows the original prompt, intermediate tool calls, final analysis text,
|
|
21
|
+
* and any tool results.
|
|
22
|
+
*
|
|
23
|
+
* @component
|
|
24
|
+
* @param props - Component props
|
|
25
|
+
* @param props.result - The analysis result data to display
|
|
26
|
+
* @returns A React component displaying the analysis results
|
|
27
|
+
*/
|
|
28
|
+
export const AnalysisResult = ({ result, onDeleteAnalysisResult, }) => {
|
|
29
|
+
// the toolResults are reasoning steps that the LLM took to achieve the final result
|
|
30
|
+
// by calling function tools to answer the prompt
|
|
31
|
+
const { id, prompt, errorMessage, streamMessage } = result;
|
|
32
|
+
const parts = streamMessage.parts;
|
|
33
|
+
const [showDeleteConfirmation, setShowDeleteConfirmation] = useState(false);
|
|
34
|
+
return (_jsxs("div", { className: "group flex w-full flex-col gap-2 pb-2 text-sm", children: [_jsx("div", { className: "mb-2 flex items-center gap-2 rounded-md text-gray-700 dark:text-gray-100", children: _jsxs("div", { className: "bg-muted flex w-full items-center gap-2 rounded-md border p-2 text-sm", children: [_jsx(SquareTerminalIcon, { className: "h-4 w-4" }), _jsx("div", { className: "flex-1", children: prompt }), _jsxs("div", { className: "flex gap-2 opacity-0 transition-opacity group-hover:opacity-100", children: [_jsx(CopyButton, { text: prompt, variant: "ghost", size: "icon", className: "h-6 w-6", ariaLabel: "Copy prompt" }), _jsx(Button, { variant: "ghost", size: "icon", className: "h-6 w-6", onClick: () => setShowDeleteConfirmation(true), children: _jsx(TrashIcon, { className: "h-4 w-4" }) }), _jsx(Dialog, { open: showDeleteConfirmation, onOpenChange: setShowDeleteConfirmation, children: _jsxs(DialogContent, { className: "sm:max-w-[425px]", children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: "Confirm Deletion" }), _jsx(DialogDescription, { children: "Are you sure you want to delete this analysis result? This action cannot be undone." })] }), _jsxs(DialogFooter, { children: [_jsx(Button, { variant: "outline", onClick: () => setShowDeleteConfirmation(false), children: "Cancel" }), _jsx(Button, { variant: "destructive", onClick: () => {
|
|
35
|
+
onDeleteAnalysisResult(id);
|
|
36
|
+
setShowDeleteConfirmation(false);
|
|
37
|
+
}, children: "Delete" })] })] }) })] })] }) }), parts?.map((part, index) => (_jsxs("div", { children: [part.type === 'text' && (_jsx(AnalysisAnswer, { content: part.text, isAnswer: index === (streamMessage.parts?.length || 0) - 1 })), part.type === 'tool-invocation' && (_jsx("div", { children: _jsx(ToolResult, { toolInvocation: part.toolInvocation, additionalData: part.additionalData, isCompleted: result.isCompleted }, part.toolInvocation.toolCallId) }))] }, index))), errorMessage && _jsx(ErrorMessage, { errorMessage: errorMessage.error })] }));
|
|
38
|
+
};
|
|
39
|
+
//# sourceMappingURL=AnalysisResult.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AnalysisResult.js","sourceRoot":"","sources":["../../src/components/AnalysisResult.tsx"],"names":[],"mappings":"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","sourcesContent":["import {StreamMessagePart} from '@openassistant/core';\nimport {AnalysisResultSchema} from '@sqlrooms/ai-config';\nimport {\n Button,\n CopyButton,\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@sqlrooms/ui';\nimport {SquareTerminalIcon, TrashIcon} from 'lucide-react';\nimport {useState} from 'react';\nimport {AnalysisAnswer} from './AnalysisAnswer';\nimport {ErrorMessage} from './ErrorMessage';\nimport {ToolResult} from './tools/ToolResult';\n\n/**\n * Props for the AnalysisResult component\n * @property {AnalysisResultSchema} result - The result of the analysis containing prompt, tool calls, and analysis data\n */\ntype AnalysisResultProps = {\n result: AnalysisResultSchema;\n onDeleteAnalysisResult: (id: string) => void;\n};\n\n/**\n * Stringify the result of the analysis, excluding toolCallMessages.\n * Used to display raw result data in a code view.\n *\n * @param result - The complete analysis result\n * @returns A JSON string representation of the result without toolCallMessages\n */\nconst stringifyResult = (result: AnalysisResultSchema) => {\n return JSON.stringify(result, null, 2);\n};\n\n/**\n * Component that displays the results of an AI analysis.\n * Shows the original prompt, intermediate tool calls, final analysis text,\n * and any tool results.\n *\n * @component\n * @param props - Component props\n * @param props.result - The analysis result data to display\n * @returns A React component displaying the analysis results\n */\nexport const AnalysisResult: React.FC<AnalysisResultProps> = ({\n result,\n onDeleteAnalysisResult,\n}) => {\n // the toolResults are reasoning steps that the LLM took to achieve the final result\n // by calling function tools to answer the prompt\n const {id, prompt, errorMessage, streamMessage} = result;\n const parts = streamMessage.parts as StreamMessagePart[];\n const [showDeleteConfirmation, setShowDeleteConfirmation] = useState(false);\n\n return (\n <div className=\"group flex w-full flex-col gap-2 pb-2 text-sm\">\n <div className=\"mb-2 flex items-center gap-2 rounded-md text-gray-700 dark:text-gray-100\">\n <div className=\"bg-muted flex w-full items-center gap-2 rounded-md border p-2 text-sm\">\n <SquareTerminalIcon className=\"h-4 w-4\" />\n {/** render prompt */}\n <div className=\"flex-1\">{prompt}</div>\n <div className=\"flex gap-2 opacity-0 transition-opacity group-hover:opacity-100\">\n <CopyButton\n text={prompt}\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-6 w-6\"\n ariaLabel=\"Copy prompt\"\n />\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-6 w-6\"\n onClick={() => setShowDeleteConfirmation(true)}\n >\n <TrashIcon className=\"h-4 w-4\" />\n </Button>\n\n {/* Delete Confirmation Dialog */}\n <Dialog\n open={showDeleteConfirmation}\n onOpenChange={setShowDeleteConfirmation}\n >\n <DialogContent className=\"sm:max-w-[425px]\">\n <DialogHeader>\n <DialogTitle>Confirm Deletion</DialogTitle>\n <DialogDescription>\n Are you sure you want to delete this analysis result? This\n action cannot be undone.\n </DialogDescription>\n </DialogHeader>\n <DialogFooter>\n <Button\n variant=\"outline\"\n onClick={() => setShowDeleteConfirmation(false)}\n >\n Cancel\n </Button>\n <Button\n variant=\"destructive\"\n onClick={() => {\n onDeleteAnalysisResult(id);\n setShowDeleteConfirmation(false);\n }}\n >\n Delete\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n </div>\n </div>\n </div>\n {/** render parts */}\n {parts?.map((part, index) => (\n <div key={index}>\n {part.type === 'text' && (\n <AnalysisAnswer\n content={part.text}\n isAnswer={index === (streamMessage.parts?.length || 0) - 1}\n />\n )}\n {part.type === 'tool-invocation' && (\n <div>\n <ToolResult\n key={part.toolInvocation.toolCallId}\n toolInvocation={part.toolInvocation}\n additionalData={part.additionalData}\n isCompleted={result.isCompleted}\n />\n </div>\n )}\n </div>\n ))}\n {/** render error message */}\n {errorMessage && <ErrorMessage errorMessage={errorMessage.error} />}\n </div>\n );\n};\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AnalysisResultsContainer.d.ts","sourceRoot":"","sources":["../../src/components/AnalysisResultsContainer.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAe,MAAM,OAAO,CAAC;AAKpC,eAAO,MAAM,wBAAwB,EAAE,KAAK,CAAC,EAAE,CAAC;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAoDA,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn, ScrollArea, ScrollBar, SkeletonPane } from '@sqlrooms/ui';
|
|
3
|
+
import { ChevronDown } from 'lucide-react';
|
|
4
|
+
import { useRef } from 'react';
|
|
5
|
+
import { useStoreWithAi } from '../AiSlice';
|
|
6
|
+
import { useScrollToBottom } from '../hooks/useScrollToBottom';
|
|
7
|
+
import { AnalysisResult } from './AnalysisResult';
|
|
8
|
+
export const AnalysisResultsContainer = ({ className }) => {
|
|
9
|
+
const isRunningAnalysis = useStoreWithAi((s) => s.ai.isRunningAnalysis);
|
|
10
|
+
const currentSession = useStoreWithAi((s) => s.ai.getCurrentSession());
|
|
11
|
+
const deleteAnalysisResult = useStoreWithAi((s) => s.ai.deleteAnalysisResult);
|
|
12
|
+
const containerRef = useRef(null);
|
|
13
|
+
const endRef = useRef(null);
|
|
14
|
+
const { showScrollButton, scrollToBottom } = useScrollToBottom({
|
|
15
|
+
containerRef,
|
|
16
|
+
endRef,
|
|
17
|
+
dataToObserve: currentSession?.analysisResults,
|
|
18
|
+
});
|
|
19
|
+
const onDeleteAnalysisResult = (id) => {
|
|
20
|
+
if (currentSession) {
|
|
21
|
+
deleteAnalysisResult(currentSession.id, id);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
return (_jsxs("div", { className: cn('relative flex h-full w-full flex-col', className), children: [_jsxs(ScrollArea, { ref: containerRef, className: "flex w-full flex-grow flex-col gap-5", children: [currentSession?.analysisResults.map((result) => (_jsx(AnalysisResult, { result: result, onDeleteAnalysisResult: onDeleteAnalysisResult }, result.id))), isRunningAnalysis && _jsx(SkeletonPane, { className: "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" }) }) })] }));
|
|
25
|
+
};
|
|
26
|
+
//# sourceMappingURL=AnalysisResultsContainer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AnalysisResultsContainer.js","sourceRoot":"","sources":["../../src/components/AnalysisResultsContainer.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAC,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAC,MAAM,cAAc,CAAC;AACrE,OAAO,EAAC,WAAW,EAAC,MAAM,cAAc,CAAC;AACzC,OAAc,EAAC,MAAM,EAAC,MAAM,OAAO,CAAC;AACpC,OAAO,EAAC,cAAc,EAAC,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAC,iBAAiB,EAAC,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAC;AAEhD,MAAM,CAAC,MAAM,wBAAwB,GAEhC,CAAC,EAAC,SAAS,EAAC,EAAE,EAAE;IACnB,MAAM,iBAAiB,GAAG,cAAc,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,iBAAiB,CAAC,CAAC;IACxE,MAAM,cAAc,GAAG,cAAc,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,iBAAiB,EAAE,CAAC,CAAC;IACvE,MAAM,oBAAoB,GAAG,cAAc,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,oBAAoB,CAAC,CAAC;IAE9E,MAAM,YAAY,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAC;IAClD,MAAM,MAAM,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAC;IAC5C,MAAM,EAAC,gBAAgB,EAAE,cAAc,EAAC,GAAG,iBAAiB,CAAC;QAC3D,YAAY;QACZ,MAAM;QACN,aAAa,EAAE,cAAc,EAAE,eAAe;KAC/C,CAAC,CAAC;IAEH,MAAM,sBAAsB,GAAG,CAAC,EAAU,EAAE,EAAE;QAC5C,IAAI,cAAc,EAAE,CAAC;YACnB,oBAAoB,CAAC,cAAc,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QAC9C,CAAC;IACH,CAAC,CAAC;IAEF,OAAO,CACL,eAAK,SAAS,EAAE,EAAE,CAAC,sCAAsC,EAAE,SAAS,CAAC,aACnE,MAAC,UAAU,IACT,GAAG,EAAE,YAAY,EACjB,SAAS,EAAC,sCAAsC,aAE/C,cAAc,EAAE,eAAe,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAC/C,KAAC,cAAc,IAEb,MAAM,EAAE,MAAM,EACd,sBAAsB,EAAE,sBAAsB,IAFzC,MAAM,CAAC,EAAE,CAGd,CACH,CAAC,EACD,iBAAiB,IAAI,KAAC,YAAY,IAAC,SAAS,EAAC,KAAK,GAAG,EACtD,cAAK,GAAG,EAAE,MAAM,EAAE,SAAS,EAAC,sBAAsB,GAAG,EACrD,KAAC,SAAS,IAAC,WAAW,EAAC,UAAU,GAAG,EACpC,KAAC,SAAS,IAAC,WAAW,EAAC,YAAY,GAAG,IAC3B,EACb,cAAK,SAAS,EAAC,qEAAqE,YAClF,iBACE,OAAO,EAAE,cAAc,EACvB,SAAS,EAAE,EAAE,CACX,iFAAiF,EACjF,qFAAqF,EACrF,gBAAgB,IAAI,2BAA2B,CAChD,gBACU,kBAAkB,YAE7B,KAAC,WAAW,IAAC,SAAS,EAAC,SAAS,GAAG,GAC5B,GACL,IACF,CACP,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import {cn, ScrollArea, ScrollBar, SkeletonPane} from '@sqlrooms/ui';\nimport {ChevronDown} from 'lucide-react';\nimport React, {useRef} from 'react';\nimport {useStoreWithAi} from '../AiSlice';\nimport {useScrollToBottom} from '../hooks/useScrollToBottom';\nimport {AnalysisResult} from './AnalysisResult';\n\nexport const AnalysisResultsContainer: React.FC<{\n className?: string;\n}> = ({className}) => {\n const isRunningAnalysis = useStoreWithAi((s) => s.ai.isRunningAnalysis);\n const currentSession = useStoreWithAi((s) => s.ai.getCurrentSession());\n const deleteAnalysisResult = useStoreWithAi((s) => s.ai.deleteAnalysisResult);\n\n const containerRef = useRef<HTMLDivElement>(null);\n const endRef = useRef<HTMLDivElement>(null);\n const {showScrollButton, scrollToBottom} = useScrollToBottom({\n containerRef,\n endRef,\n dataToObserve: currentSession?.analysisResults,\n });\n\n const onDeleteAnalysisResult = (id: string) => {\n if (currentSession) {\n deleteAnalysisResult(currentSession.id, id);\n }\n };\n\n return (\n <div className={cn('relative flex h-full w-full flex-col', className)}>\n <ScrollArea\n ref={containerRef}\n className=\"flex w-full flex-grow flex-col gap-5\"\n >\n {currentSession?.analysisResults.map((result) => (\n <AnalysisResult\n key={result.id}\n result={result}\n onDeleteAnalysisResult={onDeleteAnalysisResult}\n />\n ))}\n {isRunningAnalysis && <SkeletonPane className=\"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"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ErrorMessage.d.ts","sourceRoot":"","sources":["../../src/components/ErrorMessage.tsx"],"names":[],"mappings":"AAIA,wBAAgB,YAAY,CAAC,KAAK,EAAE;IAAC,YAAY,EAAE,MAAM,CAAA;CAAC,2CAQzD"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import Markdown from 'react-markdown';
|
|
3
|
+
import remarkGfm from 'remark-gfm';
|
|
4
|
+
import { MessageContainer } from './MessageContainer';
|
|
5
|
+
export function ErrorMessage(props) {
|
|
6
|
+
return (_jsx(MessageContainer, { isSuccess: false, type: "error", content: props, children: _jsx("div", { className: "prose dark:prose-invert max-w-none text-sm", children: _jsx(Markdown, { remarkPlugins: [remarkGfm], children: props.errorMessage }) }) }));
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=ErrorMessage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ErrorMessage.js","sourceRoot":"","sources":["../../src/components/ErrorMessage.tsx"],"names":[],"mappings":";AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AACtC,OAAO,SAAS,MAAM,YAAY,CAAC;AACnC,OAAO,EAAC,gBAAgB,EAAC,MAAM,oBAAoB,CAAC;AAEpD,MAAM,UAAU,YAAY,CAAC,KAA6B;IACxD,OAAO,CACL,KAAC,gBAAgB,IAAC,SAAS,EAAE,KAAK,EAAE,IAAI,EAAC,OAAO,EAAC,OAAO,EAAE,KAAK,YAC7D,cAAK,SAAS,EAAC,4CAA4C,YACzD,KAAC,QAAQ,IAAC,aAAa,EAAE,CAAC,SAAS,CAAC,YAAG,KAAK,CAAC,YAAY,GAAY,GACjE,GACW,CACpB,CAAC;AACJ,CAAC","sourcesContent":["import Markdown from 'react-markdown';\nimport remarkGfm from 'remark-gfm';\nimport {MessageContainer} from './MessageContainer';\n\nexport function ErrorMessage(props: {errorMessage: string}) {\n return (\n <MessageContainer isSuccess={false} type=\"error\" content={props}>\n <div className=\"prose dark:prose-invert max-w-none text-sm\">\n <Markdown remarkPlugins={[remarkGfm]}>{props.errorMessage}</Markdown>\n </div>\n </MessageContainer>\n );\n}\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
type MessageContainerProps = {
|
|
2
|
+
className?: string;
|
|
3
|
+
isSuccess: boolean;
|
|
4
|
+
type: string;
|
|
5
|
+
content: object;
|
|
6
|
+
children: React.ReactNode;
|
|
7
|
+
};
|
|
8
|
+
export declare const MessageContainer: React.FC<MessageContainerProps>;
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=MessageContainer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MessageContainer.d.ts","sourceRoot":"","sources":["../../src/components/MessageContainer.tsx"],"names":[],"mappings":"AAWA,KAAK,qBAAqB,GAAG;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;IAEnB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CAsC5D,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Badge, cn, } from '@sqlrooms/ui';
|
|
3
|
+
import { XCircleIcon } from 'lucide-react';
|
|
4
|
+
export const MessageContainer = ({ className, type,
|
|
5
|
+
// borderColor,
|
|
6
|
+
content, children, }) => {
|
|
7
|
+
return (_jsxs("div", { className: cn('group relative px-5 py-2 text-xs', className, type === 'error' && 'border-destructive rounded-md border py-4'), children: [type === 'error' && (_jsxs(Badge, { variant: "secondary", className: cn('absolute left-2 top-[-12px] flex items-center gap-1 border text-xs', 'border-destructive bg-background'), children: [_jsx(XCircleIcon, { className: "h-3 w-3 text-red-500" }), type] })), _jsx("div", { className: "flex flex-col gap-5", children: children })] }));
|
|
8
|
+
};
|
|
9
|
+
//# sourceMappingURL=MessageContainer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MessageContainer.js","sourceRoot":"","sources":["../../src/components/MessageContainer.tsx"],"names":[],"mappings":";AACA,OAAO,EACL,KAAK,EAEL,EAAE,GAIH,MAAM,cAAc,CAAC;AACtB,OAAO,EAAW,WAAW,EAAC,MAAM,cAAc,CAAC;AAWnD,MAAM,CAAC,MAAM,gBAAgB,GAAoC,CAAC,EAChE,SAAS,EACT,IAAI;AACJ,eAAe;AACf,OAAO,EACP,QAAQ,GACT,EAAE,EAAE;IACH,OAAO,CACL,eACE,SAAS,EAAE,EAAE,CACX,kCAAkC,EAClC,SAAS,EACT,IAAI,KAAK,OAAO,IAAI,2CAA2C,CAGhE,aAEA,IAAI,KAAK,OAAO,IAAI,CACnB,MAAC,KAAK,IACJ,OAAO,EAAC,WAAW,EACnB,SAAS,EAAE,EAAE,CACX,oEAAoE,EACpE,kCAAkC,CAEnC,aAKD,KAAC,WAAW,IAAC,SAAS,EAAC,sBAAsB,GAAG,EAE/C,IAAI,IACC,CACT,EAED,cAAK,SAAS,EAAC,qBAAqB,YAAE,QAAQ,GAAO,IACjD,CACP,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import {JsonMonacoEditor} from '@sqlrooms/monaco-editor';\nimport {\n Badge,\n Button,\n cn,\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from '@sqlrooms/ui';\nimport {CodeIcon, XCircleIcon} from 'lucide-react';\n\ntype MessageContainerProps = {\n className?: string;\n isSuccess: boolean;\n // borderColor: string;\n type: string;\n content: object;\n children: React.ReactNode;\n};\n\nexport const MessageContainer: React.FC<MessageContainerProps> = ({\n className,\n type,\n // borderColor,\n content,\n children,\n}) => {\n return (\n <div\n className={cn(\n 'group relative px-5 py-2 text-xs',\n className,\n type === 'error' && 'border-destructive rounded-md border py-4',\n // borderColor,\n // isSuccess ? borderColor : 'border-red-500',\n )}\n >\n {type === 'error' && (\n <Badge\n variant=\"secondary\"\n className={cn(\n 'absolute left-2 top-[-12px] flex items-center gap-1 border text-xs',\n 'border-destructive bg-background',\n // isSuccess ? borderColor : 'border-red-500',\n )}\n >\n {/* {isSuccess ? ( */}\n {/* <CheckCircle2Icon className=\"h-3 w-3 text-green-500\" /> */}\n {/* ) : ( */}\n <XCircleIcon className=\"h-3 w-3 text-red-500\" />\n {/* )} */}\n {type}\n </Badge>\n )}\n\n <div className=\"flex flex-col gap-5\">{children}</div>\n </div>\n );\n};\n"]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
interface Model {
|
|
3
|
+
provider: string;
|
|
4
|
+
label: string;
|
|
5
|
+
value: string;
|
|
6
|
+
}
|
|
7
|
+
interface ModelSelectorProps {
|
|
8
|
+
className?: string;
|
|
9
|
+
models?: Model[];
|
|
10
|
+
}
|
|
11
|
+
export declare const ModelSelector: React.FC<ModelSelectorProps>;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=ModelSelector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ModelSelector.d.ts","sourceRoot":"","sources":["../../src/components/ModelSelector.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAgB,MAAM,OAAO,CAAC;AAgBrC,UAAU,KAAK;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED,UAAU,kBAAkB;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC;CAClB;AAED,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAuEtD,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React, { useMemo } from 'react';
|
|
3
|
+
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, SelectValue, } from '@sqlrooms/ui';
|
|
4
|
+
import { useStoreWithAi } from '../AiSlice';
|
|
5
|
+
import { capitalize } from '@sqlrooms/utils';
|
|
6
|
+
import { hasAiSettingsConfig } from '../hasAiSettingsConfig';
|
|
7
|
+
import { extractModelsFromSettings } from '../utils';
|
|
8
|
+
export const ModelSelector = ({ className, models: passedModels, }) => {
|
|
9
|
+
const currentSession = useStoreWithAi((s) => s.ai.getCurrentSession());
|
|
10
|
+
const setAiModel = useStoreWithAi((s) => s.ai.setAiModel);
|
|
11
|
+
const aiSettingsConfig = useStoreWithAi((s) => hasAiSettingsConfig(s) ? s.aiSettings.config : undefined);
|
|
12
|
+
const settingsModels = useMemo(() => (aiSettingsConfig ? extractModelsFromSettings(aiSettingsConfig) : []), [aiSettingsConfig]);
|
|
13
|
+
const models = passedModels ?? settingsModels;
|
|
14
|
+
const handleModelChange = (value) => {
|
|
15
|
+
const selectedModel = models.find((model) => model.value === value);
|
|
16
|
+
if (selectedModel) {
|
|
17
|
+
setAiModel(selectedModel.provider, value);
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
if (!currentSession)
|
|
21
|
+
return null;
|
|
22
|
+
const currentModel = currentSession.model;
|
|
23
|
+
const currentModelDetails = models.find((m) => m.value === currentModel);
|
|
24
|
+
// Group models by provider
|
|
25
|
+
const modelsByProvider = models.reduce((acc, model) => {
|
|
26
|
+
if (!acc[model.provider]) {
|
|
27
|
+
acc[model.provider] = [];
|
|
28
|
+
}
|
|
29
|
+
acc[model.provider].push(model);
|
|
30
|
+
return acc;
|
|
31
|
+
}, {});
|
|
32
|
+
return (_jsx("div", { className: className, children: _jsxs(Select, { value: currentModel, onValueChange: handleModelChange, children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, { placeholder: "Select AI Model", children: currentModelDetails?.label ?? '' }) }), _jsx(SelectContent, { children: Object.entries(modelsByProvider).map(([provider, providerModels]) => (_jsxs(React.Fragment, { children: [_jsxs(SelectGroup, { children: [_jsx(SelectLabel, { className: "text-muted-foreground/50 text-center text-sm font-bold", children: capitalize(provider) }), providerModels.map((model) => (_jsx(SelectItem, { value: model.value, children: model.label }, model.value)))] }), _jsx(SelectSeparator, {})] }, provider))) })] }) }));
|
|
33
|
+
};
|
|
34
|
+
//# sourceMappingURL=ModelSelector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ModelSelector.js","sourceRoot":"","sources":["../../src/components/ModelSelector.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, {useMemo} from 'react';\nimport {\n Select,\n SelectContent,\n SelectGroup,\n SelectItem,\n SelectLabel,\n SelectSeparator,\n SelectTrigger,\n SelectValue,\n} from '@sqlrooms/ui';\nimport {useStoreWithAi} from '../AiSlice';\nimport {capitalize} from '@sqlrooms/utils';\nimport {hasAiSettingsConfig} from '../hasAiSettingsConfig';\nimport {extractModelsFromSettings} from '../utils';\n\ninterface Model {\n provider: string;\n label: string;\n value: string;\n}\n\ninterface ModelSelectorProps {\n className?: string;\n models?: Model[];\n}\n\nexport const ModelSelector: React.FC<ModelSelectorProps> = ({\n className,\n models: passedModels,\n}) => {\n const currentSession = useStoreWithAi((s) => s.ai.getCurrentSession());\n const setAiModel = useStoreWithAi((s) => s.ai.setAiModel);\n\n const aiSettingsConfig = useStoreWithAi((s) =>\n hasAiSettingsConfig(s) ? s.aiSettings.config : undefined,\n );\n const settingsModels = useMemo(\n () => (aiSettingsConfig ? extractModelsFromSettings(aiSettingsConfig) : []),\n [aiSettingsConfig],\n );\n\n const models = passedModels ?? settingsModels;\n\n const handleModelChange = (value: string) => {\n const selectedModel = models.find((model) => model.value === value);\n if (selectedModel) {\n setAiModel(selectedModel.provider, value);\n }\n };\n\n if (!currentSession) return null;\n\n const currentModel = currentSession.model;\n const currentModelDetails = models.find((m) => m.value === currentModel);\n\n // Group models by provider\n const modelsByProvider = models.reduce(\n (acc, model) => {\n if (!acc[model.provider]) {\n acc[model.provider] = [];\n }\n acc[model.provider]!.push(model);\n return acc;\n },\n {} as Record<string, Model[]>,\n );\n\n return (\n <div className={className}>\n <Select value={currentModel} onValueChange={handleModelChange}>\n <SelectTrigger className=\"w-full\">\n <SelectValue placeholder=\"Select AI Model\">\n {currentModelDetails?.label ?? ''}\n </SelectValue>\n </SelectTrigger>\n <SelectContent>\n {Object.entries(modelsByProvider).map(\n ([provider, providerModels]) => (\n <React.Fragment key={provider}>\n <SelectGroup>\n <SelectLabel className=\"text-muted-foreground/50 text-center text-sm font-bold\">\n {capitalize(provider)}\n </SelectLabel>\n {providerModels.map((model) => (\n <SelectItem key={model.value} value={model.value}>\n {model.label}\n </SelectItem>\n ))}\n </SelectGroup>\n <SelectSeparator />\n </React.Fragment>\n ),\n )}\n </SelectContent>\n </Select>\n </div>\n );\n};\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { PropsWithChildren } from 'react';
|
|
2
|
+
type QueryControlsProps = PropsWithChildren<{
|
|
3
|
+
className?: string;
|
|
4
|
+
placeholder?: string;
|
|
5
|
+
onRun?: () => void;
|
|
6
|
+
onCancel?: () => void;
|
|
7
|
+
}>;
|
|
8
|
+
export declare const QueryControls: React.FC<QueryControlsProps>;
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=QueryControls.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"QueryControls.d.ts","sourceRoot":"","sources":["../../src/components/QueryControls.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAC,iBAAiB,EAAiC,MAAM,OAAO,CAAC;AAGxE,KAAK,kBAAkB,GAAG,iBAAiB,CAAC;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,IAAI,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;CACvB,CAAC,CAAC;AAEH,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAwGtD,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Button, cn, Textarea } from '@sqlrooms/ui';
|
|
3
|
+
import { ArrowUpIcon, OctagonXIcon } from 'lucide-react';
|
|
4
|
+
import { useCallback, useRef, useEffect } from 'react';
|
|
5
|
+
import { useStoreWithAi } from '../AiSlice';
|
|
6
|
+
export const QueryControls = ({ className, placeholder = 'What would you like to learn about the data?', children, onRun, onCancel, }) => {
|
|
7
|
+
const textareaRef = useRef(null);
|
|
8
|
+
const isRunningAnalysis = useStoreWithAi((s) => s.ai.isRunningAnalysis);
|
|
9
|
+
const runAnalysis = useStoreWithAi((s) => s.ai.startAnalysis);
|
|
10
|
+
const cancelAnalysis = useStoreWithAi((s) => s.ai.cancelAnalysis);
|
|
11
|
+
const analysisPrompt = useStoreWithAi((s) => s.ai.analysisPrompt);
|
|
12
|
+
const setAnalysisPrompt = useStoreWithAi((s) => s.ai.setAnalysisPrompt);
|
|
13
|
+
const currentSession = useStoreWithAi((s) => s.ai.getCurrentSession());
|
|
14
|
+
const model = currentSession?.model;
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
// Focus the textarea when the component mounts
|
|
17
|
+
// Using a small timeout ensures the data is loaded and
|
|
18
|
+
// add timeout to prevent aria hidden warning caused by the
|
|
19
|
+
// loading progress dialog being still open
|
|
20
|
+
const timer = setTimeout(() => {
|
|
21
|
+
if (textareaRef.current) {
|
|
22
|
+
textareaRef.current.focus();
|
|
23
|
+
}
|
|
24
|
+
}, 500);
|
|
25
|
+
return () => clearTimeout(timer);
|
|
26
|
+
}, []);
|
|
27
|
+
const handleKeyDown = useCallback((e) => {
|
|
28
|
+
if (e.key === 'Enter' &&
|
|
29
|
+
!e.shiftKey &&
|
|
30
|
+
!e.ctrlKey &&
|
|
31
|
+
!e.altKey &&
|
|
32
|
+
!e.metaKey) {
|
|
33
|
+
e.preventDefault();
|
|
34
|
+
if (!isRunningAnalysis && model && analysisPrompt.trim().length) {
|
|
35
|
+
runAnalysis();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}, [isRunningAnalysis, model, analysisPrompt, runAnalysis]);
|
|
39
|
+
const canStart = Boolean(model && analysisPrompt.trim().length);
|
|
40
|
+
const handleClickRunOrCancel = useCallback(() => {
|
|
41
|
+
if (isRunningAnalysis) {
|
|
42
|
+
cancelAnalysis();
|
|
43
|
+
onCancel?.();
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
runAnalysis();
|
|
47
|
+
onRun?.();
|
|
48
|
+
}
|
|
49
|
+
}, [isRunningAnalysis, cancelAnalysis, runAnalysis]);
|
|
50
|
+
return (_jsx("div", { className: cn('flex w-full flex-col items-center justify-center gap-4', 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, disabled: isRunningAnalysis, className: "min-h-[30px] resize-none border-none p-2 text-sm outline-none focus-visible:ring-0", autoResize: true, value: analysisPrompt, onChange: (e) => setAnalysisPrompt(e.target.value), onKeyDown: handleKeyDown, placeholder: placeholder, autoFocus: true }), _jsx("div", { className: "align-stretch flex w-full items-center gap-2 overflow-hidden", children: _jsxs("div", { className: "flex h-full w-full min-w-0 items-center gap-2 overflow-hidden", children: [_jsx("div", { className: "min-w-0 flex-1 overflow-hidden pl-2", children: _jsx("div", { className: "flex flex-nowrap items-center gap-2 overflow-x-auto py-1", children: children }) }), _jsx("div", { className: "ml-auto shrink-0 pr-2", children: _jsx(Button, { className: "h-8 w-8 rounded-full", variant: "default", size: "icon", onClick: handleClickRunOrCancel, disabled: !canStart, children: isRunningAnalysis ? _jsx(OctagonXIcon, {}) : _jsx(ArrowUpIcon, {}) }) })] }) })] }) }) }));
|
|
51
|
+
};
|
|
52
|
+
//# sourceMappingURL=QueryControls.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"QueryControls.js","sourceRoot":"","sources":["../../src/components/QueryControls.tsx"],"names":[],"mappings":"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","sourcesContent":["import {Button, cn, Spinner, Textarea} from '@sqlrooms/ui';\nimport {ArrowUpIcon, OctagonXIcon} from 'lucide-react';\nimport {PropsWithChildren, useCallback, useRef, useEffect} from 'react';\nimport {useStoreWithAi} from '../AiSlice';\n\ntype QueryControlsProps = PropsWithChildren<{\n className?: string;\n placeholder?: string;\n onRun?: () => void;\n onCancel?: () => void;\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 const isRunningAnalysis = useStoreWithAi((s) => s.ai.isRunningAnalysis);\n const runAnalysis = useStoreWithAi((s) => s.ai.startAnalysis);\n const cancelAnalysis = useStoreWithAi((s) => s.ai.cancelAnalysis);\n const analysisPrompt = useStoreWithAi((s) => s.ai.analysisPrompt);\n const setAnalysisPrompt = useStoreWithAi((s) => s.ai.setAnalysisPrompt);\n const currentSession = useStoreWithAi((s) => s.ai.getCurrentSession());\n const model = currentSession?.model;\n\n useEffect(() => {\n // Focus the textarea when the component mounts\n // Using a small timeout ensures the data is loaded and\n // add timeout to prevent aria hidden warning caused by the\n // loading progress dialog being still open\n const timer = setTimeout(() => {\n if (textareaRef.current) {\n textareaRef.current.focus();\n }\n }, 500);\n\n return () => clearTimeout(timer);\n }, []);\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 (!isRunningAnalysis && model && analysisPrompt.trim().length) {\n runAnalysis();\n }\n }\n },\n [isRunningAnalysis, model, analysisPrompt, runAnalysis],\n );\n\n const canStart = Boolean(model && analysisPrompt.trim().length);\n\n const handleClickRunOrCancel = useCallback(() => {\n if (isRunningAnalysis) {\n cancelAnalysis();\n onCancel?.();\n } else {\n runAnalysis();\n onRun?.();\n }\n }, [isRunningAnalysis, cancelAnalysis, runAnalysis]);\n\n return (\n <div\n className={cn(\n 'flex w-full flex-col items-center justify-center gap-4',\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 disabled={isRunningAnalysis}\n className=\"min-h-[30px] resize-none border-none p-2 text-sm outline-none focus-visible:ring-0\"\n autoResize\n value={analysisPrompt}\n onChange={(e) => setAnalysisPrompt(e.target.value)}\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 pl-2\">\n <div className=\"flex flex-nowrap items-center gap-2 overflow-x-auto py-1\">\n {children}\n </div>\n </div>\n <div className=\"ml-auto shrink-0 pr-2\">\n <Button\n className=\"h-8 w-8 rounded-full\"\n variant=\"default\"\n size=\"icon\"\n onClick={handleClickRunOrCancel}\n disabled={!canStart}\n >\n {isRunningAnalysis ? <OctagonXIcon /> : <ArrowUpIcon />}\n </Button>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n );\n};\n"]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Main component for managing AI sessions.
|
|
4
|
+
* Combines session dropdown, title editing, action buttons, and delete confirmation.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```tsx
|
|
8
|
+
* <SessionControls className="p-4 border-b">
|
|
9
|
+
* <Button>Custom Button</Button>
|
|
10
|
+
* </SessionControls>
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
export declare const SessionControls: React.FC<{
|
|
14
|
+
className?: string;
|
|
15
|
+
children?: React.ReactNode;
|
|
16
|
+
}>;
|
|
17
|
+
//# sourceMappingURL=SessionControls.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SessionControls.d.ts","sourceRoot":"","sources":["../../src/components/SessionControls.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B;;;;;;;;;;GAUG;AACH,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B,CA2BA,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from '@sqlrooms/ui';
|
|
3
|
+
import { useStoreWithAi } from '../AiSlice';
|
|
4
|
+
import { SessionActions, SessionDropdown, SessionTitle } from './session';
|
|
5
|
+
/**
|
|
6
|
+
* Main component for managing AI sessions.
|
|
7
|
+
* Combines session dropdown, title editing, action buttons, and delete confirmation.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```tsx
|
|
11
|
+
* <SessionControls className="p-4 border-b">
|
|
12
|
+
* <Button>Custom Button</Button>
|
|
13
|
+
* </SessionControls>
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export const SessionControls = ({ className, children }) => {
|
|
17
|
+
const currentSession = useStoreWithAi((s) => s.ai.getCurrentSession());
|
|
18
|
+
return (_jsx(_Fragment, { children: _jsxs("div", { className: cn('flex flex-wrap items-center justify-between', className), children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx(SessionDropdown, {}), _jsx(SessionTitle, {}), currentSession && (_jsx("div", { className: "text-muted-foreground text-xs", children: currentSession.model }))] }), children, _jsx(SessionActions, {})] }) }));
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=SessionControls.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SessionControls.js","sourceRoot":"","sources":["../../src/components/SessionControls.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAC,EAAE,EAAC,MAAM,cAAc,CAAC;AAEhC,OAAO,EAAC,cAAc,EAAC,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAC,cAAc,EAAE,eAAe,EAAE,YAAY,EAAC,MAAM,WAAW,CAAC;AAExE;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,eAAe,GAGvB,CAAC,EAAC,SAAS,EAAE,QAAQ,EAAC,EAAE,EAAE;IAC7B,MAAM,cAAc,GAAG,cAAc,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,iBAAiB,EAAE,CAAC,CAAC;IACvE,OAAO,CACL,4BAEE,eACE,SAAS,EAAE,EAAE,CAAC,6CAA6C,EAAE,SAAS,CAAC,aAGvE,eAAK,SAAS,EAAC,yBAAyB,aACtC,KAAC,eAAe,KAAG,EACnB,KAAC,YAAY,KAAG,EACf,cAAc,IAAI,CACjB,cAAK,SAAS,EAAC,+BAA+B,YAC3C,cAAc,CAAC,KAAK,GACjB,CACP,IACG,EAGL,QAAQ,EAGT,KAAC,cAAc,KAAG,IACd,GACL,CACJ,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import {cn} from '@sqlrooms/ui';\nimport React from 'react';\nimport {useStoreWithAi} from '../AiSlice';\nimport {SessionActions, SessionDropdown, SessionTitle} from './session';\n\n/**\n * Main component for managing AI sessions.\n * Combines session dropdown, title editing, action buttons, and delete confirmation.\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 currentSession = useStoreWithAi((s) => s.ai.getCurrentSession());\n return (\n <>\n {/* Header with session controls */}\n <div\n className={cn('flex flex-wrap items-center justify-between', className)}\n >\n {/* Left side - History Button and Editable Session Title */}\n <div className=\"flex items-center gap-3\">\n <SessionDropdown />\n <SessionTitle />\n {currentSession && (\n <div className=\"text-muted-foreground text-xs\">\n {currentSession.model}\n </div>\n )}\n </div>\n\n {/* Render children if provided */}\n {children}\n\n {/* Right side buttons */}\n <SessionActions />\n </div>\n </>\n );\n};\n"]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Props for the DeleteSessionButton component
|
|
4
|
+
*/
|
|
5
|
+
export interface DeleteSessionButtonProps {
|
|
6
|
+
/** Optional CSS class names to apply to the button */
|
|
7
|
+
className?: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* A button component that handles session deletion with confirmation dialog.
|
|
11
|
+
* Only appears when there is more than one session available.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```tsx
|
|
15
|
+
* <DeleteSessionButton className="my-custom-class" />
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export declare const DeleteSessionButton: React.FC<DeleteSessionButtonProps>;
|
|
19
|
+
//# sourceMappingURL=DeleteSessionButton.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DeleteSessionButton.d.ts","sourceRoot":"","sources":["../../../src/components/session/DeleteSessionButton.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAiB,MAAM,OAAO,CAAC;AAItC;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,mBAAmB,EAAE,KAAK,CAAC,EAAE,CAAC,wBAAwB,CAiElE,CAAC"}
|