Skip to content

Commit c01b08e

Browse files
Merge branch 'ai-operations' of github.com:quadratichq/quadratic into table-code
2 parents 7ac30a3 + ef5483c commit c01b08e

File tree

284 files changed

+10943
-2673
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

284 files changed

+10943
-2673
lines changed

DEVELOPMENT.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,3 +300,21 @@ This is only required if the `quadratic-community` Auth0 account does not work.
300300
- Allowed Logout URLs: `http://localhost:3000`
301301
- Allowed Web Origins: `http://localhost:3000`
302302
- Allowed Origins (CORS): `http://localhost:3000`
303+
304+
## How to Add AI Tools
305+
306+
1. run `node dev -cas` - you need at least API and Shared to recompile (and probably need core, as there may need to be changes)
307+
308+
2. update `quadraticShared/../aiToolsSpec.ts` for the new tool:
309+
- AITool enum (the name of the tool)
310+
- AIToolSchema (list of tools)
311+
- AIToolsArgsSchema (the zod parameters)
312+
- aiToolsSpec (the actual tool and prompt definition)
313+
314+
3. create a ToolCard in `quadraticClient/../toolCards/`
315+
316+
4. add new ToolCard to `quadraticClient/../AIToolCard.tsx`
317+
318+
5. add the action to `quadraticClient/../aiToolsActions.ts`
319+
320+
Note: you may need to restart node dev occasionally if it doesn't pick up your changes.
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
export const A1Docs = `# A1 Docs
2+
3+
Cell references in Quadratic are in A1 notation.
4+
5+
## Rectangular Ranges
6+
7+
Rectangular ranges are references to a range of cells in a sheet. They are referenced by the top left cell and the bottom right cell. For example, A1:C3 is a rectangular range that references the cells A1, B1, C1, A2, B2, C2, A3, B3, and C3.
8+
9+
### Rectangular Range Examples
10+
11+
- D5 - references the cell D5
12+
- A1:C3 - references the cells A1, B1, C1, A2, B2, C2, A3, B3, and C3
13+
- A1:A3 - references the cells A1, A2, and A3
14+
- A1:C1 - references the cells A1, B1, and C1
15+
16+
## Column and Row References
17+
18+
In A1 notation, when referencing an entire column or row, use the column or row name(s).
19+
20+
### Column and Row Examples
21+
22+
- B - references the entire column B
23+
- B3:B - references all rows in column B starting from row 3
24+
- 10 - references the entire row 10
25+
- C4:C - references all columns in row C starting from row 4
26+
- D2:2 - references all columns in row 2 starting from column D
27+
28+
## Table References
29+
30+
**PREFERRED**: Always use table names (e.g., Table_Name) when working with entire tables or entire columns within tables. Use A1 notation only for non-table data or partial table selections.
31+
32+
Columns within tables may be referenced by their name in A1 notation, eg, Table1[Column Name]. To reference multiple columns within a table, you use Table1[[Name]:[Address]]. In tables, you can also reference parts of the table. If you only want the table names, you can reference it with Table1[#HEADERS]. If you want the data and the headers, you would use Table1[[#DATA],[#HEADERS]]. By default, tables are referenced as Table1[#DATA].
33+
34+
If you need individual cells within a table, you need to use normal A1 reference. For example, if you want the first row of a table, you would reference it using its corresponding A1 reference. Remember that tables usually include a name row as the first row, and a column header row as the second row. (Although these may sometimes be hidden.)
35+
36+
### Table Examples
37+
38+
- Table1 - references the entire table's data
39+
- Table1[#HEADERS] - references the table headers
40+
- Table1[[#DATA],[#HEADERS]] - references the entire table including the headers
41+
- Table1[Column 2] - references a single column within Table1
42+
- Table1[[Name]:[Address]] - references a range of columns
43+
44+
## Multiple Ranges
45+
46+
You can reference multiple ranges by combining ranges with commas.
47+
48+
### Multiple Range Examples
49+
50+
- A1:C3,D5:F7
51+
- A1:C3,D5:F7,G9:I11
52+
- Table1[Column 2], A1:C3
53+
54+
## Other Sheets
55+
56+
You can reference cells in other sheets by using the sheet name as part of the reference. Note, table names do not need sheet names as table names are unique within the file.
57+
58+
### Other Sheet Examples
59+
60+
- Sheet1!A1:C3
61+
- Sheet1!A1:C3,Sheet2!D5:F7
62+
- Sheet1!A1:C3,Sheet2!D5:F7,Sheet3!G9:I11
63+
- Table1[Column 2],Sheet2!A1:C3
64+
65+
66+
67+
`;

quadratic-api/src/ai/docs/QuadraticDocs.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ Quadratic combines a familiar spreadsheet and formulas with the power of AI and
66
77
Files can be imported by drag and dropping into the sheet, those supported file types are: csv, excel, parquet. SQL can be used to connect to databases. Once in the sheet, data can be analyzed with coding languages and AI.
88
9-
Data can be exported by following these steps: 1. highlight the data 2. right-click the highlighted data 3. select export to csv
9+
Data can be exported by following these steps: 1. highlight the data 2. right-click the highlighted data 3. select export to csv
1010
11-
Files can be shared with other users by selecting the share button in the top right. Quadratic .grid files can be download from the file menu.
11+
Files can be shared with other users by selecting the share button in the top right. Quadratic .grid files can be download from the file menu.
1212
1313
Code is inserted via AI or by pressing / while in a cell to open the code selection menu. Code cells can be re-opened to view and edit the code by double clicking or pressing / when selected.
1414
@@ -19,4 +19,5 @@ Quadratic cells can be formatted from the toolbar options or by AI, but not via
1919
Quadratic uses tables commonly to structure data. IMPORTANT: tables do not support Formulas or Code but will in the future. You cannot place Code or Formulas inside of tables.
2020
2121
Code generated in Quadratic is not global to other code cells. The data the code cell outputs to the sheet can be referenced by other cells, but variables in one code cell cannot be read in another. Imports in one code cell do not automatically apply to other code cells.
22-
`;
22+
23+
Code, data tables, and charts may take up more than one cell on the sheet. When they expand, they may overlap existing content, either directly on the sheet or in other code, table, or chart cells. If this happens, it is called a spill. To fix a spill, use the move_cells tool to move the anchor cell of the table to a different position. Ensure that the position has sufficient space to accommodate the entire range without creating another spill. Ideally, leave a space between the new position and any surrounding content.`;
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
export const ValidationDocs = `
2+
# Validations
3+
4+
## Overview
5+
6+
Validations are used to both verify that cells have allowable data, and to provide messages to the user when they enter a cell.
7+
8+
## How validations are stored
9+
10+
Validations are set per sheet so you cannot add a selection from another sheet to a validation in a different sheet.
11+
12+
## One validation per cell
13+
14+
Each cell can only have one validation. If you add a validation to a range then any validations that overlap with the new validation will be removed. The algorithm either changes the selection to remove the overlap, or, if the selection becomes empty, removes the validation.
15+
16+
## Messages and errors
17+
18+
Adding a message to validations will show the message when the user enters the cell with the cursor. An error will show when the user either enters the cell or hovers over it with the cursor.
19+
20+
## Purpose of validations
21+
22+
You can use validations to create checkboxes and dropdown lists, as well as to add messages or errors to the user when they enter a cell. They make the user experience more interactive and engaging.`;

quadratic-api/src/ai/handler/anthropic.handler.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,12 @@ export const handleAnthropicRequest = async (
2727
): Promise<ParsedAIResponse | undefined> => {
2828
const model = getModelFromModelKey(modelKey);
2929
const options = getModelOptions(modelKey, args);
30-
const { system, messages, tools, tool_choice } = getAnthropicApiArgs(args, options.promptCaching, options.thinking);
30+
const { system, messages, tools, tool_choice } = getAnthropicApiArgs(
31+
args,
32+
options.aiModelMode,
33+
options.promptCaching,
34+
options.thinking
35+
);
3136

3237
const thinking: ThinkingConfigParam = options.thinking
3338
? {

quadratic-api/src/ai/handler/bedrock.handler.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export const handleBedrockRequest = async (
1515
): Promise<ParsedAIResponse | undefined> => {
1616
const model = getModelFromModelKey(modelKey);
1717
const options = getModelOptions(modelKey, args);
18-
const { system, messages, tools, tool_choice } = getBedrockApiArgs(args);
18+
const { system, messages, tools, tool_choice } = getBedrockApiArgs(args, options.aiModelMode);
1919

2020
const apiArgs: ConverseStreamRequest | ConverseRequest = {
2121
modelId: model,

quadratic-api/src/ai/handler/genai.handler.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export const handleGenAIRequest = async (
1919
): Promise<ParsedAIResponse | undefined> => {
2020
const model = getModelFromModelKey(modelKey);
2121
const options = getModelOptions(modelKey, args);
22-
const { system, messages, tools, tool_choice } = getGenAIApiArgs(args);
22+
const { system, messages, tools, tool_choice } = getGenAIApiArgs(args, options.aiModelMode);
2323

2424
const apiArgs: GenerateContentParameters = {
2525
model,

quadratic-api/src/ai/handler/openai.handler.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,12 @@ export const handleOpenAIRequest = async (
2323
): Promise<ParsedAIResponse | undefined> => {
2424
const model = getModelFromModelKey(modelKey);
2525
const options = getModelOptions(modelKey, args);
26-
const { messages, tools, tool_choice } = getOpenAIApiArgs(args, options.strictParams, options.imageSupport);
26+
const { messages, tools, tool_choice } = getOpenAIApiArgs(
27+
args,
28+
options.aiModelMode,
29+
options.strictParams,
30+
options.imageSupport
31+
);
2732

2833
let apiArgs: ChatCompletionCreateParamsStreaming | ChatCompletionCreateParamsNonStreaming = {
2934
model,

quadratic-api/src/ai/helpers/anthropic.helper.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import type {
2828
AnthropicModelKey,
2929
BedrockAnthropicModelKey,
3030
Content,
31+
ModelMode,
3132
ParsedAIResponse,
3233
ToolResultContent,
3334
VertexAIAnthropicModelKey,
@@ -105,6 +106,7 @@ function convertToolResultContent(content: ToolResultContent): Array<TextBlockPa
105106

106107
export function getAnthropicApiArgs(
107108
args: AIRequestHelperArgs,
109+
aiModelMode: ModelMode,
108110
promptCaching: boolean,
109111
thinking: boolean | undefined
110112
): {
@@ -161,7 +163,7 @@ export function getAnthropicApiArgs(
161163
type: 'tool_use' as const,
162164
id: toolCall.id,
163165
name: toolCall.name,
164-
input: JSON.parse(toolCall.arguments),
166+
input: toolCall.arguments ? JSON.parse(toolCall.arguments) : {},
165167
})),
166168
],
167169
};
@@ -193,14 +195,17 @@ export function getAnthropicApiArgs(
193195
}
194196
}, []);
195197

196-
const tools = getAnthropicTools(source, toolName);
198+
const tools = getAnthropicTools(source, aiModelMode, toolName);
197199
const tool_choice = tools?.length ? getAnthropicToolChoice(toolName) : undefined;
198200

199201
return { system, messages, tools, tool_choice };
200202
}
201203

202-
function getAnthropicTools(source: AISource, toolName?: AITool): Tool[] | undefined {
204+
function getAnthropicTools(source: AISource, aiModelMode: ModelMode, toolName?: AITool): Tool[] | undefined {
203205
const tools = Object.entries(aiToolsSpec).filter(([name, toolSpec]) => {
206+
if (!toolSpec.aiModelModes.includes(aiModelMode)) {
207+
return false;
208+
}
204209
if (toolName === undefined) {
205210
return toolSpec.sources.includes(source);
206211
}

quadratic-api/src/ai/helpers/bedrock.helper.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import type {
3030
AIUsage,
3131
BedrockModelKey,
3232
Content,
33+
ModelMode,
3334
ParsedAIResponse,
3435
ToolResultContent,
3536
} from 'quadratic-shared/typesAndSchemasAI';
@@ -78,7 +79,10 @@ function convertToolResultContent(content: ToolResultContent): ToolResultContent
7879
});
7980
}
8081

81-
export function getBedrockApiArgs(args: AIRequestHelperArgs): {
82+
export function getBedrockApiArgs(
83+
args: AIRequestHelperArgs,
84+
aiModelMode: ModelMode
85+
): {
8286
system: SystemContentBlock[] | undefined;
8387
messages: Message[];
8488
tools: Tool[] | undefined;
@@ -104,7 +108,7 @@ export function getBedrockApiArgs(args: AIRequestHelperArgs): {
104108
toolUse: {
105109
toolUseId: toolCall.id,
106110
name: toolCall.name,
107-
input: JSON.parse(toolCall.arguments),
111+
input: toolCall.arguments ? JSON.parse(toolCall.arguments) : {},
108112
},
109113
})),
110114
],
@@ -135,14 +139,17 @@ export function getBedrockApiArgs(args: AIRequestHelperArgs): {
135139
}
136140
}, []);
137141

138-
const tools = getBedrockTools(source, toolName);
142+
const tools = getBedrockTools(source, aiModelMode, toolName);
139143
const tool_choice = tools?.length ? getBedrockToolChoice(toolName) : undefined;
140144

141145
return { system, messages, tools, tool_choice };
142146
}
143147

144-
function getBedrockTools(source: AISource, toolName?: AITool): Tool[] | undefined {
148+
function getBedrockTools(source: AISource, aiModelMode: ModelMode, toolName?: AITool): Tool[] | undefined {
145149
const tools = Object.entries(aiToolsSpec).filter(([name, toolSpec]) => {
150+
if (!toolSpec.aiModelModes.includes(aiModelMode)) {
151+
return false;
152+
}
146153
if (toolName === undefined) {
147154
return toolSpec.sources.includes(source);
148155
}

0 commit comments

Comments
 (0)