Skip to content

Commit db769e0

Browse files
Merge branch 'main' into feat/improved-providers-list
2 parents ba4e788 + d4400a5 commit db769e0

File tree

18 files changed

+413
-147
lines changed

18 files changed

+413
-147
lines changed

FAQ.md

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,18 @@
22

33
# bolt.diy
44

5+
## Recommended Models for bolt.diy
6+
7+
For the best experience with bolt.diy, we recommend using the following models:
8+
9+
- **Claude 3.5 Sonnet (old)**: Best overall coder, providing excellent results across all use cases
10+
- **Gemini 2.0 Flash**: Exceptional speed while maintaining good performance
11+
- **GPT-4o**: Strong alternative to Claude 3.5 Sonnet with comparable capabilities
12+
- **DeepSeekCoder V2 236b**: Best open source model (available through OpenRouter, DeepSeek API, or self-hosted)
13+
- **Qwen 2.5 Coder 32b**: Best model for self-hosting with reasonable hardware requirements
14+
15+
**Note**: Models with less than 7b parameters typically lack the capability to properly interact with bolt!
16+
517
## FAQ
618

719
### How do I get the best results with bolt.diy?
@@ -34,14 +46,18 @@ We have seen this error a couple times and for some reason just restarting the D
3446

3547
We promise you that we are constantly testing new PRs coming into bolt.diy and the preview is core functionality, so the application is not broken! When you get a blank preview or don’t get a preview, this is generally because the LLM hallucinated bad code or incorrect commands. We are working on making this more transparent so it is obvious. Sometimes the error will appear in developer console too so check that as well.
3648

37-
### How to add a LLM:
49+
### Everything works but the results are bad
3850

39-
To make new LLMs available to use in this version of bolt.new, head on over to `app/utils/constants.ts` and find the constant MODEL_LIST. Each element in this array is an object that has the model ID for the name (get this from the provider's API documentation), a label for the frontend model dropdown, and the provider.
51+
This goes to the point above about how local LLMs are getting very powerful but you still are going to see better (sometimes much better) results with the largest LLMs like GPT-4o, Claude 3.5 Sonnet, and DeepSeek Coder V2 236b. If you are using smaller LLMs like Qwen-2.5-Coder, consider it more experimental and educational at this point. It can build smaller applications really well, which is super impressive for a local LLM, but for larger scale applications you want to use the larger LLMs still!
4052

41-
By default, Anthropic, OpenAI, Groq, and Ollama are implemented as providers, but the YouTube video for this repo covers how to extend this to work with more providers if you wish!
53+
### Received structured exception #0xc0000005: access violation
4254

43-
When you add a new model to the MODEL_LIST array, it will immediately be available to use when you run the app locally or reload it. For Ollama models, make sure you have the model installed already before trying to use it here!
55+
If you are getting this, you are probably on Windows. The fix is generally to update the [Visual C++ Redistributable](https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170)
4456

45-
### Everything works but the results are bad
57+
### How to add an LLM:
4658

47-
This goes to the point above about how local LLMs are getting very powerful but you still are going to see better (sometimes much better) results with the largest LLMs like GPT-4o, Claude 3.5 Sonnet, and DeepSeek Coder V2 236b. If you are using smaller LLMs like Qwen-2.5-Coder, consider it more experimental and educational at this point. It can build smaller applications really well, which is super impressive for a local LLM, but for larger scale applications you want to use the larger LLMs still!
59+
To make new LLMs available to use in this version of bolt.new, head on over to `app/utils/constants.ts` and find the constant MODEL_LIST. Each element in this array is an object that has the model ID for the name (get this from the provider's API documentation), a label for the frontend model dropdown, and the provider.
60+
61+
By default, many providers are already implemented, but the YouTube video for this repo covers how to extend this to work with more providers if you wish!
62+
63+
When you add a new model to the MODEL_LIST array, it will immediately be available to use when you run the app locally or reload it.

README.md

Lines changed: 31 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,32 @@
1-
[![bolt.diy: AI-Powered Full-Stack Web Development in the Browser](./public/social_preview_index.jpg)](https://bolt.diy)
2-
31
# bolt.diy (Previously oTToDev)
2+
[![bolt.diy: AI-Powered Full-Stack Web Development in the Browser](./public/social_preview_index.jpg)](https://bolt.diy)
43

54
Welcome to bolt.diy, the official open source version of Bolt.new (previously known as oTToDev and bolt.new ANY LLM), which allows you to choose the LLM that you use for each prompt! Currently, you can use OpenAI, Anthropic, Ollama, OpenRouter, Gemini, LMStudio, Mistral, xAI, HuggingFace, DeepSeek, or Groq models - and it is easily extended to use any other model supported by the Vercel AI SDK! See the instructions below for running this locally and extending it to include more models.
65

7-
Check the [bolt.diy Docs](https://stackblitz-labs.github.io/bolt.diy/) for more information. This documentation is still being updated after the transfer.
6+
Check the [bolt.diy Docs](https://stackblitz-labs.github.io/bolt.diy/) for more information.
7+
8+
We have also launched an experimental agent called the "bolt.diy Expert" that can answer common questions about bolt.diy. Find it here on the [oTTomator Live Agent Studio](https://studio.ottomator.ai/).
89

910
bolt.diy was originally started by [Cole Medin](https://www.youtube.com/@ColeMedin) but has quickly grown into a massive community effort to build the BEST open source AI coding assistant!
1011

11-
## Join the community for bolt.diy!
12+
## Table of Contents
13+
14+
- [Join the Community](#join-the-community)
15+
- [Requested Additions](#requested-additions)
16+
- [Features](#features)
17+
- [Setup](#setup)
18+
- [Run the Application](#run-the-application)
19+
- [Available Scripts](#available-scripts)
20+
- [Contributing](#contributing)
21+
- [Roadmap](#roadmap)
22+
- [FAQ](#faq)
23+
24+
## Join the community
1225

13-
https://thinktank.ottomator.ai
26+
[Join the bolt.diy community here, in the thinktank on ottomator.ai!](https://thinktank.ottomator.ai)
1427

1528

16-
## Requested Additions - Feel Free to Contribute!
29+
## Requested Additions
1730

1831
- ✅ OpenRouter Integration (@coleam00)
1932
- ✅ Gemini Integration (@jonathands)
@@ -60,7 +73,7 @@ https://thinktank.ottomator.ai
6073
- ⬜ Perplexity Integration
6174
- ⬜ Vertex AI Integration
6275

63-
## bolt.diy Features
76+
## Features
6477

6578
- **AI-powered full-stack web development** directly in your browser.
6679
- **Support for multiple LLMs** with an extensible architecture to integrate additional models.
@@ -70,7 +83,7 @@ https://thinktank.ottomator.ai
7083
- **Download projects as ZIP** for easy portability.
7184
- **Integration-ready Docker support** for a hassle-free setup.
7285

73-
## Setup bolt.diy
86+
## Setup
7487

7588
If you're new to installing software from GitHub, don't worry! If you encounter any issues, feel free to submit an "issue" using the provided links or improve this documentation by forking the repository, editing the instructions, and submitting a pull request. The following instruction will help you get the stable branch up and running on your local machine in no time.
7689

@@ -95,34 +108,6 @@ Clone the repository using Git:
95108
git clone -b stable https://github.com/stackblitz-labs/bolt.diy
96109
```
97110

98-
### (Optional) Configure Environment Variables
99-
100-
Most environment variables can be configured directly through the settings menu of the application. However, if you need to manually configure them:
101-
102-
1. Rename `.env.example` to `.env.local`.
103-
2. Add your LLM API keys. For example:
104-
105-
```env
106-
GROQ_API_KEY=YOUR_GROQ_API_KEY
107-
OPENAI_API_KEY=YOUR_OPENAI_API_KEY
108-
ANTHROPIC_API_KEY=YOUR_ANTHROPIC_API_KEY
109-
```
110-
111-
**Note**: Ollama does not require an API key as it runs locally.
112-
113-
3. Optionally, set additional configurations:
114-
115-
```env
116-
# Debugging
117-
VITE_LOG_LEVEL=debug
118-
119-
# Ollama settings (example: 8K context, localhost port 11434)
120-
OLLAMA_API_BASE_URL=http://localhost:11434
121-
DEFAULT_NUM_CTX=8192
122-
```
123-
124-
**Important**: Do not commit your `.env.local` file to version control. This file is already included in `.gitignore`.
125-
126111
---
127112

128113
## Run the Application
@@ -155,27 +140,30 @@ DEFAULT_NUM_CTX=8192
155140
156141
Use the provided NPM scripts:
157142
```bash
158-
npm run dockerbuild # Development build
159-
npm run dockerbuild:prod # Production build
143+
npm run dockerbuild
160144
```
161145
162146
Alternatively, use Docker commands directly:
163147
```bash
164-
docker build . --target bolt-ai-development # Development build
165-
docker build . --target bolt-ai-production # Production build
148+
docker build . --target bolt-ai-development
166149
```
167150
168151
2. **Run the Container**:
169152
Use Docker Compose profiles to manage environments:
170153
```bash
171-
docker-compose --profile development up # Development
172-
docker-compose --profile production up # Production
154+
docker-compose --profile development up
173155
```
174156
175157
- With the development profile, changes to your code will automatically reflect in the running container (hot reloading).
176158
177159
---
178160
161+
### Entering API Keys
162+
163+
All of your API Keys can be configured directly in the application. Just selecte the provider you want from the dropdown and click the pencile icon to enter your API key.
164+
165+
---
166+
179167
### Update Your Local Version to the Latest
180168
181169
To keep your local version of bolt.diy up to date with the latest changes, follow these steps for your operating system:
@@ -236,4 +224,4 @@ Explore upcoming features and priorities on our [Roadmap](https://roadmap.sh/r/o
236224

237225
## FAQ
238226

239-
For answers to common questions, visit our [FAQ Page](FAQ.md).
227+
For answers to common questions, issues, and to see a list of recommended models, visit our [FAQ Page](FAQ.md).

app/commit.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{ "commit": "eb6d4353565be31c6e20bfca2c5aea29e4f45b6d", "version": "0.0.3" }
1+
{ "commit": "a53b10ff399c591e898182e4b3934c26db19b6d6", "version": "0.0.3" }

app/components/chat/BaseChat.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,9 @@ export const BaseChat = React.forwardRef<HTMLDivElement, BaseChatProps>(
119119

120120
useEffect(() => {
121121
// Load API keys from cookies on component mount
122+
123+
let parsedApiKeys: Record<string, string> | undefined = {};
124+
122125
try {
123126
const storedApiKeys = Cookies.get('apiKeys');
124127

@@ -127,6 +130,7 @@ export const BaseChat = React.forwardRef<HTMLDivElement, BaseChatProps>(
127130

128131
if (typeof parsedKeys === 'object' && parsedKeys !== null) {
129132
setApiKeys(parsedKeys);
133+
parsedApiKeys = parsedKeys;
130134
}
131135
}
132136
} catch (error) {
@@ -155,7 +159,7 @@ export const BaseChat = React.forwardRef<HTMLDivElement, BaseChatProps>(
155159
Cookies.remove('providers');
156160
}
157161

158-
initializeModelList(providerSettings).then((modelList) => {
162+
initializeModelList({ apiKeys: parsedApiKeys, providerSettings }).then((modelList) => {
159163
setModelList(modelList);
160164
});
161165

app/components/settings/SettingsWindow.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ export const SettingsWindow = ({ open, onClose }: SettingsProps) => {
6363
variants={dialogBackdropVariants}
6464
/>
6565
</RadixDialog.Overlay>
66-
<RadixDialog.Content asChild>
66+
<RadixDialog.Content aria-describedby={undefined} asChild>
6767
<motion.div
6868
className="fixed top-[50%] left-[50%] z-max h-[85vh] w-[90vw] max-w-[900px] translate-x-[-50%] translate-y-[-50%] border border-bolt-elements-borderColor rounded-lg shadow-lg focus:outline-none overflow-hidden"
6969
initial="closed"

app/components/settings/debug/DebugTab.tsx

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import React, { useCallback, useEffect, useState } from 'react';
22
import { useSettings } from '~/lib/hooks/useSettings';
33
import commit from '~/commit.json';
44
import { toast } from 'react-toastify';
5+
import { providerBaseUrlEnvKeys } from '~/utils/constants';
56

67
interface ProviderStatus {
78
name: string;
@@ -236,7 +237,7 @@ const checkProviderStatus = async (url: string | null, providerName: string): Pr
236237
}
237238

238239
// Try different endpoints based on provider
239-
const checkUrls = [`${url}/api/health`, `${url}/v1/models`];
240+
const checkUrls = [`${url}/api/health`, url.endsWith('v1') ? `${url}/models` : `${url}/v1/models`];
240241
console.log(`[Debug] Checking additional endpoints:`, checkUrls);
241242

242243
const results = await Promise.all(
@@ -321,14 +322,16 @@ export default function DebugTab() {
321322
.filter(([, provider]) => LOCAL_PROVIDERS.includes(provider.name))
322323
.map(async ([, provider]) => {
323324
const envVarName =
324-
provider.name.toLowerCase() === 'ollama'
325-
? 'OLLAMA_API_BASE_URL'
326-
: provider.name.toLowerCase() === 'lmstudio'
327-
? 'LMSTUDIO_API_BASE_URL'
328-
: `REACT_APP_${provider.name.toUpperCase()}_URL`;
325+
providerBaseUrlEnvKeys[provider.name].baseUrlKey || `REACT_APP_${provider.name.toUpperCase()}_URL`;
329326

330327
// Access environment variables through import.meta.env
331-
const url = import.meta.env[envVarName] || provider.settings.baseUrl || null; // Ensure baseUrl is used
328+
let settingsUrl = provider.settings.baseUrl;
329+
330+
if (settingsUrl && settingsUrl.trim().length === 0) {
331+
settingsUrl = undefined;
332+
}
333+
334+
const url = settingsUrl || import.meta.env[envVarName] || null; // Ensure baseUrl is used
332335
console.log(`[Debug] Using URL for ${provider.name}:`, url, `(from ${envVarName})`);
333336

334337
const status = await checkProviderStatus(url, provider.name);

app/components/settings/providers/ProvidersTab.tsx

Lines changed: 71 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ import { logStore } from '~/lib/stores/logs';
77

88
// Import a default fallback icon
99
import DefaultIcon from '/icons/Default.svg';
10-
11-
// List of advanced providers with correct casing
1210
const ADVANCED_PROVIDERS = ['Ollama', 'OpenAILike', 'LMStudio'];
11+
import { providerBaseUrlEnvKeys } from '~/utils/constants';
12+
1313

1414
export default function ProvidersTab() {
1515
const { providers, updateProviderSettings, isLocalModel } = useSettings();
@@ -118,28 +118,77 @@ export default function ProvidersTab() {
118118
/>
119119
</div>
120120

121-
{/* Regular Providers Grid */}
122-
<div className="grid grid-cols-2 gap-4 mb-8">
123-
{regularProviders.map((provider) => (
124-
<ProviderCard key={provider.name} provider={provider} />
125-
))}
126-
</div>
121+
{filteredProviders.map((provider) => {
122+
const envBaseUrlKey = providerBaseUrlEnvKeys[provider.name].baseUrlKey;
123+
const envBaseUrl = envBaseUrlKey ? import.meta.env[envBaseUrlKey] : undefined;
124+
125+
return (
126+
<div
127+
key={provider.name}
128+
className="flex flex-col mb-2 provider-item hover:bg-bolt-elements-bg-depth-3 p-4 rounded-lg border border-bolt-elements-borderColor "
129+
>
130+
<div className="flex items-center justify-between mb-2">
131+
<div className="flex items-center gap-2">
132+
<img
133+
src={`/icons/${provider.name}.svg`} // Attempt to load the specific icon
134+
onError={(e) => {
135+
// Fallback to default icon on error
136+
e.currentTarget.src = DefaultIcon;
137+
}}
138+
alt={`${provider.name} icon`}
139+
className="w-6 h-6 dark:invert"
140+
/>
141+
<span className="text-bolt-elements-textPrimary">{provider.name}</span>
142+
</div>
143+
<Switch
144+
className="ml-auto"
145+
checked={provider.settings.enabled}
146+
onCheckedChange={(enabled) => {
147+
updateProviderSettings(provider.name, { ...provider.settings, enabled });
127148

128-
{/* Advanced Providers Section */}
129-
{advancedProviders.length > 0 && (
130-
<div className="mb-4 border-t border-bolt-elements-borderColor pt-4">
131-
<h3 className="text-bolt-elements-textSecondary text-lg font-medium mb-2">Experimental Providers</h3>
132-
<p className="text-bolt-elements-textSecondary mb-6">
133-
These providers are experimental features that allow you to run AI models locally or connect to your own infrastructure.
134-
They require additional setup but offer more flexibility for advanced users.
135-
</p>
136-
<div className="grid grid-cols-2 gap-4">
137-
{advancedProviders.map((provider) => (
138-
<ProviderCard key={provider.name} provider={provider} />
139-
))}
149+
if (enabled) {
150+
logStore.logProvider(`Provider ${provider.name} enabled`, { provider: provider.name });
151+
} else {
152+
logStore.logProvider(`Provider ${provider.name} disabled`, { provider: provider.name });
153+
}
154+
}}
155+
/>
156+
</div>
157+
{/* Base URL input for configurable providers */}
158+
{URL_CONFIGURABLE_PROVIDERS.includes(provider.name) && provider.settings.enabled && (
159+
<div className="mt-2">
160+
{envBaseUrl && (
161+
<label className="block text-xs text-bolt-elements-textSecondary text-green-300 mb-2">
162+
Set On (.env) : {envBaseUrl}
163+
</label>
164+
)}
165+
<label className="block text-sm text-bolt-elements-textSecondary mb-2">
166+
{envBaseUrl ? 'Override Base Url' : 'Base URL '}:{' '}
167+
</label>
168+
<input
169+
type="text"
170+
value={provider.settings.baseUrl || ''}
171+
onChange={(e) => {
172+
let newBaseUrl: string | undefined = e.target.value;
173+
174+
if (newBaseUrl && newBaseUrl.trim().length === 0) {
175+
newBaseUrl = undefined;
176+
}
177+
178+
updateProviderSettings(provider.name, { ...provider.settings, baseUrl: newBaseUrl });
179+
logStore.logProvider(`Base URL updated for ${provider.name}`, {
180+
provider: provider.name,
181+
baseUrl: newBaseUrl,
182+
});
183+
}}
184+
placeholder={`Enter ${provider.name} base URL`}
185+
className="w-full bg-white dark:bg-bolt-elements-background-depth-4 relative px-2 py-1.5 rounded-md focus:outline-none placeholder-bolt-elements-textTertiary text-bolt-elements-textPrimary dark:text-bolt-elements-textPrimary border border-bolt-elements-borderColor"
186+
/>
187+
</div>
188+
)}
140189
</div>
141-
</div>
142-
)}
190+
);
191+
})}
143192
</div>
144193
);
145194
}

app/entry.server.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export default async function handleRequest(
1414
remixContext: EntryContext,
1515
_loadContext: AppLoadContext,
1616
) {
17-
await initializeModelList();
17+
await initializeModelList({});
1818

1919
const readable = await renderToReadableStream(<RemixServer context={remixContext} url={request.url} />, {
2020
signal: request.signal,

0 commit comments

Comments
 (0)