Skip to content

Commit 768ef77

Browse files
authored
Merge pull request #23 from beekeeper-studio/rc-11
Framework migration, Add Gemini & OpenAI, token limits
2 parents 377579a + 6a911ca commit 768ef77

32 files changed

+1514
-1359
lines changed

instructions.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
The current date is {current_date}.
2+
13
You are an interactive SQL assistant embedded in Beekeeper Studio. A SQL GUI and database manager used by software engineers, DBAs, and other technically skilled people.
24
Your job is to help users write, debug, and understand SQL queries based on their natural language questions, schema context, and query history.
35

@@ -26,6 +28,11 @@ Your job is to help users write, debug, and understand SQL queries based on thei
2628
* Don't comment code unless asked.
2729
* Running `SELECT` queries can be expensive, add LIMITS of 10, 100, or 1000 as needed unless explicitly asked for the full query.
2830

31+
## Synthetic Data
32+
33+
Sometimes you may see tools resulting in "User rejected tool call". These are actually messages added by the system to inform you that the user has cancelled what you were doing.
34+
35+
## Database Context
2936

3037
The information of the database you are working on is as follows:
3138

manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"id": "bks-ai-shell",
33
"name": "AI Shell",
4-
"version": "1.0.29",
4+
"version": "1.1.0",
55
"minAppVersion": "5",
66
"description": "Ask AI to analyze your database and generate SQL queries.",
77
"author": {

package.json

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,14 @@
1313
"plugin:build": "vite build && cp manifest.json dist/"
1414
},
1515
"dependencies": {
16-
"@anthropic-ai/sdk": "^0.39.0",
16+
"@ai-sdk/anthropic": "^1.2.12",
17+
"@ai-sdk/google": "^1.2.22",
18+
"@ai-sdk/openai": "^1.3.22",
19+
"@ai-sdk/vue": "^1.2.12",
1720
"@beekeeperstudio/plugin": "^1.3.0-beta",
18-
"@langchain/anthropic": "^0.3.21",
19-
"@langchain/core": "^0.3.48",
21+
"@langchain/core": "^0.3.61",
2022
"@material-symbols/font-400": "^0.31.2",
23+
"ai": "^4.3.16",
2124
"highlight.js": "^11.11.1",
2225
"langchain": "^0.3.19",
2326
"lodash": "^4.17.21",
@@ -27,7 +30,7 @@
2730
"pluralize": "^8.0.0",
2831
"typeface-roboto": "^0.0.75",
2932
"vue": "^3.4.21",
30-
"zod": "^3.22.4"
33+
"zod": "^3.25.32"
3134
},
3235
"devDependencies": {
3336
"@types/lodash": "^4.17.16",

src/App.vue

Lines changed: 66 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,38 @@
11
<template>
22
<div class="shell-app">
3-
<!-- API Key Form -->
4-
<ApiKeyForm
5-
v-if="page === 'api-key-form'"
6-
:initial-provider-id="providerId"
7-
:initial-api-key="apiKey"
8-
@submit="handleApiKeySubmit"
9-
:disabled="disabledApiKeyForm"
10-
:error="error"
11-
/>
3+
<div v-if="!appReady && showLoading" class="not-ready">
4+
<h1>AI Shell</h1>
5+
<div class="progress-bar"></div>
6+
</div>
7+
<template v-else>
8+
<!-- API Key Form -->
9+
<ApiKeyForm
10+
v-if="!apiKeyExists || page === 'api-key-form'"
11+
@submit="page = 'chat-interface'"
12+
@cancel="page = 'chat-interface'"
13+
:cancelable="apiKeyExists"
14+
/>
1215

13-
<!-- Chat Interface -->
14-
<ChatInterface
15-
v-else-if="page === 'chat-interface'"
16-
@navigate-to-api-form="page = 'api-key-form'"
17-
/>
16+
<ChatInterface
17+
v-else
18+
:initialMessages="messages"
19+
:openaiApiKey="openaiApiKey"
20+
:anthropicApiKey="anthropicApiKey"
21+
:googleApiKey="googleApiKey"
22+
@manage-models="page = 'api-key-form'"
23+
/>
24+
</template>
1825
</div>
1926
</template>
2027

21-
<script>
28+
<script lang="ts">
2229
import ApiKeyForm from "./components/ApiKeyForm.vue";
2330
import ChatInterface from "./components/ChatInterface.vue";
24-
import { useProviderStore } from "./store";
25-
import { mapState, mapActions } from "pinia";
31+
import { useChatStore } from "@/stores/chat";
32+
import { useConfigurationStore } from "@/stores/configuration";
33+
import { useInternalDataStore } from "@/stores/internalData";
34+
import { useTabState } from "@/stores/tabState";
35+
import { mapState, mapActions, mapGetters } from "pinia";
2636
2737
export default {
2838
components: {
@@ -34,52 +44,58 @@ export default {
3444
return {
3545
page: "", // Will be set in mounted based on API key availability
3646
disabledApiKeyForm: false,
37-
error: "",
47+
error: "" as unknown,
48+
appReady: false,
49+
showLoading: false,
3850
};
3951
},
4052
4153
async mounted() {
42-
await this.initializeChat();
43-
// Check if API key exists and auto-navigate to appropriate page
44-
if (this.apiKey && this.providerId) {
45-
try {
46-
await this.initializeProvider();
47-
this.page = "chat-interface";
48-
} catch (e) {
49-
// If initialization fails, go to API key form
54+
// Show loading bar after 500ms if not ready
55+
const loadingTimer = setTimeout(() => {
56+
this.showLoading = true;
57+
}, 1000);
58+
59+
try {
60+
await this.initialize();
61+
62+
const configuration = useConfigurationStore();
63+
const apiKey =
64+
configuration[`providers.${this.lastUsedProviderId}.apiKey`] ?? "";
65+
66+
// Check if API key exists and auto-navigate to appropriate page
67+
if (apiKey && this.lastUsedProviderId) {
68+
try {
69+
this.page = "chat-interface";
70+
} catch (e) {
71+
// If initialization fails, go to API key form
72+
this.page = "api-key-form";
73+
this.error = e;
74+
}
75+
} else {
5076
this.page = "api-key-form";
51-
this.error = e;
5277
}
53-
} else {
54-
this.page = "api-key-form";
78+
} finally {
79+
clearTimeout(loadingTimer);
80+
this.appReady = true;
5581
}
5682
},
5783
5884
computed: {
59-
...mapState(useProviderStore, ["providerId", "apiKey"]),
85+
...mapState(useInternalDataStore, ["lastUsedProviderId"]),
86+
...mapState(useTabState, ["messages"]),
87+
...mapState(useConfigurationStore, {
88+
openaiApiKey: "providers.openai.apiKey",
89+
anthropicApiKey: "providers.anthropic.apiKey",
90+
googleApiKey: "providers.google.apiKey",
91+
}),
92+
...mapGetters(useConfigurationStore, ["apiKeyExists"]),
6093
},
6194
6295
methods: {
63-
...mapActions(useProviderStore, [
64-
"setApiKey",
65-
"setProviderId",
66-
"initializeChat",
67-
"initializeProvider",
68-
]),
69-
async handleApiKeySubmit(data) {
70-
this.error = "";
71-
this.disabledApiKeyForm = true;
72-
await this.$nextTick()
73-
this.setApiKey(data.key);
74-
this.setProviderId(data.provider);
75-
try {
76-
await this.initializeProvider();
77-
this.page = "chat-interface";
78-
} catch (e) {
79-
this.error = e;
80-
}
81-
this.disabledApiKeyForm = false;
82-
},
96+
...mapActions(useConfigurationStore, ["configure"]),
97+
...mapActions(useInternalDataStore, ["setInternal"]),
98+
...mapActions(useChatStore, ["initialize"]),
8399
},
84100
};
85101
</script>

src/assets/styles/components/_all.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
@use "spinner";
33
@use "dropdown";
44
@use "run-query-message";
5+
@use "progress-bar";
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
.progress-bar {
2+
height: 4px;
3+
width: 100%;
4+
background: var(--border-color);
5+
position: relative;
6+
overflow: hidden;
7+
}
8+
9+
.progress-bar::before {
10+
content: '';
11+
position: absolute;
12+
top: 0;
13+
left: -100%;
14+
height: 100%;
15+
width: 100%;
16+
background: linear-gradient(90deg, transparent, var(--theme-base), transparent);
17+
animation: progress 1.5s infinite;
18+
}
19+
20+
@keyframes progress {
21+
0% { left: -100%; }
22+
100% { left: 100%; }
23+
}

src/assets/styles/main.scss

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,11 @@
1919
overflow: auto;
2020
}
2121

22+
.not-ready {
23+
width: 100%;
24+
max-width: 20rem;
25+
display: flex;
26+
flex-direction: column;
27+
align-items: center;
28+
justify-content: center;
29+
}

src/assets/styles/pages/_api-key-form.scss

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,16 @@
1717
display: flex;
1818
flex-direction: column;
1919
gap: 1rem;
20+
margin-inline: auto;
2021
margin-bottom: 1.5rem;
22+
max-width: 20rem;
23+
24+
.input-group {
25+
display: flex;
26+
gap: 0.5rem;
27+
justify-content: space-between;
28+
align-items: center;
29+
}
2130

2231
input {
2332
padding: 0.65rem 1rem;
@@ -32,10 +41,13 @@
3241
}
3342
}
3443

35-
button[type="submit"] {
36-
padding-block: 1.15rem;
37-
font-size: 0.85rem;
44+
.actions {
45+
display: flex;
46+
justify-content: center;
47+
gap: 0.5rem;
48+
}
3849

50+
button {
3951
&:disabled {
4052
opacity: 0.6;
4153
}
@@ -45,10 +57,7 @@
4557
font-size: 0.85rem;
4658
color: var(--text-dark);
4759
opacity: 0.7;
48-
49-
p {
50-
margin-bottom: 0.5rem;
51-
}
60+
margin-bottom: 0.5rem;
5261
}
5362

5463
.error-message {

0 commit comments

Comments
 (0)