@sqlrooms/ai 0.6.0 → 0.8.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.
Files changed (129) hide show
  1. package/README.md +466 -0
  2. package/dist/AiSlice.d.ts +489 -307
  3. package/dist/AiSlice.d.ts.map +1 -1
  4. package/dist/AiSlice.js +267 -177
  5. package/dist/AiSlice.js.map +1 -1
  6. package/dist/analysis.d.ts +25 -19
  7. package/dist/analysis.d.ts.map +1 -1
  8. package/dist/analysis.js +86 -145
  9. package/dist/analysis.js.map +1 -1
  10. package/dist/components/AnalysisAnswer.d.ts +14 -0
  11. package/dist/components/AnalysisAnswer.d.ts.map +1 -0
  12. package/dist/components/AnalysisAnswer.js +14 -0
  13. package/dist/components/AnalysisAnswer.js.map +1 -0
  14. package/dist/{AnalysisResult.d.ts → components/AnalysisResult.d.ts} +2 -1
  15. package/dist/components/AnalysisResult.d.ts.map +1 -0
  16. package/dist/components/AnalysisResult.js +46 -0
  17. package/dist/components/AnalysisResult.js.map +1 -0
  18. package/dist/components/AnalysisResultsContainer.d.ts +5 -0
  19. package/dist/components/AnalysisResultsContainer.d.ts.map +1 -0
  20. package/dist/components/AnalysisResultsContainer.js +27 -0
  21. package/dist/components/AnalysisResultsContainer.js.map +1 -0
  22. package/dist/components/ErrorMessage.d.ts +4 -0
  23. package/dist/components/ErrorMessage.d.ts.map +1 -0
  24. package/dist/components/ErrorMessage.js +7 -0
  25. package/dist/components/ErrorMessage.js.map +1 -0
  26. package/dist/components/MessageContainer.d.ts +10 -0
  27. package/dist/components/MessageContainer.d.ts.map +1 -0
  28. package/dist/components/MessageContainer.js +17 -0
  29. package/dist/components/MessageContainer.js.map +1 -0
  30. package/dist/components/ModelSelector.d.ts +13 -0
  31. package/dist/components/ModelSelector.d.ts.map +1 -0
  32. package/dist/components/ModelSelector.js +29 -0
  33. package/dist/components/ModelSelector.js.map +1 -0
  34. package/dist/components/QueryControls.d.ts +8 -0
  35. package/dist/components/QueryControls.d.ts.map +1 -0
  36. package/dist/components/QueryControls.js +45 -0
  37. package/dist/components/QueryControls.js.map +1 -0
  38. package/dist/components/SessionControls.d.ts +17 -0
  39. package/dist/components/SessionControls.d.ts.map +1 -0
  40. package/dist/components/SessionControls.js +20 -0
  41. package/dist/components/SessionControls.js.map +1 -0
  42. package/dist/components/session/DeleteSessionButton.d.ts +19 -0
  43. package/dist/components/session/DeleteSessionButton.d.ts.map +1 -0
  44. package/dist/components/session/DeleteSessionButton.js +54 -0
  45. package/dist/components/session/DeleteSessionButton.js.map +1 -0
  46. package/dist/components/session/DeleteSessionDialog.d.ts +27 -0
  47. package/dist/components/session/DeleteSessionDialog.d.ts.map +1 -0
  48. package/dist/components/session/DeleteSessionDialog.js +19 -0
  49. package/dist/components/session/DeleteSessionDialog.js.map +1 -0
  50. package/dist/components/session/SessionActions.d.ts +18 -0
  51. package/dist/components/session/SessionActions.d.ts.map +1 -0
  52. package/dist/components/session/SessionActions.js +19 -0
  53. package/dist/components/session/SessionActions.js.map +1 -0
  54. package/dist/components/session/SessionDropdown.d.ts +18 -0
  55. package/dist/components/session/SessionDropdown.d.ts.map +1 -0
  56. package/dist/components/session/SessionDropdown.js +21 -0
  57. package/dist/components/session/SessionDropdown.js.map +1 -0
  58. package/dist/components/session/SessionTitle.d.ts +18 -0
  59. package/dist/components/session/SessionTitle.d.ts.map +1 -0
  60. package/dist/components/session/SessionTitle.js +22 -0
  61. package/dist/components/session/SessionTitle.js.map +1 -0
  62. package/dist/components/session/SessionType.d.ts +24 -0
  63. package/dist/components/session/SessionType.d.ts.map +1 -0
  64. package/dist/components/session/SessionType.js +2 -0
  65. package/dist/components/session/SessionType.js.map +1 -0
  66. package/dist/components/session/index.d.ts +7 -0
  67. package/dist/components/session/index.d.ts.map +1 -0
  68. package/dist/components/session/index.js +7 -0
  69. package/dist/components/session/index.js.map +1 -0
  70. package/dist/components/tools/QueryToolResult.d.ts +7 -0
  71. package/dist/components/tools/QueryToolResult.d.ts.map +1 -0
  72. package/dist/components/tools/QueryToolResult.js +9 -0
  73. package/dist/components/tools/QueryToolResult.js.map +1 -0
  74. package/dist/components/tools/ToolChart.d.ts +13 -0
  75. package/dist/components/tools/ToolChart.d.ts.map +1 -0
  76. package/dist/components/tools/ToolChart.js +14 -0
  77. package/dist/components/tools/ToolChart.js.map +1 -0
  78. package/dist/components/tools/ToolQuery.d.ts +7 -0
  79. package/dist/components/tools/ToolQuery.d.ts.map +1 -0
  80. package/dist/components/tools/ToolQuery.js +9 -0
  81. package/dist/components/tools/ToolQuery.js.map +1 -0
  82. package/dist/components/tools/ToolResult.d.ts +9 -0
  83. package/dist/components/tools/ToolResult.d.ts.map +1 -0
  84. package/dist/components/tools/ToolResult.js +32 -0
  85. package/dist/components/tools/ToolResult.js.map +1 -0
  86. package/dist/components/tools/ToolResultErrorBoundary.d.ts +19 -0
  87. package/dist/components/tools/ToolResultErrorBoundary.d.ts.map +1 -0
  88. package/dist/components/tools/ToolResultErrorBoundary.js +23 -0
  89. package/dist/components/tools/ToolResultErrorBoundary.js.map +1 -0
  90. package/dist/hooks/useScrollToBottom.d.ts +82 -0
  91. package/dist/hooks/useScrollToBottom.d.ts.map +1 -0
  92. package/dist/hooks/useScrollToBottom.js +140 -0
  93. package/dist/hooks/useScrollToBottom.js.map +1 -0
  94. package/dist/index.d.ts +20 -5
  95. package/dist/index.d.ts.map +1 -1
  96. package/dist/index.js +19 -5
  97. package/dist/index.js.map +1 -1
  98. package/dist/schemas.d.ts +592 -201
  99. package/dist/schemas.d.ts.map +1 -1
  100. package/dist/schemas.js +36 -11
  101. package/dist/schemas.js.map +1 -1
  102. package/package.json +11 -9
  103. package/dist/AnalysisResult.d.ts.map +0 -1
  104. package/dist/AnalysisResult.js +0 -49
  105. package/dist/AnalysisResult.js.map +0 -1
  106. package/dist/AnalysisResultsContainer.d.ts +0 -2
  107. package/dist/AnalysisResultsContainer.d.ts.map +0 -1
  108. package/dist/AnalysisResultsContainer.js +0 -15
  109. package/dist/AnalysisResultsContainer.js.map +0 -1
  110. package/dist/QueryControls.d.ts +0 -6
  111. package/dist/QueryControls.d.ts.map +0 -1
  112. package/dist/QueryControls.js +0 -28
  113. package/dist/QueryControls.js.map +0 -1
  114. package/dist/QueryResult.d.ts +0 -9
  115. package/dist/QueryResult.d.ts.map +0 -1
  116. package/dist/QueryResult.js +0 -46
  117. package/dist/QueryResult.js.map +0 -1
  118. package/dist/ToolCall.d.ts +0 -66
  119. package/dist/ToolCall.d.ts.map +0 -1
  120. package/dist/ToolCall.js +0 -59
  121. package/dist/ToolCall.js.map +0 -1
  122. package/dist/ToolResult.d.ts +0 -10
  123. package/dist/ToolResult.d.ts.map +0 -1
  124. package/dist/ToolResult.js +0 -26
  125. package/dist/ToolResult.js.map +0 -1
  126. package/dist/hooks/use-scroll-to-bottom.d.ts +0 -7
  127. package/dist/hooks/use-scroll-to-bottom.d.ts.map +0 -1
  128. package/dist/hooks/use-scroll-to-bottom.js +0 -51
  129. package/dist/hooks/use-scroll-to-bottom.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SessionType.js","sourceRoot":"","sources":["../../../src/components/session/SessionType.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * Represents a session in the AI system.\n *\n * @example\n * ```typescript\n * const session: SessionType = {\n * id: \"session_123\",\n * name: \"My Analysis Session\",\n * modelProvider: \"openai\",\n * model: \"gpt-4o-mini\"\n * };\n * ```\n */\nexport type SessionType = {\n /** Unique identifier for the session */\n id: string;\n\n /** Display name of the session */\n name: string;\n\n /** Provider of the AI model (e.g., \"openai\") */\n modelProvider?: string;\n\n /** Name of the AI model being used (e.g., \"gpt-4o-mini\") */\n model?: string;\n};\n"]}
@@ -0,0 +1,7 @@
1
+ export * from './DeleteSessionButton';
2
+ export * from './DeleteSessionDialog';
3
+ export * from './SessionActions';
4
+ export * from './SessionDropdown';
5
+ export * from './SessionTitle';
6
+ export * from './SessionType';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/session/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC"}
@@ -0,0 +1,7 @@
1
+ export * from './DeleteSessionButton';
2
+ export * from './DeleteSessionDialog';
3
+ export * from './SessionActions';
4
+ export * from './SessionDropdown';
5
+ export * from './SessionTitle';
6
+ export * from './SessionType';
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/components/session/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC","sourcesContent":["export * from './DeleteSessionButton';\nexport * from './DeleteSessionDialog';\nexport * from './SessionActions';\nexport * from './SessionDropdown';\nexport * from './SessionTitle';\nexport * from './SessionType';\n"]}
@@ -0,0 +1,7 @@
1
+ type QueryToolResultProps = {
2
+ title: string;
3
+ sqlQuery: string;
4
+ };
5
+ export declare function QueryToolResult({ title, sqlQuery }: QueryToolResultProps): import("react/jsx-runtime").JSX.Element;
6
+ export {};
7
+ //# sourceMappingURL=QueryToolResult.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"QueryToolResult.d.ts","sourceRoot":"","sources":["../../../src/components/tools/QueryToolResult.tsx"],"names":[],"mappings":"AAIA,KAAK,oBAAoB,GAAG;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,wBAAgB,eAAe,CAAC,EAAC,KAAK,EAAE,QAAQ,EAAC,EAAE,oBAAoB,2CAiBtE"}
@@ -0,0 +1,9 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { DataTableModal } from '@sqlrooms/data-table';
3
+ import { Button, useDisclosure } from '@sqlrooms/ui';
4
+ import { TableIcon } from 'lucide-react';
5
+ export function QueryToolResult({ title, sqlQuery }) {
6
+ const tableModal = useDisclosure();
7
+ return (_jsxs(_Fragment, { children: [_jsx("div", { className: "text-muted-foreground bg-muted max-h-20 w-full overflow-auto whitespace-pre-wrap rounded-md p-2 font-mono text-xs", children: sqlQuery }), _jsx("div", { children: _jsxs(Button, { variant: "ghost", size: "sm", onClick: tableModal.onOpen, children: [_jsx(TableIcon, { className: "h-4 w-4" }), _jsx("h3", { className: "ml-1 text-xs", children: "Show Query Result" })] }) }), _jsx(DataTableModal, { title: title, query: sqlQuery, tableModal: tableModal })] }));
8
+ }
9
+ //# sourceMappingURL=QueryToolResult.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"QueryToolResult.js","sourceRoot":"","sources":["../../../src/components/tools/QueryToolResult.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAC,cAAc,EAAC,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAC,MAAM,EAAE,aAAa,EAAC,MAAM,cAAc,CAAC;AACnD,OAAO,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAOvC,MAAM,UAAU,eAAe,CAAC,EAAC,KAAK,EAAE,QAAQ,EAAuB;IACrE,MAAM,UAAU,GAAG,aAAa,EAAE,CAAC;IACnC,OAAO,CACL,8BACE,cAAK,SAAS,EAAC,mHAAmH,YAC/H,QAAQ,GACL,EACN,wBACE,MAAC,MAAM,IAAC,OAAO,EAAC,OAAO,EAAC,IAAI,EAAC,IAAI,EAAC,OAAO,EAAE,UAAU,CAAC,MAAM,aAC1D,KAAC,SAAS,IAAC,SAAS,EAAC,SAAS,GAAG,EACjC,aAAI,SAAS,EAAC,cAAc,kCAAuB,IAC5C,GACL,EAEN,KAAC,cAAc,IAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,GAAI,IACxE,CACJ,CAAC;AACJ,CAAC","sourcesContent":["import {DataTableModal} from '@sqlrooms/data-table';\nimport {Button, useDisclosure} from '@sqlrooms/ui';\nimport {TableIcon} from 'lucide-react';\n\ntype QueryToolResultProps = {\n title: string;\n sqlQuery: string;\n};\n\nexport function QueryToolResult({title, sqlQuery}: QueryToolResultProps) {\n const tableModal = useDisclosure();\n return (\n <>\n <div className=\"text-muted-foreground bg-muted max-h-20 w-full overflow-auto whitespace-pre-wrap rounded-md p-2 font-mono text-xs\">\n {sqlQuery}\n </div>\n <div>\n <Button variant=\"ghost\" size=\"sm\" onClick={tableModal.onOpen}>\n <TableIcon className=\"h-4 w-4\" />\n <h3 className=\"ml-1 text-xs\">Show Query Result</h3>\n </Button>\n </div>\n\n <DataTableModal title={title} query={sqlQuery} tableModal={tableModal} />\n </>\n );\n}\n"]}
@@ -0,0 +1,13 @@
1
+ type ToolChartProps = {
2
+ reasoning: string;
3
+ sqlQuery: string;
4
+ vegaLiteSpec: string;
5
+ };
6
+ /**
7
+ * Renders a chart tool call with visualization using Vega-Lite
8
+ * @param {ChartToolParameters} props - The component props
9
+ * @returns {JSX.Element} The rendered chart tool call
10
+ */
11
+ export declare function ToolChart({ sqlQuery, vegaLiteSpec }: ToolChartProps): import("react/jsx-runtime").JSX.Element;
12
+ export {};
13
+ //# sourceMappingURL=ToolChart.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ToolChart.d.ts","sourceRoot":"","sources":["../../../src/components/tools/ToolChart.tsx"],"names":[],"mappings":"AAKA,KAAK,cAAc,GAAG;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,EAAC,QAAQ,EAAE,YAAY,EAAC,EAAE,cAAc,2CAwBjE"}
@@ -0,0 +1,14 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { Spinner } from '@sqlrooms/ui';
3
+ import { VegaLiteChart } from '@sqlrooms/vega';
4
+ import { Suspense } from 'react';
5
+ import { ToolQuery } from './ToolQuery';
6
+ /**
7
+ * Renders a chart tool call with visualization using Vega-Lite
8
+ * @param {ChartToolParameters} props - The component props
9
+ * @returns {JSX.Element} The rendered chart tool call
10
+ */
11
+ export function ToolChart({ sqlQuery, vegaLiteSpec }) {
12
+ return (_jsx(_Fragment, { children: vegaLiteSpec && (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(ToolQuery, { title: "Query Result", sqlQuery: sqlQuery }), _jsx(Suspense, { fallback: _jsx("div", { className: "flex h-full w-full items-center justify-center", children: _jsx(Spinner, { className: "h-4 w-4" }) }), children: _jsx(VegaLiteChart, { className: "max-w-[600px]", aspectRatio: 16 / 9, sqlQuery: sqlQuery, spec: vegaLiteSpec }) })] })) }));
13
+ }
14
+ //# sourceMappingURL=ToolChart.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ToolChart.js","sourceRoot":"","sources":["../../../src/components/tools/ToolChart.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAC,OAAO,EAAC,MAAM,cAAc,CAAC;AACrC,OAAO,EAAC,aAAa,EAAC,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAC,QAAQ,EAAC,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAC,SAAS,EAAC,MAAM,aAAa,CAAC;AAQtC;;;;GAIG;AACH,MAAM,UAAU,SAAS,CAAC,EAAC,QAAQ,EAAE,YAAY,EAAiB;IAChE,OAAO,CACL,4BACG,YAAY,IAAI,CACf,eAAK,SAAS,EAAC,qBAAqB,aAClC,KAAC,SAAS,IAAC,KAAK,EAAC,cAAc,EAAC,QAAQ,EAAE,QAAQ,GAAI,EACtD,KAAC,QAAQ,IACP,QAAQ,EACN,cAAK,SAAS,EAAC,gDAAgD,YAC7D,KAAC,OAAO,IAAC,SAAS,EAAC,SAAS,GAAG,GAC3B,YAGR,KAAC,aAAa,IACZ,SAAS,EAAC,eAAe,EACzB,WAAW,EAAE,EAAE,GAAG,CAAC,EACnB,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,YAAY,GAClB,GACO,IACP,CACP,GACA,CACJ,CAAC;AACJ,CAAC","sourcesContent":["import {Spinner} from '@sqlrooms/ui';\nimport {VegaLiteChart} from '@sqlrooms/vega';\nimport {Suspense} from 'react';\nimport {ToolQuery} from './ToolQuery';\n\ntype ToolChartProps = {\n reasoning: string;\n sqlQuery: string;\n vegaLiteSpec: string;\n};\n\n/**\n * Renders a chart tool call with visualization using Vega-Lite\n * @param {ChartToolParameters} props - The component props\n * @returns {JSX.Element} The rendered chart tool call\n */\nexport function ToolChart({sqlQuery, vegaLiteSpec}: ToolChartProps) {\n return (\n <>\n {vegaLiteSpec && (\n <div className=\"flex flex-col gap-2\">\n <ToolQuery title=\"Query Result\" sqlQuery={sqlQuery} />\n <Suspense\n fallback={\n <div className=\"flex h-full w-full items-center justify-center\">\n <Spinner className=\"h-4 w-4\" />\n </div>\n }\n >\n <VegaLiteChart\n className=\"max-w-[600px]\"\n aspectRatio={16 / 9}\n sqlQuery={sqlQuery}\n spec={vegaLiteSpec}\n />\n </Suspense>\n </div>\n )}\n </>\n );\n}\n"]}
@@ -0,0 +1,7 @@
1
+ type QueryToolResultProps = {
2
+ title: string;
3
+ sqlQuery: string;
4
+ };
5
+ export declare function QueryToolResult({ title, sqlQuery }: QueryToolResultProps): import("react/jsx-runtime").JSX.Element;
6
+ export {};
7
+ //# sourceMappingURL=ToolQuery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ToolQuery.d.ts","sourceRoot":"","sources":["../../../src/components/tools/ToolQuery.tsx"],"names":[],"mappings":"AAIA,KAAK,oBAAoB,GAAG;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,wBAAgB,eAAe,CAAC,EAAC,KAAK,EAAE,QAAQ,EAAC,EAAE,oBAAoB,2CAiBtE"}
@@ -0,0 +1,9 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { DataTableModal } from '@sqlrooms/data-table';
3
+ import { Button, useDisclosure } from '@sqlrooms/ui';
4
+ import { TableIcon } from 'lucide-react';
5
+ export function QueryToolResult({ title, sqlQuery }) {
6
+ const tableModal = useDisclosure();
7
+ return (_jsxs(_Fragment, { children: [_jsx("div", { className: "text-muted-foreground bg-muted max-h-20 w-full overflow-auto whitespace-pre-wrap rounded-md p-2 font-mono text-xs", children: sqlQuery }), _jsx("div", { children: _jsxs(Button, { variant: "ghost", size: "sm", onClick: tableModal.onOpen, children: [_jsx(TableIcon, { className: "h-4 w-4" }), _jsx("h3", { className: "ml-1 text-xs", children: "Show Query Result" })] }) }), _jsx(DataTableModal, { title: title, query: sqlQuery, tableModal: tableModal })] }));
8
+ }
9
+ //# sourceMappingURL=ToolQuery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ToolQuery.js","sourceRoot":"","sources":["../../../src/components/tools/ToolQuery.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAC,cAAc,EAAC,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAC,MAAM,EAAE,aAAa,EAAC,MAAM,cAAc,CAAC;AACnD,OAAO,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAOvC,MAAM,UAAU,eAAe,CAAC,EAAC,KAAK,EAAE,QAAQ,EAAuB;IACrE,MAAM,UAAU,GAAG,aAAa,EAAE,CAAC;IACnC,OAAO,CACL,8BACE,cAAK,SAAS,EAAC,mHAAmH,YAC/H,QAAQ,GACL,EACN,wBACE,MAAC,MAAM,IAAC,OAAO,EAAC,OAAO,EAAC,IAAI,EAAC,IAAI,EAAC,OAAO,EAAE,UAAU,CAAC,MAAM,aAC1D,KAAC,SAAS,IAAC,SAAS,EAAC,SAAS,GAAG,EACjC,aAAI,SAAS,EAAC,cAAc,kCAAuB,IAC5C,GACL,EAEN,KAAC,cAAc,IAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,GAAI,IACxE,CACJ,CAAC;AACJ,CAAC","sourcesContent":["import {DataTableModal} from '@sqlrooms/data-table';\nimport {Button, useDisclosure} from '@sqlrooms/ui';\nimport {TableIcon} from 'lucide-react';\n\ntype QueryToolResultProps = {\n title: string;\n sqlQuery: string;\n};\n\nexport function QueryToolResult({title, sqlQuery}: QueryToolResultProps) {\n const tableModal = useDisclosure();\n return (\n <>\n <div className=\"text-muted-foreground bg-muted max-h-20 w-full overflow-auto whitespace-pre-wrap rounded-md p-2 font-mono text-xs\">\n {sqlQuery}\n </div>\n <div>\n <Button variant=\"ghost\" size=\"sm\" onClick={tableModal.onOpen}>\n <TableIcon className=\"h-4 w-4\" />\n <h3 className=\"ml-1 text-xs\">Show Query Result</h3>\n </Button>\n </div>\n\n <DataTableModal title={title} query={sqlQuery} tableModal={tableModal} />\n </>\n );\n}\n"]}
@@ -0,0 +1,9 @@
1
+ import { ToolCallMessage } from '@openassistant/core';
2
+ import React from 'react';
3
+ type ToolResultProps = {
4
+ toolCallMessage: ToolCallMessage;
5
+ errorMessage?: string;
6
+ };
7
+ export declare const ToolResult: React.FC<ToolResultProps>;
8
+ export {};
9
+ //# sourceMappingURL=ToolResult.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ToolResult.d.ts","sourceRoot":"","sources":["../../../src/components/tools/ToolResult.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,eAAe,EAAC,MAAM,qBAAqB,CAAC;AAIpD,OAAO,KAAK,MAAM,OAAO,CAAC;AAK1B,KAAK,eAAe,GAAG;IACrB,eAAe,EAAE,eAAe,CAAC;IACjC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CAmFhD,CAAC"}
@@ -0,0 +1,32 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { JsonMonacoEditor } from '@sqlrooms/monaco-editor';
3
+ import { Button, useDisclosure } from '@sqlrooms/ui';
4
+ import { InfoIcon } from 'lucide-react';
5
+ import { useStoreWithAi } from '../../AiSlice';
6
+ import { MessageContainer } from '../MessageContainer';
7
+ import { ToolCallErrorBoundary } from './ToolResultErrorBoundary';
8
+ export const ToolResult = ({ toolCallMessage, errorMessage, }) => {
9
+ const { isOpen: showDetails, onToggle: toggleShowDetails } = useDisclosure(false);
10
+ const { toolName, args, llmResult, additionalData, text, isCompleted } = toolCallMessage;
11
+ const ToolComponent = useStoreWithAi((state) => state.ai.findToolComponent(toolName));
12
+ // check if args has a property called 'reason'
13
+ const reason = args.reasoning;
14
+ // check if llmResult is an object and has a success property
15
+ const isSuccess = typeof llmResult === 'object' &&
16
+ llmResult !== null &&
17
+ 'success' in llmResult &&
18
+ llmResult.success === true;
19
+ return !isCompleted ? (_jsx("div", { className: "text-sm text-gray-500", children: text })) : (_jsxs(MessageContainer, { isSuccess: isSuccess, type: toolName, content: {
20
+ toolName,
21
+ args,
22
+ llmResult,
23
+ additionalData,
24
+ isCompleted,
25
+ }, children: [_jsx("div", { className: "text-sm text-gray-500", children: reason && _jsx("span", { children: reason }) }), ToolComponent && isSuccess && isCompleted && (_jsx(ToolCallErrorBoundary, { children: typeof ToolComponent === 'function' ? (_jsx(ToolComponent, { ...llmResult, ...additionalData })) : (ToolComponent) })), isCompleted && (errorMessage || !isSuccess) && (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx("p", { className: "text-sm font-bold text-red-500", children: "Tool call failed" }), _jsx("p", { className: "text-xs", children: errorMessage }), _jsxs(Button, { variant: "ghost", size: "xs", onClick: () => toggleShowDetails(), className: "w-fit", children: [_jsx(InfoIcon, { className: "h-4 w-4" }), showDetails ? 'Hide Details' : 'Show Details'] }), showDetails && (_jsx("div", { className: "h-[300px] w-full overflow-hidden rounded-md border", children: _jsx(JsonMonacoEditor, { value: toolCallMessage, readOnly: true, options: {
26
+ lineNumbers: false,
27
+ minimap: { enabled: false },
28
+ scrollBeyondLastLine: false,
29
+ wordWrap: 'on',
30
+ } }) }))] }))] }));
31
+ };
32
+ //# sourceMappingURL=ToolResult.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ToolResult.js","sourceRoot":"","sources":["../../../src/components/tools/ToolResult.tsx"],"names":[],"mappings":";AACA,OAAO,EAAC,gBAAgB,EAAC,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAC,MAAM,EAAE,aAAa,EAAC,MAAM,cAAc,CAAC;AACnD,OAAO,EAAC,QAAQ,EAAC,MAAM,cAAc,CAAC;AAEtC,OAAO,EAAC,cAAc,EAAC,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAC,gBAAgB,EAAC,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAC,qBAAqB,EAAC,MAAM,2BAA2B,CAAC;AAOhE,MAAM,CAAC,MAAM,UAAU,GAA8B,CAAC,EACpD,eAAe,EACf,YAAY,GACb,EAAE,EAAE;IACH,MAAM,EAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,iBAAiB,EAAC,GACtD,aAAa,CAAC,KAAK,CAAC,CAAC;IACvB,MAAM,EAAC,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,cAAc,EAAE,IAAI,EAAE,WAAW,EAAC,GAClE,eAAe,CAAC;IAElB,MAAM,aAAa,GAAG,cAAc,CAAC,CAAC,KAAK,EAAE,EAAE,CAC7C,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CACrC,CAAC;IAEF,+CAA+C;IAC/C,MAAM,MAAM,GAAG,IAAI,CAAC,SAAmB,CAAC;IAExC,6DAA6D;IAC7D,MAAM,SAAS,GACb,OAAO,SAAS,KAAK,QAAQ;QAC7B,SAAS,KAAK,IAAI;QAClB,SAAS,IAAI,SAAS;QACtB,SAAS,CAAC,OAAO,KAAK,IAAI,CAAC;IAE7B,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CACpB,cAAK,SAAS,EAAC,uBAAuB,YAAE,IAAI,GAAO,CACpD,CAAC,CAAC,CAAC,CACF,MAAC,gBAAgB,IACf,SAAS,EAAE,SAAS,EACpB,IAAI,EAAE,QAAQ,EACd,OAAO,EAAE;YACP,QAAQ;YACR,IAAI;YACJ,SAAS;YACT,cAAc;YACd,WAAW;SACZ,aAED,cAAK,SAAS,EAAC,uBAAuB,YACnC,MAAM,IAAI,yBAAO,MAAM,GAAQ,GAC5B,EACL,aAAa,IAAI,SAAS,IAAI,WAAW,IAAI,CAC5C,KAAC,qBAAqB,cACnB,OAAO,aAAa,KAAK,UAAU,CAAC,CAAC,CAAC,CACrC,KAAC,aAAa,OACP,SAAqC,KACrC,cAA0C,GAC/C,CACH,CAAC,CAAC,CAAC,CACF,aAAa,CACd,GACqB,CACzB,EACA,WAAW,IAAI,CAAC,YAAY,IAAI,CAAC,SAAS,CAAC,IAAI,CAC9C,eAAK,SAAS,EAAC,qBAAqB,aAClC,YAAG,SAAS,EAAC,gCAAgC,iCAAqB,EAClE,YAAG,SAAS,EAAC,SAAS,YAAE,YAAY,GAAK,EACzC,MAAC,MAAM,IACL,OAAO,EAAC,OAAO,EACf,IAAI,EAAC,IAAI,EACT,OAAO,EAAE,GAAG,EAAE,CAAC,iBAAiB,EAAE,EAClC,SAAS,EAAC,OAAO,aAEjB,KAAC,QAAQ,IAAC,SAAS,EAAC,SAAS,GAAG,EAC/B,WAAW,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,cAAc,IACvC,EACR,WAAW,IAAI,CACd,cAAK,SAAS,EAAC,oDAAoD,YACjE,KAAC,gBAAgB,IACf,KAAK,EAAE,eAAe,EACtB,QAAQ,EAAE,IAAI,EACd,OAAO,EAAE;gCACP,WAAW,EAAE,KAAK;gCAClB,OAAO,EAAE,EAAC,OAAO,EAAE,KAAK,EAAC;gCACzB,oBAAoB,EAAE,KAAK;gCAC3B,QAAQ,EAAE,IAAI;6BACf,GACD,GACE,CACP,IACG,CACP,IACgB,CACpB,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import {ToolCallMessage} from '@openassistant/core';\nimport {JsonMonacoEditor} from '@sqlrooms/monaco-editor';\nimport {Button, useDisclosure} from '@sqlrooms/ui';\nimport {InfoIcon} from 'lucide-react';\nimport React from 'react';\nimport {useStoreWithAi} from '../../AiSlice';\nimport {MessageContainer} from '../MessageContainer';\nimport {ToolCallErrorBoundary} from './ToolResultErrorBoundary';\n\ntype ToolResultProps = {\n toolCallMessage: ToolCallMessage;\n errorMessage?: string;\n};\n\nexport const ToolResult: React.FC<ToolResultProps> = ({\n toolCallMessage,\n errorMessage,\n}) => {\n const {isOpen: showDetails, onToggle: toggleShowDetails} =\n useDisclosure(false);\n const {toolName, args, llmResult, additionalData, text, isCompleted} =\n toolCallMessage;\n\n const ToolComponent = useStoreWithAi((state) =>\n state.ai.findToolComponent(toolName),\n );\n\n // check if args has a property called 'reason'\n const reason = args.reasoning as string;\n\n // check if llmResult is an object and has a success property\n const isSuccess =\n typeof llmResult === 'object' &&\n llmResult !== null &&\n 'success' in llmResult &&\n llmResult.success === true;\n\n return !isCompleted ? (\n <div className=\"text-sm text-gray-500\">{text}</div>\n ) : (\n <MessageContainer\n isSuccess={isSuccess}\n type={toolName}\n content={{\n toolName,\n args,\n llmResult,\n additionalData,\n isCompleted,\n }}\n >\n <div className=\"text-sm text-gray-500\">\n {reason && <span>{reason}</span>}\n </div>\n {ToolComponent && isSuccess && isCompleted && (\n <ToolCallErrorBoundary>\n {typeof ToolComponent === 'function' ? (\n <ToolComponent\n {...(llmResult as Record<string, unknown>)}\n {...(additionalData as Record<string, unknown>)}\n />\n ) : (\n ToolComponent\n )}\n </ToolCallErrorBoundary>\n )}\n {isCompleted && (errorMessage || !isSuccess) && (\n <div className=\"flex flex-col gap-2\">\n <p className=\"text-sm font-bold text-red-500\">Tool call failed</p>\n <p className=\"text-xs\">{errorMessage}</p>\n <Button\n variant=\"ghost\"\n size=\"xs\"\n onClick={() => toggleShowDetails()}\n className=\"w-fit\"\n >\n <InfoIcon className=\"h-4 w-4\" />\n {showDetails ? 'Hide Details' : 'Show Details'}\n </Button>\n {showDetails && (\n <div className=\"h-[300px] w-full overflow-hidden rounded-md border\">\n <JsonMonacoEditor\n value={toolCallMessage}\n readOnly={true}\n options={{\n lineNumbers: false,\n minimap: {enabled: false},\n scrollBeyondLastLine: false,\n wordWrap: 'on',\n }}\n />\n </div>\n )}\n </div>\n )}\n </MessageContainer>\n );\n};\n"]}
@@ -0,0 +1,19 @@
1
+ import React, { ReactNode } from 'react';
2
+ export declare class ToolCallErrorBoundary extends React.Component<{
3
+ children: ReactNode;
4
+ onError?: () => void;
5
+ }, {
6
+ hasError: boolean;
7
+ error?: Error;
8
+ }> {
9
+ constructor(props: {
10
+ children: ReactNode;
11
+ onError?: () => void;
12
+ });
13
+ static getDerivedStateFromError(): {
14
+ hasError: boolean;
15
+ };
16
+ componentDidCatch(error: Error): void;
17
+ render(): string | number | boolean | import("react/jsx-runtime").JSX.Element | Iterable<React.ReactNode> | null | undefined;
18
+ }
19
+ //# sourceMappingURL=ToolResultErrorBoundary.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ToolResultErrorBoundary.d.ts","sourceRoot":"","sources":["../../../src/components/tools/ToolResultErrorBoundary.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAC,SAAS,EAAC,MAAM,OAAO,CAAC;AAEvC,qBAAa,qBAAsB,SAAQ,KAAK,CAAC,SAAS,CACxD;IAAC,QAAQ,EAAE,SAAS,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;CAAC,EAC3C;IAAC,QAAQ,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,KAAK,CAAA;CAAC,CACnC;gBACa,KAAK,EAAE;QAAC,QAAQ,EAAE,SAAS,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;KAAC;IAK9D,MAAM,CAAC,wBAAwB;;;IAI/B,iBAAiB,CAAC,KAAK,EAAE,KAAK;IAM9B,MAAM;CAYP"}
@@ -0,0 +1,23 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import React from 'react';
3
+ export class ToolCallErrorBoundary extends React.Component {
4
+ constructor(props) {
5
+ super(props);
6
+ this.state = { hasError: false };
7
+ }
8
+ static getDerivedStateFromError() {
9
+ return { hasError: true };
10
+ }
11
+ componentDidCatch(error) {
12
+ console.error('Tool call component error:', error);
13
+ this.setState({ error });
14
+ this.props.onError?.();
15
+ }
16
+ render() {
17
+ if (this.state.hasError) {
18
+ return (_jsxs("div", { className: "text-danger text-sm text-red-500", children: ["Failed to render tool component. Please try again or contact support.", _jsx("pre", { children: JSON.stringify(this.state.error, null, 2) })] }));
19
+ }
20
+ return this.props.children;
21
+ }
22
+ }
23
+ //# sourceMappingURL=ToolResultErrorBoundary.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ToolResultErrorBoundary.js","sourceRoot":"","sources":["../../../src/components/tools/ToolResultErrorBoundary.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAkB,MAAM,OAAO,CAAC;AAEvC,MAAM,OAAO,qBAAsB,SAAQ,KAAK,CAAC,SAGhD;IACC,YAAY,KAAkD;QAC5D,KAAK,CAAC,KAAK,CAAC,CAAC;QACb,IAAI,CAAC,KAAK,GAAG,EAAC,QAAQ,EAAE,KAAK,EAAC,CAAC;IACjC,CAAC;IAED,MAAM,CAAC,wBAAwB;QAC7B,OAAO,EAAC,QAAQ,EAAE,IAAI,EAAC,CAAC;IAC1B,CAAC;IAED,iBAAiB,CAAC,KAAY;QAC5B,OAAO,CAAC,KAAK,CAAC,4BAA4B,EAAE,KAAK,CAAC,CAAC;QACnD,IAAI,CAAC,QAAQ,CAAC,EAAC,KAAK,EAAC,CAAC,CAAC;QACvB,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;IACzB,CAAC;IAED,MAAM;QACJ,IAAI,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;YACxB,OAAO,CACL,eAAK,SAAS,EAAC,kCAAkC,sFAE/C,wBAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,GAAO,IAClD,CACP,CAAC;QACJ,CAAC;QAED,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC;IAC7B,CAAC;CACF","sourcesContent":["import React, {ReactNode} from 'react';\n\nexport class ToolCallErrorBoundary extends React.Component<\n {children: ReactNode; onError?: () => void},\n {hasError: boolean; error?: Error}\n> {\n constructor(props: {children: ReactNode; onError?: () => void}) {\n super(props);\n this.state = {hasError: false};\n }\n\n static getDerivedStateFromError() {\n return {hasError: true};\n }\n\n componentDidCatch(error: Error) {\n console.error('Tool call component error:', error);\n this.setState({error});\n this.props.onError?.();\n }\n\n render() {\n if (this.state.hasError) {\n return (\n <div className=\"text-danger text-sm text-red-500\">\n Failed to render tool component. Please try again or contact support.\n <pre>{JSON.stringify(this.state.error, null, 2)}</pre>\n </div>\n );\n }\n\n return this.props.children;\n }\n}\n"]}
@@ -0,0 +1,82 @@
1
+ import { type RefObject } from 'react';
2
+ interface ScrollToBottomResult<T extends HTMLElement> {
3
+ showScrollButton: boolean;
4
+ scrollToBottom: () => void;
5
+ }
6
+ /**
7
+ * A React hook that provides automatic scrolling behavior for containers with dynamic content.
8
+ *
9
+ * This hook helps manage scroll behavior in containers where content is being added dynamically,
10
+ * such as chat interfaces or logs. It automatically scrolls to the bottom when new content is added
11
+ * if the user was already at the bottom, and provides a function to manually scroll to the bottom.
12
+ *
13
+ * @template T - The type of HTMLElement for the container and end references
14
+ *
15
+ * @param options - Configuration options
16
+ * @param options.dataToObserve - The data to observe for changes (messages, items, etc.)
17
+ * @param options.containerRef - Reference to the scrollable container element
18
+ * @param options.endRef - Reference to an element at the end of the content
19
+ * @param options.scrollOnInitialLoad - Whether to scroll to bottom on initial load (default: true)
20
+ *
21
+ * @returns An object containing:
22
+ * - showScrollButton: Boolean indicating if the "scroll to bottom" button should be shown
23
+ * - scrollToBottom: Function to programmatically scroll to the bottom
24
+ *
25
+ * @example
26
+ * ```tsx
27
+ * import { useRef } from 'react';
28
+ * import { useScrollToBottom } from './use-scroll-to-bottom';
29
+ *
30
+ * function ChatContainer({ messages }) {
31
+ * const containerRef = useRef<HTMLDivElement>(null);
32
+ * const endRef = useRef<HTMLDivElement>(null);
33
+ *
34
+ * const { showScrollButton, scrollToBottom } = useScrollToBottom({
35
+ * dataToObserve: messages,
36
+ * containerRef,
37
+ * endRef,
38
+ * scrollOnInitialLoad: false // Disable scrolling on initial load
39
+ * });
40
+ *
41
+ * return (
42
+ * <div className="relative h-[500px]">
43
+ * <div ref={containerRef} className="h-full overflow-y-auto p-4">
44
+ * {messages.map((message) => (
45
+ * <div key={message.id} className="mb-4">
46
+ * {message.text}
47
+ * </div>
48
+ * ))}
49
+ * <div ref={endRef} />
50
+ * </div>
51
+ *
52
+ * {showScrollButton && (
53
+ * <button
54
+ * onClick={scrollToBottom}
55
+ * className="absolute bottom-4 right-4 rounded-full bg-blue-500 p-2"
56
+ * >
57
+ * ↓
58
+ * </button>
59
+ * )}
60
+ * </div>
61
+ * );
62
+ * }
63
+ * ```
64
+ */
65
+ export declare function useScrollToBottom<T extends HTMLElement>({
66
+ /**
67
+ * The data to observe. Can be an array of items or a single item.
68
+ * When the data changes, the hook will scroll to the bottom of the container.
69
+ */
70
+ dataToObserve, containerRef, endRef,
71
+ /**
72
+ * Whether to scroll to bottom on initial load.
73
+ * @default false
74
+ */
75
+ scrollOnInitialLoad, }: {
76
+ dataToObserve: unknown;
77
+ containerRef: RefObject<T>;
78
+ endRef: RefObject<T>;
79
+ scrollOnInitialLoad?: boolean;
80
+ }): ScrollToBottomResult<T>;
81
+ export {};
82
+ //# sourceMappingURL=useScrollToBottom.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useScrollToBottom.d.ts","sourceRoot":"","sources":["../../src/hooks/useScrollToBottom.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,KAAK,SAAS,EAAwB,MAAM,OAAO,CAAC;AAE/E,UAAU,oBAAoB,CAAC,CAAC,SAAS,WAAW;IAClD,gBAAgB,EAAE,OAAO,CAAC;IAC1B,cAAc,EAAE,MAAM,IAAI,CAAC;CAC5B;AAQD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,WAAW,EAAE;AACvD;;;GAGG;AACH,aAAa,EACb,YAAY,EACZ,MAAM;AACN;;;GAGG;AACH,mBAA2B,GAC5B,EAAE;IACD,aAAa,EAAE,OAAO,CAAC;IACvB,YAAY,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;IAC3B,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;IACrB,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B,GAAG,oBAAoB,CAAC,CAAC,CAAC,CA8E1B"}
@@ -0,0 +1,140 @@
1
+ import { useEffect, useRef, useState, useCallback } from 'react';
2
+ /**
3
+ * Only show button and auto-scroll if we're scrolled up more
4
+ * than {AT_BOTTOM_TOLERANCE}px from the bottom.
5
+ */
6
+ const AT_BOTTOM_TOLERANCE = 100;
7
+ /**
8
+ * A React hook that provides automatic scrolling behavior for containers with dynamic content.
9
+ *
10
+ * This hook helps manage scroll behavior in containers where content is being added dynamically,
11
+ * such as chat interfaces or logs. It automatically scrolls to the bottom when new content is added
12
+ * if the user was already at the bottom, and provides a function to manually scroll to the bottom.
13
+ *
14
+ * @template T - The type of HTMLElement for the container and end references
15
+ *
16
+ * @param options - Configuration options
17
+ * @param options.dataToObserve - The data to observe for changes (messages, items, etc.)
18
+ * @param options.containerRef - Reference to the scrollable container element
19
+ * @param options.endRef - Reference to an element at the end of the content
20
+ * @param options.scrollOnInitialLoad - Whether to scroll to bottom on initial load (default: true)
21
+ *
22
+ * @returns An object containing:
23
+ * - showScrollButton: Boolean indicating if the "scroll to bottom" button should be shown
24
+ * - scrollToBottom: Function to programmatically scroll to the bottom
25
+ *
26
+ * @example
27
+ * ```tsx
28
+ * import { useRef } from 'react';
29
+ * import { useScrollToBottom } from './use-scroll-to-bottom';
30
+ *
31
+ * function ChatContainer({ messages }) {
32
+ * const containerRef = useRef<HTMLDivElement>(null);
33
+ * const endRef = useRef<HTMLDivElement>(null);
34
+ *
35
+ * const { showScrollButton, scrollToBottom } = useScrollToBottom({
36
+ * dataToObserve: messages,
37
+ * containerRef,
38
+ * endRef,
39
+ * scrollOnInitialLoad: false // Disable scrolling on initial load
40
+ * });
41
+ *
42
+ * return (
43
+ * <div className="relative h-[500px]">
44
+ * <div ref={containerRef} className="h-full overflow-y-auto p-4">
45
+ * {messages.map((message) => (
46
+ * <div key={message.id} className="mb-4">
47
+ * {message.text}
48
+ * </div>
49
+ * ))}
50
+ * <div ref={endRef} />
51
+ * </div>
52
+ *
53
+ * {showScrollButton && (
54
+ * <button
55
+ * onClick={scrollToBottom}
56
+ * className="absolute bottom-4 right-4 rounded-full bg-blue-500 p-2"
57
+ * >
58
+ * ↓
59
+ * </button>
60
+ * )}
61
+ * </div>
62
+ * );
63
+ * }
64
+ * ```
65
+ */
66
+ export function useScrollToBottom({
67
+ /**
68
+ * The data to observe. Can be an array of items or a single item.
69
+ * When the data changes, the hook will scroll to the bottom of the container.
70
+ */
71
+ dataToObserve, containerRef, endRef,
72
+ /**
73
+ * Whether to scroll to bottom on initial load.
74
+ * @default false
75
+ */
76
+ scrollOnInitialLoad = false, }) {
77
+ const [showScrollButton, setShowButton] = useState(false);
78
+ // Track if user was at bottom before content changes
79
+ const wasAtBottomRef = useRef(scrollOnInitialLoad);
80
+ // Track if this is the initial load
81
+ const isInitialLoadRef = useRef(true);
82
+ // Check if the container is scrolled to the bottom
83
+ const checkIfAtBottom = useCallback((container) => {
84
+ const { scrollTop, scrollHeight, clientHeight } = container;
85
+ return scrollHeight - scrollTop - clientHeight <= AT_BOTTOM_TOLERANCE;
86
+ }, []);
87
+ // Extracted reusable handleScroll function
88
+ const onScroll = useCallback(() => {
89
+ const container = containerRef.current;
90
+ if (!container)
91
+ return;
92
+ const isAtBottom = checkIfAtBottom(container);
93
+ // Update wasAtBottom state for next content change
94
+ wasAtBottomRef.current = isAtBottom;
95
+ // Show button only if not at bottom
96
+ setShowButton(!isAtBottom);
97
+ }, [checkIfAtBottom, containerRef]);
98
+ // Handle new content being added
99
+ useEffect(() => {
100
+ if (!dataToObserve)
101
+ return;
102
+ const container = containerRef.current;
103
+ const end = endRef.current;
104
+ if (container && end && wasAtBottomRef.current) {
105
+ // Only scroll if this is not the initial load or if scrollOnInitialLoad is true
106
+ if (!isInitialLoadRef.current || scrollOnInitialLoad) {
107
+ end.scrollIntoView({ behavior: 'instant', block: 'end' });
108
+ }
109
+ }
110
+ // Mark that initial load is complete
111
+ isInitialLoadRef.current = false;
112
+ // After content change, check scroll position again
113
+ onScroll();
114
+ }, [containerRef, dataToObserve, endRef, onScroll, scrollOnInitialLoad]);
115
+ useEffect(() => {
116
+ const container = containerRef.current;
117
+ if (!container)
118
+ return;
119
+ container.addEventListener('scroll', onScroll);
120
+ // Initial check with a slight delay to ensure proper measurement
121
+ const timeoutId = setTimeout(onScroll, 100);
122
+ return () => {
123
+ container.removeEventListener('scroll', onScroll);
124
+ clearTimeout(timeoutId);
125
+ };
126
+ }, [containerRef, onScroll]);
127
+ const scrollToBottom = () => {
128
+ if (containerRef.current) {
129
+ containerRef.current.scrollTo({
130
+ top: containerRef.current.scrollHeight,
131
+ behavior: 'smooth',
132
+ });
133
+ }
134
+ };
135
+ return {
136
+ showScrollButton,
137
+ scrollToBottom,
138
+ };
139
+ }
140
+ //# sourceMappingURL=useScrollToBottom.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useScrollToBottom.js","sourceRoot":"","sources":["../../src/hooks/useScrollToBottom.ts"],"names":[],"mappings":"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","sourcesContent":["import {useEffect, useRef, type RefObject, useState, useCallback} from 'react';\n\ninterface ScrollToBottomResult<T extends HTMLElement> {\n showScrollButton: boolean;\n scrollToBottom: () => void;\n}\n\n/**\n * Only show button and auto-scroll if we're scrolled up more\n * than {AT_BOTTOM_TOLERANCE}px from the bottom.\n */\nconst AT_BOTTOM_TOLERANCE = 100;\n\n/**\n * A React hook that provides automatic scrolling behavior for containers with dynamic content.\n *\n * This hook helps manage scroll behavior in containers where content is being added dynamically,\n * such as chat interfaces or logs. It automatically scrolls to the bottom when new content is added\n * if the user was already at the bottom, and provides a function to manually scroll to the bottom.\n *\n * @template T - The type of HTMLElement for the container and end references\n *\n * @param options - Configuration options\n * @param options.dataToObserve - The data to observe for changes (messages, items, etc.)\n * @param options.containerRef - Reference to the scrollable container element\n * @param options.endRef - Reference to an element at the end of the content\n * @param options.scrollOnInitialLoad - Whether to scroll to bottom on initial load (default: true)\n *\n * @returns An object containing:\n * - showScrollButton: Boolean indicating if the \"scroll to bottom\" button should be shown\n * - scrollToBottom: Function to programmatically scroll to the bottom\n *\n * @example\n * ```tsx\n * import { useRef } from 'react';\n * import { useScrollToBottom } from './use-scroll-to-bottom';\n *\n * function ChatContainer({ messages }) {\n * const containerRef = useRef<HTMLDivElement>(null);\n * const endRef = useRef<HTMLDivElement>(null);\n *\n * const { showScrollButton, scrollToBottom } = useScrollToBottom({\n * dataToObserve: messages,\n * containerRef,\n * endRef,\n * scrollOnInitialLoad: false // Disable scrolling on initial load\n * });\n *\n * return (\n * <div className=\"relative h-[500px]\">\n * <div ref={containerRef} className=\"h-full overflow-y-auto p-4\">\n * {messages.map((message) => (\n * <div key={message.id} className=\"mb-4\">\n * {message.text}\n * </div>\n * ))}\n * <div ref={endRef} />\n * </div>\n *\n * {showScrollButton && (\n * <button\n * onClick={scrollToBottom}\n * className=\"absolute bottom-4 right-4 rounded-full bg-blue-500 p-2\"\n * >\n * ↓\n * </button>\n * )}\n * </div>\n * );\n * }\n * ```\n */\nexport function useScrollToBottom<T extends HTMLElement>({\n /**\n * The data to observe. Can be an array of items or a single item.\n * When the data changes, the hook will scroll to the bottom of the container.\n */\n dataToObserve,\n containerRef,\n endRef,\n /**\n * Whether to scroll to bottom on initial load.\n * @default false\n */\n scrollOnInitialLoad = false,\n}: {\n dataToObserve: unknown;\n containerRef: RefObject<T>;\n endRef: RefObject<T>;\n scrollOnInitialLoad?: boolean;\n}): ScrollToBottomResult<T> {\n const [showScrollButton, setShowButton] = useState(false);\n\n // Track if user was at bottom before content changes\n const wasAtBottomRef = useRef(scrollOnInitialLoad);\n\n // Track if this is the initial load\n const isInitialLoadRef = useRef(true);\n\n // Check if the container is scrolled to the bottom\n const checkIfAtBottom = useCallback((container: T) => {\n const {scrollTop, scrollHeight, clientHeight} = container;\n return scrollHeight - scrollTop - clientHeight <= AT_BOTTOM_TOLERANCE;\n }, []);\n\n // Extracted reusable handleScroll function\n const onScroll = useCallback(() => {\n const container = containerRef.current;\n if (!container) return;\n\n const isAtBottom = checkIfAtBottom(container);\n\n // Update wasAtBottom state for next content change\n wasAtBottomRef.current = isAtBottom;\n\n // Show button only if not at bottom\n setShowButton(!isAtBottom);\n }, [checkIfAtBottom, containerRef]);\n\n // Handle new content being added\n useEffect(() => {\n if (!dataToObserve) return;\n\n const container = containerRef.current;\n const end = endRef.current;\n\n if (container && end && wasAtBottomRef.current) {\n // Only scroll if this is not the initial load or if scrollOnInitialLoad is true\n if (!isInitialLoadRef.current || scrollOnInitialLoad) {\n end.scrollIntoView({behavior: 'instant', block: 'end'});\n }\n }\n\n // Mark that initial load is complete\n isInitialLoadRef.current = false;\n\n // After content change, check scroll position again\n onScroll();\n }, [containerRef, dataToObserve, endRef, onScroll, scrollOnInitialLoad]);\n\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n\n container.addEventListener('scroll', onScroll);\n\n // Initial check with a slight delay to ensure proper measurement\n const timeoutId = setTimeout(onScroll, 100);\n\n return () => {\n container.removeEventListener('scroll', onScroll);\n clearTimeout(timeoutId);\n };\n }, [containerRef, onScroll]);\n\n const scrollToBottom = () => {\n if (containerRef.current) {\n containerRef.current.scrollTo({\n top: containerRef.current.scrollHeight,\n behavior: 'smooth',\n });\n }\n };\n\n return {\n showScrollButton,\n scrollToBottom,\n };\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -1,7 +1,22 @@
1
- export { AiSliceConfig, createAiSlice, useStoreWithAi as useAiStore, createDefaultAiConfig, } from './AiSlice';
1
+ /**
2
+ * {@include ../README.md}
3
+ * @packageDocumentation
4
+ */
5
+ export { AiSliceConfig, createAiSlice, useStoreWithAi, createDefaultAiConfig, } from './AiSlice';
2
6
  export type { AiSliceState } from './AiSlice';
3
- export { QueryControls } from './QueryControls';
4
- export { AnalysisResultsContainer } from './AnalysisResultsContainer';
5
- export { AnalysisResult } from './AnalysisResult';
6
- export { useScrollToBottom, useScrollToBottomButton, } from './hooks/use-scroll-to-bottom';
7
+ export { QueryControls } from './components/QueryControls';
8
+ export { AnalysisResultsContainer } from './components/AnalysisResultsContainer';
9
+ export { AnalysisResult } from './components/AnalysisResult';
10
+ export { useScrollToBottom } from './hooks/useScrollToBottom';
11
+ export type { AiSliceTool } from './AiSlice';
12
+ export { QueryToolResult } from './components/tools/QueryToolResult';
13
+ export { getDefaultInstructions } from './analysis';
14
+ export * from './components/ModelSelector';
15
+ export * from './components/SessionControls';
16
+ export * from './components/QueryControls';
17
+ export * from './components/session/DeleteSessionDialog';
18
+ export * from './components/session/SessionActions';
19
+ export * from './components/session/SessionDropdown';
20
+ export * from './components/session/SessionTitle';
21
+ export * from './components/session/SessionType';
7
22
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,aAAa,EACb,cAAc,IAAI,UAAU,EAC5B,qBAAqB,GACtB,MAAM,WAAW,CAAC;AAEnB,YAAY,EAAC,YAAY,EAAC,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAC,aAAa,EAAC,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAC,wBAAwB,EAAC,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAC;AAChD,OAAO,EACL,iBAAiB,EACjB,uBAAuB,GACxB,MAAM,8BAA8B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,aAAa,EACb,aAAa,EACb,cAAc,EACd,qBAAqB,GACtB,MAAM,WAAW,CAAC;AAEnB,YAAY,EAAC,YAAY,EAAC,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAC,aAAa,EAAC,MAAM,4BAA4B,CAAC;AACzD,OAAO,EAAC,wBAAwB,EAAC,MAAM,uCAAuC,CAAC;AAC/E,OAAO,EAAC,cAAc,EAAC,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAC,iBAAiB,EAAC,MAAM,2BAA2B,CAAC;AAC5D,YAAY,EAAC,WAAW,EAAC,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAC,eAAe,EAAC,MAAM,oCAAoC,CAAC;AACnE,OAAO,EAAC,sBAAsB,EAAC,MAAM,YAAY,CAAC;AAElD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,0CAA0C,CAAC;AACzD,cAAc,qCAAqC,CAAC;AACpD,cAAc,sCAAsC,CAAC;AACrD,cAAc,mCAAmC,CAAC;AAClD,cAAc,kCAAkC,CAAC"}
package/dist/index.js CHANGED
@@ -1,6 +1,20 @@
1
- export { AiSliceConfig, createAiSlice, useStoreWithAi as useAiStore, createDefaultAiConfig, } from './AiSlice';
2
- export { QueryControls } from './QueryControls';
3
- export { AnalysisResultsContainer } from './AnalysisResultsContainer';
4
- export { AnalysisResult } from './AnalysisResult';
5
- export { useScrollToBottom, useScrollToBottomButton, } from './hooks/use-scroll-to-bottom';
1
+ /**
2
+ * {@include ../README.md}
3
+ * @packageDocumentation
4
+ */
5
+ export { AiSliceConfig, createAiSlice, useStoreWithAi, createDefaultAiConfig, } from './AiSlice';
6
+ export { QueryControls } from './components/QueryControls';
7
+ export { AnalysisResultsContainer } from './components/AnalysisResultsContainer';
8
+ export { AnalysisResult } from './components/AnalysisResult';
9
+ export { useScrollToBottom } from './hooks/useScrollToBottom';
10
+ export { QueryToolResult } from './components/tools/QueryToolResult';
11
+ export { getDefaultInstructions } from './analysis';
12
+ export * from './components/ModelSelector';
13
+ export * from './components/SessionControls';
14
+ export * from './components/QueryControls';
15
+ export * from './components/session/DeleteSessionDialog';
16
+ export * from './components/session/SessionActions';
17
+ export * from './components/session/SessionDropdown';
18
+ export * from './components/session/SessionTitle';
19
+ export * from './components/session/SessionType';
6
20
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,aAAa,EACb,cAAc,IAAI,UAAU,EAC5B,qBAAqB,GACtB,MAAM,WAAW,CAAC;AAGnB,OAAO,EAAC,aAAa,EAAC,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAC,wBAAwB,EAAC,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAC;AAChD,OAAO,EACL,iBAAiB,EACjB,uBAAuB,GACxB,MAAM,8BAA8B,CAAC","sourcesContent":["export {\n AiSliceConfig,\n createAiSlice,\n useStoreWithAi as useAiStore,\n createDefaultAiConfig,\n} from './AiSlice';\n\nexport type {AiSliceState} from './AiSlice';\nexport {QueryControls} from './QueryControls';\nexport {AnalysisResultsContainer} from './AnalysisResultsContainer';\nexport {AnalysisResult} from './AnalysisResult';\nexport {\n useScrollToBottom,\n useScrollToBottomButton,\n} from './hooks/use-scroll-to-bottom';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,aAAa,EACb,aAAa,EACb,cAAc,EACd,qBAAqB,GACtB,MAAM,WAAW,CAAC;AAGnB,OAAO,EAAC,aAAa,EAAC,MAAM,4BAA4B,CAAC;AACzD,OAAO,EAAC,wBAAwB,EAAC,MAAM,uCAAuC,CAAC;AAC/E,OAAO,EAAC,cAAc,EAAC,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAC,iBAAiB,EAAC,MAAM,2BAA2B,CAAC;AAE5D,OAAO,EAAC,eAAe,EAAC,MAAM,oCAAoC,CAAC;AACnE,OAAO,EAAC,sBAAsB,EAAC,MAAM,YAAY,CAAC;AAElD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,0CAA0C,CAAC;AACzD,cAAc,qCAAqC,CAAC;AACpD,cAAc,sCAAsC,CAAC;AACrD,cAAc,mCAAmC,CAAC;AAClD,cAAc,kCAAkC,CAAC","sourcesContent":["/**\n * {@include ../README.md}\n * @packageDocumentation\n */\n\nexport {\n AiSliceConfig,\n createAiSlice,\n useStoreWithAi,\n createDefaultAiConfig,\n} from './AiSlice';\n\nexport type {AiSliceState} from './AiSlice';\nexport {QueryControls} from './components/QueryControls';\nexport {AnalysisResultsContainer} from './components/AnalysisResultsContainer';\nexport {AnalysisResult} from './components/AnalysisResult';\nexport {useScrollToBottom} from './hooks/useScrollToBottom';\nexport type {AiSliceTool} from './AiSlice';\nexport {QueryToolResult} from './components/tools/QueryToolResult';\nexport {getDefaultInstructions} from './analysis';\n\nexport * from './components/ModelSelector';\nexport * from './components/SessionControls';\nexport * from './components/QueryControls';\nexport * from './components/session/DeleteSessionDialog';\nexport * from './components/session/SessionActions';\nexport * from './components/session/SessionDropdown';\nexport * from './components/session/SessionTitle';\nexport * from './components/session/SessionType';\n"]}