@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
@@ -1,5 +1,11 @@
1
- import { StepResult } from 'ai';
2
- import { ToolCallMessage, VercelToolSet } from '@openassistant/core';
1
+ import { StreamMessage } from '@openassistant/core';
2
+ import { DataTable } from '@sqlrooms/duckdb';
3
+ import { AnalysisResultSchema } from './schemas';
4
+ import { AiSliceTool } from './AiSlice';
5
+ /**
6
+ * Returns the default system instructions for the AI assistant
7
+ */
8
+ export declare function getDefaultInstructions(tablesSchema: DataTable[]): string;
3
9
  /**
4
10
  * Configuration options for running an AI analysis session
5
11
  */
@@ -16,21 +22,24 @@ export type AnalysisConfig = {
16
22
  prompt: string;
17
23
  /** Optional controller for canceling the analysis operation */
18
24
  abortController?: AbortController;
19
- /**
20
- * Callback fired after each analysis step completion
21
- * @param event - Current step result containing tool execution details. See Vercel AI SDK documentation for more details.
22
- * Specifically, it contains the array of tool calls and the results of the tool calls (toolResults).
23
- * @param toolCallMessages - Collection of messages generated during tool calls. They are linked to the tool call by the toolCallId.
24
- */
25
- onStepFinish?: (event: StepResult<typeof TOOLS>, toolCallMessages: ToolCallMessage[]) => Promise<void> | void;
26
25
  /** Maximum number of analysis steps allowed (default: 100) */
27
26
  maxSteps?: number;
27
+ /** The history of analysis results (e.g. saved in localStorage) */
28
+ historyAnalysis?: AnalysisResultSchema[];
29
+ /** Tools to use in the analysis */
30
+ tools?: Record<string, AiSliceTool>;
31
+ /**
32
+ * Function to get custom instructions for the AI assistant
33
+ * @param tablesSchema - The schema of the tables in the database
34
+ * @returns The instructions string to use
35
+ */
36
+ getInstructions?: (tablesSchema: DataTable[]) => string;
28
37
  /**
29
38
  * Callback for handling streaming results
30
- * @param message - Current message content being streamed
31
39
  * @param isCompleted - Indicates if this is the final message in the stream
40
+ * @param streamMessage - Current message content being streamed
32
41
  */
33
- onStreamResult: (message: string, isCompleted: boolean) => void;
42
+ onStreamResult: (isCompleted: boolean, streamMessage?: StreamMessage) => void;
34
43
  };
35
44
  /**
36
45
  * Executes an AI analysis session on the project data
@@ -38,17 +47,14 @@ export type AnalysisConfig = {
38
47
  * @param config - Analysis configuration options. See {@link AnalysisConfig} for more details.
39
48
  * @returns Object containing tool calls executed and the final analysis result
40
49
  */
41
- export declare function runAnalysis({ name, modelProvider, model, apiKey, prompt, abortController, onStepFinish, onStreamResult, maxSteps, }: AnalysisConfig): Promise<{
42
- messages: import("ai").Message[];
43
- outputToolResults: never[][] | undefined;
44
- outputToolCalls: import("ai").ToolCall<string, unknown>[] | undefined;
50
+ export declare function runAnalysis({ name, modelProvider, model, apiKey, prompt, abortController, historyAnalysis, onStreamResult, maxSteps, tools, getInstructions, }: AnalysisConfig): Promise<{
51
+ messages: import("@openassistant/core").AIMessage[];
45
52
  }>;
46
53
  /**
47
- * Collection of tools available to the AI assistant for data analysis
54
+ * Default tools available to the AI assistant for data analysis
48
55
  * Includes:
49
56
  * - query: Executes SQL queries against DuckDB
50
- * - chart: Creates VegaLite visualizations
51
57
  */
52
- declare const TOOLS: VercelToolSet;
53
- export {};
58
+ export declare function getDefaultTools(): Record<string, AiSliceTool>;
59
+ export declare const TOOLS: Record<string, AiSliceTool>;
54
60
  //# sourceMappingURL=analysis.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"analysis.d.ts","sourceRoot":"","sources":["../src/analysis.ts"],"names":[],"mappings":"AAKA,OAAO,EAAC,UAAU,EAAC,MAAM,IAAI,CAAC;AAE9B,OAAO,EAGL,eAAe,EACf,aAAa,EACd,MAAM,qBAAqB,CAAC;AAsF7B;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,6DAA6D;IAC7D,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,sDAAsD;IACtD,aAAa,EAAE,MAAM,CAAC;IAEtB,mDAAmD;IACnD,KAAK,EAAE,MAAM,CAAC;IAEd,sDAAsD;IACtD,MAAM,EAAE,MAAM,CAAC;IAEf,kDAAkD;IAClD,MAAM,EAAE,MAAM,CAAC;IAEf,+DAA+D;IAC/D,eAAe,CAAC,EAAE,eAAe,CAAC;IAElC;;;;;OAKG;IACH,YAAY,CAAC,EAAE,CACb,KAAK,EAAE,UAAU,CAAC,OAAO,KAAK,CAAC,EAC/B,gBAAgB,EAAE,eAAe,EAAE,KAChC,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAE1B,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;;OAIG;IACH,cAAc,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,KAAK,IAAI,CAAC;CACjE,CAAC;AAEF;;;;;GAKG;AACH,wBAAsB,WAAW,CAAC,EAChC,IAAoB,EACpB,aAAa,EACb,KAAK,EACL,MAAM,EACN,MAAM,EACN,eAAe,EACf,YAAY,EACZ,cAAc,EACd,QAAY,GACb,EAAE,cAAc;;;;GA6BhB;AAiBD;;;;;GAKG;AACH,QAAA,MAAM,KAAK,EAAE,aAwHZ,CAAC"}
1
+ {"version":3,"file":"analysis.d.ts","sourceRoot":"","sources":["../src/analysis.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,aAAa,EAEd,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAEL,SAAS,EAIV,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAC,oBAAoB,EAAsB,MAAM,WAAW,CAAC;AACpE,OAAO,EAAC,WAAW,EAAC,MAAM,WAAW,CAAC;AAuDtC;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,YAAY,EAAE,SAAS,EAAE,GAAG,MAAM,CAExE;AA6BD;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,6DAA6D;IAC7D,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,sDAAsD;IACtD,aAAa,EAAE,MAAM,CAAC;IAEtB,mDAAmD;IACnD,KAAK,EAAE,MAAM,CAAC;IAEd,sDAAsD;IACtD,MAAM,EAAE,MAAM,CAAC;IAEf,kDAAkD;IAClD,MAAM,EAAE,MAAM,CAAC;IAEf,+DAA+D;IAC/D,eAAe,CAAC,EAAE,eAAe,CAAC;IAElC,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,mEAAmE;IACnE,eAAe,CAAC,EAAE,oBAAoB,EAAE,CAAC;IAEzC,mCAAmC;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAEpC;;;;OAIG;IACH,eAAe,CAAC,EAAE,CAAC,YAAY,EAAE,SAAS,EAAE,KAAK,MAAM,CAAC;IAExD;;;;OAIG;IACH,cAAc,EAAE,CAAC,WAAW,EAAE,OAAO,EAAE,aAAa,CAAC,EAAE,aAAa,KAAK,IAAI,CAAC;CAC/E,CAAC;AAEF;;;;;GAKG;AACH,wBAAsB,WAAW,CAAC,EAChC,IAAoB,EACpB,aAAa,EACb,KAAK,EACL,MAAM,EACN,MAAM,EACN,eAAe,EACf,eAAe,EACf,cAAc,EACd,QAAY,EACZ,KAAU,EACV,eAAe,GAChB,EAAE,cAAc;;GAuChB;AAED;;;;GAIG;AACH,wBAAgB,eAAe,IAAI,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAsD7D;AAED,eAAO,MAAM,KAAK,6BAAoB,CAAC"}
package/dist/analysis.js CHANGED
@@ -1,8 +1,7 @@
1
- import { arrowTableToJson, getDuckDb, getDuckTableSchemas, } from '@sqlrooms/duckdb';
2
- import { createAssistant, } from '@openassistant/core';
3
- import { ChartToolParameters, QueryToolParameters } from './schemas';
4
- import { queryMessage } from './QueryResult';
5
- import { isChartToolParameters, isQueryToolParameters } from './ToolCall';
1
+ import { createAssistant, rebuildMessages, tool, } from '@openassistant/core';
2
+ import { arrowTableToJson, DuckQueryError, getDuckDb, getDuckTableSchemas, } from '@sqlrooms/duckdb';
3
+ import { QueryToolResult } from './components/tools/QueryToolResult';
4
+ import { QueryToolParameters } from './schemas';
6
5
  /**
7
6
  * System prompt template for the AI assistant that provides instructions for:
8
7
  * - Using DuckDB-specific SQL syntax and functions
@@ -10,7 +9,7 @@ import { isChartToolParameters, isQueryToolParameters } from './ToolCall';
10
9
  * - Creating visualizations with VegaLite
11
10
  * - Formatting final answers
12
11
  */
13
- const SYSTEM_PROMPT = `
12
+ const DEFAULT_INSTRUCTIONS = `
14
13
  You are analyzing tables in DuckDB database in the context of a project.
15
14
 
16
15
  Instructions for analysis:
@@ -51,10 +50,16 @@ For your final answer:
51
50
  - Provide an explanation for how you got it
52
51
  - Explain your reasoning step by step
53
52
  - Include relevant statistics or metrics
54
- - For each prompt, please alwasy provide the final answer.
53
+ - For each prompt, please always provide the final answer.
55
54
 
56
55
  Please use the following schema for the tables:
57
56
  `;
57
+ /**
58
+ * Returns the default system instructions for the AI assistant
59
+ */
60
+ export function getDefaultInstructions(tablesSchema) {
61
+ return `${DEFAULT_INSTRUCTIONS}\n${JSON.stringify(tablesSchema)}`;
62
+ }
58
63
  /**
59
64
  * Generates summary statistics for a SQL query result
60
65
  * @param conn - DuckDB connection instance
@@ -84,163 +89,99 @@ async function getQuerySummary(conn, sqlQuery) {
84
89
  * @param config - Analysis configuration options. See {@link AnalysisConfig} for more details.
85
90
  * @returns Object containing tool calls executed and the final analysis result
86
91
  */
87
- export async function runAnalysis({ name = 'sqlrooms-ai', modelProvider, model, apiKey, prompt, abortController, onStepFinish, onStreamResult, maxSteps = 5, }) {
92
+ export async function runAnalysis({ name = 'sqlrooms-ai', modelProvider, model, apiKey, prompt, abortController, historyAnalysis, onStreamResult, maxSteps = 5, tools = {}, getInstructions, }) {
88
93
  const tablesSchema = await getDuckTableSchemas();
89
- // get the singlton assistant instance
94
+ // get the singleton assistant instance
90
95
  const assistant = await createAssistant({
91
96
  name,
92
97
  modelProvider,
93
98
  model,
94
99
  apiKey,
95
100
  version: 'v1',
96
- instructions: `${SYSTEM_PROMPT}\n${JSON.stringify(tablesSchema)}`,
97
- vercelFunctions: TOOLS,
101
+ instructions: getInstructions
102
+ ? getInstructions(tablesSchema)
103
+ : getDefaultInstructions(tablesSchema),
104
+ functions: tools,
98
105
  temperature: 0,
99
106
  toolChoice: 'auto', // this will enable streaming
100
107
  maxSteps,
101
108
  ...(abortController ? { abortController } : {}),
102
109
  });
110
+ // restore ai messages from historyAnalysis?
111
+ if (historyAnalysis) {
112
+ const historyMessages = historyAnalysis.map((analysis) => ({
113
+ prompt: analysis.prompt,
114
+ response: analysis.streamMessage,
115
+ }));
116
+ const initialMessages = rebuildMessages(historyMessages);
117
+ assistant.setMessages(initialMessages);
118
+ }
103
119
  // process the prompt
104
- const result = await assistant.processTextMessage({
120
+ const newMessages = await assistant.processTextMessage({
105
121
  textMessage: prompt,
106
- streamMessageCallback: (message) => {
107
- // the final result (before the answer) can be streamed back here
108
- onStreamResult(message.deltaMessage, message.isCompleted ?? false);
122
+ streamMessageCallback: ({ isCompleted, message }) => {
123
+ onStreamResult(isCompleted ?? false, message);
109
124
  },
110
- onStepFinish,
111
125
  });
112
- return result;
126
+ return newMessages;
113
127
  }
114
128
  /**
115
- * Extracts a readable error message from an error object
116
- * @param error - Error object or unknown value
117
- * @returns Formatted error message string
118
- */
119
- function getErrorMessage(error) {
120
- if (error instanceof Error) {
121
- if (error.cause instanceof Error) {
122
- return error.cause.message;
123
- }
124
- return error.message;
125
- }
126
- return String(error);
127
- }
128
- /**
129
- * Collection of tools available to the AI assistant for data analysis
129
+ * Default tools available to the AI assistant for data analysis
130
130
  * Includes:
131
131
  * - query: Executes SQL queries against DuckDB
132
- * - chart: Creates VegaLite visualizations
133
132
  */
134
- const TOOLS = {
135
- query: {
136
- description: `A tool for executing SQL queries in DuckDB that is embedded in browser using duckdb-wasm.
137
- Query results are returned as a json object "{success: boolean, data: object[], error?: string}"
138
- Please only analyze tables which are in the main schema.
139
- To obtain stats, use the "SUMMARIZE table_name" query.
140
- Don't execute queries that modify data unless explicitly asked.`,
141
- parameters: QueryToolParameters,
142
- executeWithContext: async (props) => {
143
- if (!isQueryToolParameters(props.functionArgs)) {
144
- return {
145
- name: 'query',
146
- result: {
147
- success: false,
148
- error: 'Invalid query parameters',
149
- },
150
- };
151
- }
152
- const { type, sqlQuery } = props.functionArgs;
153
- try {
154
- const { conn } = await getDuckDb();
155
- // TODO use options.abortSignal: maybe call db.cancelPendingQuery
156
- const result = await conn.query(sqlQuery);
157
- // Only get summary if the query isn't already a SUMMARIZE query
158
- const summaryData = sqlQuery.toLowerCase().includes('summarize')
159
- ? arrowTableToJson(result)
160
- : await getQuerySummary(conn, sqlQuery);
161
- // Get first 2 rows of the result as a json object
162
- const subResult = result.slice(0, 2);
163
- const firstTwoRows = arrowTableToJson(subResult);
164
- // create result object sent back to LLM for tool call
165
- const llmResult = {
166
- type,
167
- success: true,
168
- data: {
169
- // only summary and first two rows will be sent back to LLM as context
170
- summary: summaryData,
171
- firstTwoRows,
172
- },
173
- };
174
- // data object of the raw query result, which is NOT sent back to LLM
175
- // we can use it to visualize the arrow table in the callback function `message()` below
176
- const data = { sqlQuery };
177
- return {
178
- name: 'query',
179
- result: llmResult,
180
- data,
181
- };
182
- }
183
- catch (error) {
184
- return {
185
- name: 'query',
186
- result: {
187
- success: false,
188
- description: 'Failed to execute the query. Please stop tool call and return error message.',
189
- error: getErrorMessage(error),
190
- },
191
- };
192
- }
193
- },
194
- message: queryMessage,
195
- },
196
- chart: {
197
- description: `A tool for creating VegaLite charts based on the schema of the SQL query result from the "query" tool.
198
- In the response:
199
- - omit the data from the vegaLiteSpec
200
- - provide an sql query in sqlQuery instead.`,
201
- parameters: ChartToolParameters,
202
- executeWithContext: async (props) => {
203
- if (!isChartToolParameters(props.functionArgs)) {
204
- return {
205
- name: 'chart',
206
- result: {
207
- success: false,
208
- error: 'Invalid chart parameters',
209
- },
210
- };
211
- }
212
- const { sqlQuery, vegaLiteSpec } = props.functionArgs;
213
- const llmResult = {
214
- success: true,
215
- details: 'Chart created successfully.',
216
- };
217
- // data object of the vegaLiteSpec and sqlQuery
218
- // it is not used yet, but we can use it to create a JSON editor for user to edit the vegaLiteSpec so that chart can be updated
219
- const data = {
220
- sqlQuery,
221
- vegaLiteSpec,
222
- };
223
- return {
224
- name: 'chart',
225
- result: llmResult,
226
- data,
227
- };
228
- },
229
- },
230
- // answer tool: the LLM will provide a structured answer
231
- // answer: {
232
- // description: 'A tool for providing the final answer.',
233
- // parameters: AnswerToolParameters,
234
- // executeWithContext: async (props: CallbackFunctionProps) => {
235
- // const {answer} = props.functionArgs;
236
- // return {
237
- // name: 'answer',
238
- // result: {
239
- // success: true,
240
- // data: answer,
241
- // },
242
- // };
243
- // },
244
- // },
245
- };
133
+ export function getDefaultTools() {
134
+ return {
135
+ query: tool({
136
+ description: `A tool for running SQL queries on the tables in the database.
137
+ Please only run one query at a time.
138
+ If a query fails, please don't try to run it again with the same syntax.`,
139
+ parameters: QueryToolParameters,
140
+ // TODO: specify the return type e.g. Promise<Partial<ToolCallMessage>>
141
+ execute: async ({ type, sqlQuery }) => {
142
+ try {
143
+ const { conn } = await getDuckDb();
144
+ // TODO use options.abortSignal: maybe call db.cancelPendingQuery
145
+ const result = await conn.query(sqlQuery);
146
+ // Only get summary if the query isn't already a SUMMARIZE query
147
+ const summaryData = sqlQuery.toLowerCase().includes('summarize')
148
+ ? arrowTableToJson(result)
149
+ : await getQuerySummary(conn, sqlQuery);
150
+ // Get first 2 rows of the result as a json object
151
+ const subResult = result.slice(0, 2);
152
+ const firstTwoRows = arrowTableToJson(subResult);
153
+ return {
154
+ llmResult: {
155
+ success: true,
156
+ data: {
157
+ type,
158
+ summary: summaryData,
159
+ firstTwoRows,
160
+ },
161
+ },
162
+ additionalData: {
163
+ title: 'Query Result',
164
+ sqlQuery,
165
+ },
166
+ };
167
+ }
168
+ catch (error) {
169
+ return {
170
+ llmResult: {
171
+ success: false,
172
+ details: 'Query execution failed.',
173
+ errorMessage: error instanceof DuckQueryError
174
+ ? error.getMessageForUser()
175
+ : error instanceof Error
176
+ ? error.message
177
+ : 'Unknown error',
178
+ },
179
+ };
180
+ }
181
+ },
182
+ component: QueryToolResult,
183
+ }),
184
+ };
185
+ }
186
+ export const TOOLS = getDefaultTools();
246
187
  //# sourceMappingURL=analysis.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"analysis.js","sourceRoot":"","sources":["../src/analysis.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n arrowTableToJson,\n getDuckDb,\n getDuckTableSchemas,\n} from '@sqlrooms/duckdb';\nimport {StepResult} from 'ai';\nimport * as duckdb from '@duckdb/duckdb-wasm';\nimport {\n CallbackFunctionProps,\n createAssistant,\n ToolCallMessage,\n VercelToolSet,\n} from '@openassistant/core';\n\nimport {ChartToolParameters, QueryToolParameters} from './schemas';\nimport {queryMessage} from './QueryResult';\nimport {isChartToolParameters, isQueryToolParameters} from './ToolCall';\n\n/**\n * System prompt template for the AI assistant that provides instructions for:\n * - Using DuckDB-specific SQL syntax and functions\n * - Handling query results and error cases\n * - Creating visualizations with VegaLite\n * - Formatting final answers\n */\nconst SYSTEM_PROMPT = `\nYou are analyzing tables in DuckDB database in the context of a project.\n\nInstructions for analysis:\n- Use DuckDB-specific SQL syntax and functions (not Oracle, PostgreSQL, or other SQL dialects)\n- Some key DuckDB-specific functions to use:\n * regexp_matches() for regex (not regexp_like)\n * strftime() for date formatting (not to_char)\n * list_aggregate() for array operations\n * unnest() for array expansion\n * regr_sxy()\n * corr()\n * skewness()\n- Please always try to use SQL queries to answer users questions\n- Please run tool calls sequentially, don't run multiple tool calls in parallel\n- IMPORTANT: Do not list out raw query results in your response. Instead:\n * Describe the results in natural language\n * Provide summary statistics\n * Use comparisons and relative terms\n * Include only the most relevant values if necessary\n- Break down complex problems into smaller steps\n- Use \"SUMMARIZE table_name\"for quick overview of the table\n- Please don't modify data\n- IMPORTANT: When you receive an error response from a tool call (where success: false):\n * Stop making any further tool calls immediately\n * Return a final answer that includes the error message\n * Explain what went wrong and suggest possible fixes if applicable\n\nWhen creating visualizations:\n- Follow VegaLite syntax\n- Choose appropriate chart types based on the data and analysis goals\n- Use clear titles and axis labels\n- Consider color schemes for better readability\n- Add meaningful tooltips when relevant\n- Format numbers and dates appropriately\n- Use aggregations when dealing with large datasets\n\nFor your final answer:\n- Provide an explanation for how you got it\n- Explain your reasoning step by step\n- Include relevant statistics or metrics\n- For each prompt, please alwasy provide the final answer.\n\nPlease use the following schema for the tables:\n`;\n\n/**\n * Generates summary statistics for a SQL query result\n * @param conn - DuckDB connection instance\n * @param sqlQuery - SQL SELECT query to analyze\n * @returns Summary statistics as JSON object, or null if the query is not a SELECT statement or if summary generation fails\n */\nasync function getQuerySummary(\n conn: duckdb.AsyncDuckDBConnection,\n sqlQuery: string,\n) {\n if (!sqlQuery.toLowerCase().trim().startsWith('select')) {\n return null;\n }\n\n try {\n const viewName = `temp_result_${Date.now()}`; // unique view name to avoid conflicts\n await conn.query(`CREATE TEMPORARY VIEW ${viewName} AS ${sqlQuery}`);\n const summaryResult = await conn.query(`SUMMARIZE ${viewName}`);\n const summaryData = arrowTableToJson(summaryResult);\n await conn.query(`DROP VIEW IF EXISTS ${viewName}`);\n return summaryData;\n } catch (error) {\n console.warn('Failed to get summary:', error);\n return null;\n }\n}\n\n/**\n * Configuration options for running an AI analysis session\n */\nexport type AnalysisConfig = {\n /** Assistant instance identifier (default: 'sqlrooms-ai') */\n name?: string;\n\n /** AI model provider (e.g., 'openai', 'anthropic') */\n modelProvider: string;\n\n /** Model identifier (e.g., 'gpt-4', 'claude-3') */\n model: string;\n\n /** Authentication key for the model provider's API */\n apiKey: string;\n\n /** Analysis prompt or question to be processed */\n prompt: string;\n\n /** Optional controller for canceling the analysis operation */\n abortController?: AbortController;\n\n /**\n * Callback fired after each analysis step completion\n * @param event - Current step result containing tool execution details. See Vercel AI SDK documentation for more details.\n * Specifically, it contains the array of tool calls and the results of the tool calls (toolResults).\n * @param toolCallMessages - Collection of messages generated during tool calls. They are linked to the tool call by the toolCallId.\n */\n onStepFinish?: (\n event: StepResult<typeof TOOLS>,\n toolCallMessages: ToolCallMessage[],\n ) => Promise<void> | void;\n\n /** Maximum number of analysis steps allowed (default: 100) */\n maxSteps?: number;\n\n /**\n * Callback for handling streaming results\n * @param message - Current message content being streamed\n * @param isCompleted - Indicates if this is the final message in the stream\n */\n onStreamResult: (message: string, isCompleted: boolean) => void;\n};\n\n/**\n * Executes an AI analysis session on the project data\n *\n * @param config - Analysis configuration options. See {@link AnalysisConfig} for more details.\n * @returns Object containing tool calls executed and the final analysis result\n */\nexport async function runAnalysis({\n name = 'sqlrooms-ai',\n modelProvider,\n model,\n apiKey,\n prompt,\n abortController,\n onStepFinish,\n onStreamResult,\n maxSteps = 5,\n}: AnalysisConfig) {\n const tablesSchema = await getDuckTableSchemas();\n\n // get the singlton assistant instance\n const assistant = await createAssistant({\n name,\n modelProvider,\n model,\n apiKey,\n version: 'v1',\n instructions: `${SYSTEM_PROMPT}\\n${JSON.stringify(tablesSchema)}`,\n vercelFunctions: TOOLS,\n temperature: 0,\n toolChoice: 'auto', // this will enable streaming\n maxSteps,\n ...(abortController ? {abortController} : {}),\n });\n\n // process the prompt\n const result = await assistant.processTextMessage({\n textMessage: prompt,\n streamMessageCallback: (message) => {\n // the final result (before the answer) can be streamed back here\n onStreamResult(message.deltaMessage, message.isCompleted ?? false);\n },\n onStepFinish,\n });\n\n return result;\n}\n\n/**\n * Extracts a readable error message from an error object\n * @param error - Error object or unknown value\n * @returns Formatted error message string\n */\nfunction getErrorMessage(error: unknown): string {\n if (error instanceof Error) {\n if (error.cause instanceof Error) {\n return error.cause.message;\n }\n return error.message;\n }\n return String(error);\n}\n\n/**\n * Collection of tools available to the AI assistant for data analysis\n * Includes:\n * - query: Executes SQL queries against DuckDB\n * - chart: Creates VegaLite visualizations\n */\nconst TOOLS: VercelToolSet = {\n query: {\n description: `A tool for executing SQL queries in DuckDB that is embedded in browser using duckdb-wasm.\nQuery results are returned as a json object \"{success: boolean, data: object[], error?: string}\"\nPlease only analyze tables which are in the main schema.\nTo obtain stats, use the \"SUMMARIZE table_name\" query.\nDon't execute queries that modify data unless explicitly asked.`,\n parameters: QueryToolParameters,\n executeWithContext: async (props: CallbackFunctionProps) => {\n if (!isQueryToolParameters(props.functionArgs)) {\n return {\n name: 'query',\n result: {\n success: false,\n error: 'Invalid query parameters',\n },\n };\n }\n\n const {type, sqlQuery} = props.functionArgs;\n try {\n const {conn} = await getDuckDb();\n // TODO use options.abortSignal: maybe call db.cancelPendingQuery\n const result = await conn.query(sqlQuery);\n // Only get summary if the query isn't already a SUMMARIZE query\n const summaryData = sqlQuery.toLowerCase().includes('summarize')\n ? arrowTableToJson(result)\n : await getQuerySummary(conn, sqlQuery);\n\n // Get first 2 rows of the result as a json object\n const subResult = result.slice(0, 2);\n const firstTwoRows = arrowTableToJson(subResult);\n\n // create result object sent back to LLM for tool call\n const llmResult = {\n type,\n success: true,\n data: {\n // only summary and first two rows will be sent back to LLM as context\n summary: summaryData,\n firstTwoRows,\n },\n };\n\n // data object of the raw query result, which is NOT sent back to LLM\n // we can use it to visualize the arrow table in the callback function `message()` below\n const data = {sqlQuery};\n\n return {\n name: 'query',\n result: llmResult,\n data,\n };\n } catch (error) {\n return {\n name: 'query',\n result: {\n success: false,\n description:\n 'Failed to execute the query. Please stop tool call and return error message.',\n error: getErrorMessage(error),\n },\n };\n }\n },\n message: queryMessage,\n },\n\n chart: {\n description: `A tool for creating VegaLite charts based on the schema of the SQL query result from the \"query\" tool.\nIn the response:\n- omit the data from the vegaLiteSpec\n- provide an sql query in sqlQuery instead.`,\n parameters: ChartToolParameters,\n executeWithContext: async (props: CallbackFunctionProps) => {\n if (!isChartToolParameters(props.functionArgs)) {\n return {\n name: 'chart',\n result: {\n success: false,\n error: 'Invalid chart parameters',\n },\n };\n }\n const {sqlQuery, vegaLiteSpec} = props.functionArgs;\n const llmResult = {\n success: true,\n details: 'Chart created successfully.',\n };\n\n // data object of the vegaLiteSpec and sqlQuery\n // it is not used yet, but we can use it to create a JSON editor for user to edit the vegaLiteSpec so that chart can be updated\n const data = {\n sqlQuery,\n vegaLiteSpec,\n };\n\n return {\n name: 'chart',\n result: llmResult,\n data,\n };\n },\n },\n\n // answer tool: the LLM will provide a structured answer\n // answer: {\n // description: 'A tool for providing the final answer.',\n // parameters: AnswerToolParameters,\n // executeWithContext: async (props: CallbackFunctionProps) => {\n // const {answer} = props.functionArgs;\n // return {\n // name: 'answer',\n // result: {\n // success: true,\n // data: answer,\n // },\n // };\n // },\n // },\n};\n"]}
1
+ {"version":3,"file":"analysis.js","sourceRoot":"","sources":["../src/analysis.ts"],"names":[],"mappings":"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","sourcesContent":["import * as duckdb from '@duckdb/duckdb-wasm';\nimport {\n createAssistant,\n rebuildMessages,\n StreamMessage,\n tool,\n} from '@openassistant/core';\nimport {\n arrowTableToJson,\n DataTable,\n DuckQueryError,\n getDuckDb,\n getDuckTableSchemas,\n} from '@sqlrooms/duckdb';\n\nimport {QueryToolResult} from './components/tools/QueryToolResult';\nimport {AnalysisResultSchema, QueryToolParameters} from './schemas';\nimport {AiSliceTool} from './AiSlice';\n\n/**\n * System prompt template for the AI assistant that provides instructions for:\n * - Using DuckDB-specific SQL syntax and functions\n * - Handling query results and error cases\n * - Creating visualizations with VegaLite\n * - Formatting final answers\n */\nconst DEFAULT_INSTRUCTIONS = `\nYou are analyzing tables in DuckDB database in the context of a project.\n\nInstructions for analysis:\n- Use DuckDB-specific SQL syntax and functions (not Oracle, PostgreSQL, or other SQL dialects)\n- Some key DuckDB-specific functions to use:\n * regexp_matches() for regex (not regexp_like)\n * strftime() for date formatting (not to_char)\n * list_aggregate() for array operations\n * unnest() for array expansion\n * regr_sxy()\n * corr()\n * skewness()\n- Please always try to use SQL queries to answer users questions\n- Please run tool calls sequentially, don't run multiple tool calls in parallel\n- IMPORTANT: Do not list out raw query results in your response. Instead:\n * Describe the results in natural language\n * Provide summary statistics\n * Use comparisons and relative terms\n * Include only the most relevant values if necessary\n- Break down complex problems into smaller steps\n- Use \"SUMMARIZE table_name\"for quick overview of the table\n- Please don't modify data\n- IMPORTANT: When you receive an error response from a tool call (where success: false):\n * Stop making any further tool calls immediately\n * Return a final answer that includes the error message\n * Explain what went wrong and suggest possible fixes if applicable\n\nWhen creating visualizations:\n- Follow VegaLite syntax\n- Choose appropriate chart types based on the data and analysis goals\n- Use clear titles and axis labels\n- Consider color schemes for better readability\n- Add meaningful tooltips when relevant\n- Format numbers and dates appropriately\n- Use aggregations when dealing with large datasets\n\nFor your final answer:\n- Provide an explanation for how you got it\n- Explain your reasoning step by step\n- Include relevant statistics or metrics\n- For each prompt, please always provide the final answer.\n\nPlease use the following schema for the tables:\n`;\n\n/**\n * Returns the default system instructions for the AI assistant\n */\nexport function getDefaultInstructions(tablesSchema: DataTable[]): string {\n return `${DEFAULT_INSTRUCTIONS}\\n${JSON.stringify(tablesSchema)}`;\n}\n\n/**\n * Generates summary statistics for a SQL query result\n * @param conn - DuckDB connection instance\n * @param sqlQuery - SQL SELECT query to analyze\n * @returns Summary statistics as JSON object, or null if the query is not a SELECT statement or if summary generation fails\n */\nasync function getQuerySummary(\n conn: duckdb.AsyncDuckDBConnection,\n sqlQuery: string,\n) {\n if (!sqlQuery.toLowerCase().trim().startsWith('select')) {\n return null;\n }\n\n try {\n const viewName = `temp_result_${Date.now()}`; // unique view name to avoid conflicts\n await conn.query(`CREATE TEMPORARY VIEW ${viewName} AS ${sqlQuery}`);\n const summaryResult = await conn.query(`SUMMARIZE ${viewName}`);\n const summaryData = arrowTableToJson(summaryResult);\n await conn.query(`DROP VIEW IF EXISTS ${viewName}`);\n return summaryData;\n } catch (error) {\n console.warn('Failed to get summary:', error);\n return null;\n }\n}\n\n/**\n * Configuration options for running an AI analysis session\n */\nexport type AnalysisConfig = {\n /** Assistant instance identifier (default: 'sqlrooms-ai') */\n name?: string;\n\n /** AI model provider (e.g., 'openai', 'anthropic') */\n modelProvider: string;\n\n /** Model identifier (e.g., 'gpt-4', 'claude-3') */\n model: string;\n\n /** Authentication key for the model provider's API */\n apiKey: string;\n\n /** Analysis prompt or question to be processed */\n prompt: string;\n\n /** Optional controller for canceling the analysis operation */\n abortController?: AbortController;\n\n /** Maximum number of analysis steps allowed (default: 100) */\n maxSteps?: number;\n\n /** The history of analysis results (e.g. saved in localStorage) */\n historyAnalysis?: AnalysisResultSchema[];\n\n /** Tools to use in the analysis */\n tools?: Record<string, AiSliceTool>;\n\n /**\n * Function to get custom instructions for the AI assistant\n * @param tablesSchema - The schema of the tables in the database\n * @returns The instructions string to use\n */\n getInstructions?: (tablesSchema: DataTable[]) => string;\n\n /**\n * Callback for handling streaming results\n * @param isCompleted - Indicates if this is the final message in the stream\n * @param streamMessage - Current message content being streamed\n */\n onStreamResult: (isCompleted: boolean, streamMessage?: StreamMessage) => void;\n};\n\n/**\n * Executes an AI analysis session on the project data\n *\n * @param config - Analysis configuration options. See {@link AnalysisConfig} for more details.\n * @returns Object containing tool calls executed and the final analysis result\n */\nexport async function runAnalysis({\n name = 'sqlrooms-ai',\n modelProvider,\n model,\n apiKey,\n prompt,\n abortController,\n historyAnalysis,\n onStreamResult,\n maxSteps = 5,\n tools = {},\n getInstructions,\n}: AnalysisConfig) {\n const tablesSchema = await getDuckTableSchemas();\n\n // get the singleton assistant instance\n const assistant = await createAssistant({\n name,\n modelProvider,\n model,\n apiKey,\n version: 'v1',\n instructions: getInstructions\n ? getInstructions(tablesSchema)\n : getDefaultInstructions(tablesSchema),\n functions: tools,\n temperature: 0,\n toolChoice: 'auto', // this will enable streaming\n maxSteps,\n ...(abortController ? {abortController} : {}),\n });\n\n // restore ai messages from historyAnalysis?\n if (historyAnalysis) {\n const historyMessages = historyAnalysis.map((analysis) => ({\n prompt: analysis.prompt,\n response: analysis.streamMessage,\n }));\n const initialMessages = rebuildMessages(historyMessages);\n assistant.setMessages(initialMessages);\n }\n\n // process the prompt\n const newMessages = await assistant.processTextMessage({\n textMessage: prompt,\n streamMessageCallback: ({isCompleted, message}) => {\n onStreamResult(isCompleted ?? false, message);\n },\n });\n\n return newMessages;\n}\n\n/**\n * Default tools available to the AI assistant for data analysis\n * Includes:\n * - query: Executes SQL queries against DuckDB\n */\nexport function getDefaultTools(): Record<string, AiSliceTool> {\n return {\n query: tool({\n description: `A tool for running SQL queries on the tables in the database.\nPlease only run one query at a time.\nIf a query fails, please don't try to run it again with the same syntax.`,\n parameters: QueryToolParameters,\n // TODO: specify the return type e.g. Promise<Partial<ToolCallMessage>>\n execute: async ({type, sqlQuery}) => {\n try {\n const {conn} = await getDuckDb();\n // TODO use options.abortSignal: maybe call db.cancelPendingQuery\n const result = await conn.query(sqlQuery);\n // Only get summary if the query isn't already a SUMMARIZE query\n const summaryData = sqlQuery.toLowerCase().includes('summarize')\n ? arrowTableToJson(result)\n : await getQuerySummary(conn, sqlQuery);\n\n // Get first 2 rows of the result as a json object\n const subResult = result.slice(0, 2);\n const firstTwoRows = arrowTableToJson(subResult);\n\n return {\n llmResult: {\n success: true,\n data: {\n type,\n summary: summaryData,\n firstTwoRows,\n },\n },\n additionalData: {\n title: 'Query Result',\n sqlQuery,\n },\n };\n } catch (error) {\n return {\n llmResult: {\n success: false,\n details: 'Query execution failed.',\n errorMessage:\n error instanceof DuckQueryError\n ? error.getMessageForUser()\n : error instanceof Error\n ? error.message\n : 'Unknown error',\n },\n };\n }\n },\n component: QueryToolResult,\n }),\n };\n}\n\nexport const TOOLS = getDefaultTools();\n"]}
@@ -0,0 +1,14 @@
1
+ import React from 'react';
2
+ type AnalysisAnswerProps = {
3
+ content: string;
4
+ isAnswer: boolean;
5
+ };
6
+ /**
7
+ * Renders an analysis answer with markdown content of the final streaming response.
8
+ *
9
+ * @param {AnalysisAnswerProps} props - The component props. See {@link AnalysisAnswerProps} for more details.
10
+ * @returns {JSX.Element} The rendered answer tool call
11
+ */
12
+ export declare const AnalysisAnswer: React.NamedExoticComponent<AnalysisAnswerProps>;
13
+ export {};
14
+ //# sourceMappingURL=AnalysisAnswer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AnalysisAnswer.d.ts","sourceRoot":"","sources":["../../src/components/AnalysisAnswer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,KAAK,mBAAmB,GAAG;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,cAAc,iDAgBzB,CAAC"}
@@ -0,0 +1,14 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import React from 'react';
3
+ import Markdown from 'react-markdown';
4
+ import { MessageContainer } from './MessageContainer';
5
+ /**
6
+ * Renders an analysis answer with markdown content of the final streaming response.
7
+ *
8
+ * @param {AnalysisAnswerProps} props - The component props. See {@link AnalysisAnswerProps} for more details.
9
+ * @returns {JSX.Element} The rendered answer tool call
10
+ */
11
+ export const AnalysisAnswer = React.memo(function AnalysisAnswer(props) {
12
+ return (_jsx("div", { className: "flex flex-col gap-5", children: _jsx(MessageContainer, { isSuccess: true, type: props.isAnswer ? 'answer' : 'thinking', content: props, children: _jsx(Markdown, { className: "prose dark:prose-invert max-w-none text-sm", children: props.content }) }) }));
13
+ });
14
+ //# sourceMappingURL=AnalysisAnswer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AnalysisAnswer.js","sourceRoot":"","sources":["../../src/components/AnalysisAnswer.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AACtC,OAAO,EAAC,gBAAgB,EAAC,MAAM,oBAAoB,CAAC;AAOpD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,cAAc,CAC9D,KAA0B;IAE1B,OAAO,CACL,cAAK,SAAS,EAAC,qBAAqB,YAClC,KAAC,gBAAgB,IACf,SAAS,EAAE,IAAI,EACf,IAAI,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,EAC5C,OAAO,EAAE,KAAK,YAEd,KAAC,QAAQ,IAAC,SAAS,EAAC,4CAA4C,YAC7D,KAAK,CAAC,OAAO,GACL,GACM,GACf,CACP,CAAC;AACJ,CAAC,CAAC,CAAC","sourcesContent":["import React from 'react';\nimport Markdown from 'react-markdown';\nimport {MessageContainer} from './MessageContainer';\n\ntype AnalysisAnswerProps = {\n content: string;\n isAnswer: boolean;\n};\n\n/**\n * Renders an analysis answer with markdown content of the final streaming response.\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 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 <Markdown className=\"prose dark:prose-invert max-w-none text-sm\">\n {props.content}\n </Markdown>\n </MessageContainer>\n </div>\n );\n});\n"]}
@@ -1,10 +1,11 @@
1
- import { AnalysisResultSchema } from './schemas';
1
+ import { AnalysisResultSchema } from '../schemas';
2
2
  /**
3
3
  * Props for the AnalysisResult component
4
4
  * @property {AnalysisResultSchema} result - The result of the analysis containing prompt, tool calls, and analysis data
5
5
  */
6
6
  type AnalysisResultProps = {
7
7
  result: AnalysisResultSchema;
8
+ onDeleteAnalysisResult: (id: string) => void;
8
9
  };
9
10
  /**
10
11
  * Component that displays the results of an AI analysis.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AnalysisResult.d.ts","sourceRoot":"","sources":["../../src/components/AnalysisResult.tsx"],"names":[],"mappings":"AAeA,OAAO,EAAC,oBAAoB,EAAC,MAAM,YAAY,CAAC;AAKhD;;;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,CAgHxD,CAAC"}
@@ -0,0 +1,46 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { JsonMonacoEditor } from '@sqlrooms/monaco-editor';
3
+ import { Button, Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, Popover, PopoverContent, PopoverTrigger, } from '@sqlrooms/ui';
4
+ import { CodeIcon, SquareTerminalIcon, TrashIcon } from 'lucide-react';
5
+ import { useState } from 'react';
6
+ import { AnalysisAnswer } from './AnalysisAnswer';
7
+ import { ErrorMessage } from './ErrorMessage';
8
+ import { ToolResult } from './tools/ToolResult';
9
+ /**
10
+ * Stringify the result of the analysis, excluding toolCallMessages.
11
+ * Used to display raw result data in a code view.
12
+ *
13
+ * @param result - The complete analysis result
14
+ * @returns A JSON string representation of the result without toolCallMessages
15
+ */
16
+ const stringifyResult = (result) => {
17
+ return JSON.stringify(result, null, 2);
18
+ };
19
+ /**
20
+ * Component that displays the results of an AI analysis.
21
+ * Shows the original prompt, intermediate tool calls, final analysis text,
22
+ * and any tool results.
23
+ *
24
+ * @component
25
+ * @param props - Component props
26
+ * @param props.result - The analysis result data to display
27
+ * @returns A React component displaying the analysis results
28
+ */
29
+ export const AnalysisResult = ({ result, onDeleteAnalysisResult, }) => {
30
+ // the toolResults are reasoning steps that the LLM took to achieve the final result
31
+ // by calling function tools to answer the prompt
32
+ const { id, prompt, errorMessage, streamMessage } = result;
33
+ const [showDeleteConfirmation, setShowDeleteConfirmation] = useState(false);
34
+ return (_jsxs("div", { className: "group flex w-full flex-col gap-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: "flex w-full items-center gap-2 rounded-md border p-4 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: [_jsxs(Popover, { children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx(Button, { variant: "ghost", size: "icon", className: "h-6 w-6", children: _jsx(CodeIcon, { className: "h-4 w-4" }) }) }), _jsx(PopoverContent, { className: "max-h-[400px] w-[400px] overflow-auto", align: "end", side: "right", children: _jsx(JsonMonacoEditor, { value: stringifyResult(result), readOnly: true, className: "h-[300px]", options: {
35
+ minimap: { enabled: false },
36
+ scrollBeyondLastLine: false,
37
+ automaticLayout: true,
38
+ folding: true,
39
+ lineNumbers: false,
40
+ wordWrap: 'on',
41
+ } }) })] }), _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: () => {
42
+ onDeleteAnalysisResult(id);
43
+ setShowDeleteConfirmation(false);
44
+ }, children: "Delete" })] })] }) })] })] }) }), streamMessage.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' && (_jsx("div", { children: part.toolCallMessages.map((toolCallMessage) => (_jsx(ToolResult, { toolCallMessage: toolCallMessage }, toolCallMessage.toolCallId))) }))] }, index))), errorMessage && _jsx(ErrorMessage, { errorMessage: errorMessage.error })] }));
45
+ };
46
+ //# 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 {JsonMonacoEditor} from '@sqlrooms/monaco-editor';\nimport {\n Button,\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from '@sqlrooms/ui';\nimport {CodeIcon, SquareTerminalIcon, TrashIcon} from 'lucide-react';\nimport {useState} from 'react';\nimport {AnalysisResultSchema} from '../schemas';\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 [showDeleteConfirmation, setShowDeleteConfirmation] = useState(false);\n\n return (\n <div className=\"group flex w-full flex-col gap-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=\"flex w-full items-center gap-2 rounded-md border p-4 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 <Popover>\n <PopoverTrigger asChild>\n <Button variant=\"ghost\" size=\"icon\" className=\"h-6 w-6\">\n <CodeIcon className=\"h-4 w-4\" />\n </Button>\n </PopoverTrigger>\n <PopoverContent\n className=\"max-h-[400px] w-[400px] overflow-auto\"\n align=\"end\"\n side=\"right\"\n >\n <JsonMonacoEditor\n value={stringifyResult(result)}\n readOnly={true}\n className=\"h-[300px]\"\n options={{\n minimap: {enabled: false},\n scrollBeyondLastLine: false,\n automaticLayout: true,\n folding: true,\n lineNumbers: false,\n wordWrap: 'on',\n }}\n />\n </PopoverContent>\n </Popover>\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 {streamMessage.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' && (\n <div>\n {part.toolCallMessages.map((toolCallMessage) => (\n <ToolResult\n key={toolCallMessage.toolCallId}\n toolCallMessage={toolCallMessage}\n />\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,5 @@
1
+ import React from 'react';
2
+ export declare const AnalysisResultsContainer: React.FC<{
3
+ className?: string;
4
+ }>;
5
+ //# sourceMappingURL=AnalysisResultsContainer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AnalysisResultsContainer.d.ts","sourceRoot":"","sources":["../../src/components/AnalysisResultsContainer.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAwB,MAAM,OAAO,CAAC;AAM7C,eAAO,MAAM,wBAAwB,EAAE,KAAK,CAAC,EAAE,CAAC;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAkDA,CAAC"}
@@ -0,0 +1,27 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { cn, SkeletonPane } from '@sqlrooms/ui';
4
+ import { ChevronDown } from 'lucide-react';
5
+ import { useRef } from 'react';
6
+ import { useStoreWithAi } from '../AiSlice';
7
+ import { AnalysisResult } from './AnalysisResult';
8
+ import { useScrollToBottom } from '../hooks/useScrollToBottom';
9
+ export const AnalysisResultsContainer = ({ className }) => {
10
+ const isRunningAnalysis = useStoreWithAi((s) => s.ai.isRunningAnalysis);
11
+ const currentSession = useStoreWithAi((s) => s.ai.getCurrentSession());
12
+ const deleteAnalysisResult = useStoreWithAi((s) => s.ai.deleteAnalysisResult);
13
+ const containerRef = useRef(null);
14
+ const endRef = useRef(null);
15
+ const { showScrollButton, scrollToBottom } = useScrollToBottom({
16
+ containerRef,
17
+ endRef,
18
+ dataToObserve: currentSession?.analysisResults,
19
+ });
20
+ const onDeleteAnalysisResult = (id) => {
21
+ if (currentSession) {
22
+ deleteAnalysisResult(currentSession.id, id);
23
+ }
24
+ };
25
+ return (_jsxs("div", { className: cn('relative flex h-full w-full flex-col', className), children: [_jsxs("div", { ref: containerRef, className: "flex w-full flex-grow flex-col gap-5 overflow-auto", 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("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" }) }) })] }));
26
+ };
27
+ //# sourceMappingURL=AnalysisResultsContainer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AnalysisResultsContainer.js","sourceRoot":"","sources":["../../src/components/AnalysisResultsContainer.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AACb,OAAO,EAAC,EAAE,EAAE,YAAY,EAAC,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAC,WAAW,EAAC,MAAM,cAAc,CAAC;AACzC,OAAc,EAAU,MAAM,EAAC,MAAM,OAAO,CAAC;AAC7C,OAAO,EAAC,cAAc,EAAC,MAAM,YAAY,CAAC;AAE1C,OAAO,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAC,iBAAiB,EAAC,MAAM,4BAA4B,CAAC;AAE7D,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,eACE,GAAG,EAAE,YAAY,EACjB,SAAS,EAAC,oDAAoD,aAE7D,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,IACjD,EACN,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":["'use client';\nimport {cn, SkeletonPane} from '@sqlrooms/ui';\nimport {ChevronDown} from 'lucide-react';\nimport React, {useMemo, useRef} from 'react';\nimport {useStoreWithAi} from '../AiSlice';\nimport {TOOLS} from '../analysis';\nimport {AnalysisResult} from './AnalysisResult';\nimport {useScrollToBottom} from '../hooks/useScrollToBottom';\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 <div\n ref={containerRef}\n className=\"flex w-full flex-grow flex-col gap-5 overflow-auto\"\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 </div>\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,4 @@
1
+ export declare function ErrorMessage(props: {
2
+ errorMessage: string;
3
+ }): import("react/jsx-runtime").JSX.Element;
4
+ //# sourceMappingURL=ErrorMessage.d.ts.map