From 6f1d0a9150631ecb42cc6e9a77a5d5ad44ffccce Mon Sep 17 00:00:00 2001 From: eduardruzga Date: Sun, 17 Nov 2024 15:52:38 +0200 Subject: [PATCH 001/125] .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index b43105b77f..3303fba9bf 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,7 @@ dist-ssr *.sln *.sw? +/.history /.cache /build .env.local From 8246eb3c626d1b4e9789dd344ee4389f53d57a30 Mon Sep 17 00:00:00 2001 From: eduardruzga Date: Mon, 18 Nov 2024 12:04:56 +0200 Subject: [PATCH 002/125] Add windows start command --- package.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index ce8e95d0d6..6bbb65aa73 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,9 @@ "test:watch": "vitest", "lint": "eslint --cache --cache-location ./node_modules/.cache/eslint .", "lint:fix": "npm run lint -- --fix", - "start": "bindings=$(./bindings.sh) && wrangler pages dev ./build/client $bindings", + "start:windows": "wrangler pages dev ./build/client", + "start:unix": "bindings=$(./bindings.sh) && wrangler pages dev ./build/client $bindings", + "start": "node -e \"const { spawn } = require('child_process'); const isWindows = process.platform === 'win32'; const cmd = isWindows ? 'npm run start:windows' : 'npm run start:unix'; const child = spawn(cmd, { shell: true, stdio: 'inherit' }); child.on('exit', code => process.exit(code));\"", "typecheck": "tsc", "dockerstart": "bindings=$(./bindings.sh) && wrangler pages dev ./build/client $bindings --ip 0.0.0.0 --port 5173 --no-show-interactive-dev-session", "dockerrun": "docker run -it -d --name bolt-ai-live -p 5173:5173 --env-file .env.local bolt-ai", "dockerbuild:prod": "docker build -t bolt-ai:production -t bolt-ai:latest --target bolt-ai-production .", From 920f3618d28d3f0ea5e907381e98846961e6b719 Mon Sep 17 00:00:00 2001 From: eduardruzga Date: Mon, 18 Nov 2024 19:12:47 +0200 Subject: [PATCH 003/125] Fix package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6bbb65aa73..03a5f79e81 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "lint:fix": "npm run lint -- --fix", "start:windows": "wrangler pages dev ./build/client", "start:unix": "bindings=$(./bindings.sh) && wrangler pages dev ./build/client $bindings", - "start": "node -e \"const { spawn } = require('child_process'); const isWindows = process.platform === 'win32'; const cmd = isWindows ? 'npm run start:windows' : 'npm run start:unix'; const child = spawn(cmd, { shell: true, stdio: 'inherit' }); child.on('exit', code => process.exit(code));\"", "typecheck": "tsc", + "start": "node -e \"const { spawn } = require('child_process'); const isWindows = process.platform === 'win32'; const cmd = isWindows ? 'npm run start:windows' : 'npm run start:unix'; const child = spawn(cmd, { shell: true, stdio: 'inherit' }); child.on('exit', code => process.exit(code));\"", "dockerstart": "bindings=$(./bindings.sh) && wrangler pages dev ./build/client $bindings --ip 0.0.0.0 --port 5173 --no-show-interactive-dev-session", "dockerrun": "docker run -it -d --name bolt-ai-live -p 5173:5173 --env-file .env.local bolt-ai", "dockerbuild:prod": "docker build -t bolt-ai:production -t bolt-ai:latest --target bolt-ai-production .", From bfaaf86c69aa558dda35dc638e30108e5d58dc69 Mon Sep 17 00:00:00 2001 From: Aaron Bolton Date: Mon, 18 Nov 2024 20:48:35 +0000 Subject: [PATCH 004/125] Created DEFAULT_NUM_CTX VAR with a deafult of 32768 --- .env.example | 7 +++++++ app/lib/.server/llm/model.ts | 6 +++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/.env.example b/.env.example index 46a21e8929..386d407985 100644 --- a/.env.example +++ b/.env.example @@ -56,3 +56,10 @@ XAI_API_KEY= # Include this environment variable if you want more logging for debugging locally VITE_LOG_LEVEL=debug + +# Example Context Values for qwen2.5-coder:32b +# +# DEFAULT_NUM_CTX=32768 # Consumes 36GB of VRAM +# DEFAULT_NUM_CTX=24576 # Consumes 32GB of VRAM +# DEFAULT_NUM_CTX=12288 # Consumes 26GB of VRAM +# DEFAULT_NUM_CTX=6144 # Consumes 24GB of VRAM \ No newline at end of file diff --git a/app/lib/.server/llm/model.ts b/app/lib/.server/llm/model.ts index 6be9d11703..266dd69d84 100644 --- a/app/lib/.server/llm/model.ts +++ b/app/lib/.server/llm/model.ts @@ -8,6 +8,10 @@ import { ollama } from 'ollama-ai-provider'; import { createOpenRouter } from "@openrouter/ai-sdk-provider"; import { createMistral } from '@ai-sdk/mistral'; +export const DEFAULT_NUM_CTX = process.env.DEFAULT_NUM_CTX ? + parseInt(process.env.DEFAULT_NUM_CTX, 10) : + 32768; + export function getAnthropicModel(apiKey: string, model: string) { const anthropic = createAnthropic({ apiKey, @@ -58,7 +62,7 @@ export function getGroqModel(apiKey: string, model: string) { export function getOllamaModel(baseURL: string, model: string) { let Ollama = ollama(model, { - numCtx: 32768, + numCtx: DEFAULT_NUM_CTX, }); Ollama.config.baseURL = `${baseURL}/api`; From e78a5b0a050818454344020b1682c07c1051f932 Mon Sep 17 00:00:00 2001 From: Andrew Trokhymenko Date: Mon, 18 Nov 2024 19:55:28 -0500 Subject: [PATCH 005/125] image-upload --- app/components/chat/BaseChat.tsx | 121 ++++++++++++++++------ app/components/chat/Chat.client.tsx | 42 +++++++- app/components/chat/FilePreview.tsx | 40 +++++++ app/components/chat/SendButton.client.tsx | 5 +- app/components/chat/UserMessage.tsx | 27 ++++- app/components/sidebar/Menu.client.tsx | 2 +- app/components/workbench/EditorPanel.tsx | 9 +- app/components/workbench/FileTree.tsx | 2 +- app/lib/.server/llm/stream-text.ts | 41 ++++++-- app/routes/api.chat.ts | 17 ++- 10 files changed, 244 insertions(+), 62 deletions(-) create mode 100644 app/components/chat/FilePreview.tsx diff --git a/app/components/chat/BaseChat.tsx b/app/components/chat/BaseChat.tsx index 629c5cbed4..e0cd9280d8 100644 --- a/app/components/chat/BaseChat.tsx +++ b/app/components/chat/BaseChat.tsx @@ -17,6 +17,8 @@ import Cookies from 'js-cookie'; import styles from './BaseChat.module.scss'; import type { ProviderInfo } from '~/utils/types'; +import FilePreview from './FilePreview'; + const EXAMPLE_PROMPTS = [ { text: 'Build a todo app in React using Tailwind' }, { text: 'Build a simple blog using Astro' }, @@ -33,7 +35,7 @@ const ModelSelector = ({ model, setModel, provider, setProvider, modelList, prov { - setProvider(providerList.find(p => p.name === e.target.value)); + setProvider(providerList.find((p) => p.name === e.target.value)); const firstModel = [...modelList].find((m) => m.provider == e.target.value); setModel(firstModel ? firstModel.name : ''); }} @@ -51,7 +51,7 @@ const ModelSelector = ({ model, setModel, provider, setProvider, modelList, prov key={provider?.name} value={model} onChange={(e) => setModel(e.target.value)} - style={{ maxWidth: "70%" }} + style={{ maxWidth: '70%' }} className="flex-1 p-2 rounded-lg border border-bolt-elements-borderColor bg-bolt-elements-prompt-background text-bolt-elements-textPrimary focus:outline-none focus:ring-2 focus:ring-bolt-elements-focus transition-all" > {[...modelList] @@ -93,32 +93,34 @@ interface BaseChatProps { setImageDataList?: (dataList: string[]) => void; } export const BaseChat = React.forwardRef( - ({ - textareaRef, - messageRef, - scrollRef, - showChat, - chatStarted = false, - isStreaming = false, - model, - setModel, - provider, - setProvider, - input = '', - enhancingPrompt, - handleInputChange, - promptEnhanced, - enhancePrompt, - sendMessage, - handleStop, - uploadedFiles, - setUploadedFiles, - imageDataList, - setImageDataList, - messages, - children, // Add this - }, ref) => { - console.log(provider); + ( + { + textareaRef, + messageRef, + scrollRef, + showChat = true, + chatStarted = false, + isStreaming = false, + model, + setModel, + provider, + setProvider, + input = '', + enhancingPrompt, + handleInputChange, + promptEnhanced, + enhancePrompt, + sendMessage, + handleStop, + uploadedFiles, + setUploadedFiles, + imageDataList, + setImageDataList, + messages, + children, // Add this + }, + ref, + ) => { const TEXTAREA_MAX_HEIGHT = chatStarted ? 400 : 200; const [apiKeys, setApiKeys] = useState>({}); const [modelList, setModelList] = useState(MODEL_LIST); @@ -139,7 +141,7 @@ export const BaseChat = React.forwardRef( Cookies.remove('apiKeys'); } - initializeModelList().then(modelList => { + initializeModelList().then((modelList) => { setModelList(modelList); }); }, []); @@ -239,12 +241,13 @@ export const BaseChat = React.forwardRef( setProvider={setProvider} providerList={PROVIDER_LIST} /> - {provider && + {provider && ( updateApiKey(provider.name, key)} - />} + /> + )} ( className="transition-all" onClick={() => handleFileUpload()} > -
+
( ); }, ); - - - diff --git a/app/components/chat/FilePreview.tsx b/app/components/chat/FilePreview.tsx index 378ada6eda..31fd11b9e8 100644 --- a/app/components/chat/FilePreview.tsx +++ b/app/components/chat/FilePreview.tsx @@ -1,23 +1,22 @@ -// FilePreview.tsx +// Remove the lucide-react import import React from 'react'; -import { X } from 'lucide-react'; +// Rest of the interface remains the same interface FilePreviewProps { files: File[]; - imageDataList: string[]; // or imagePreviews: string[] + imageDataList: string[]; onRemove: (index: number) => void; } const FilePreview: React.FC = ({ files, imageDataList, onRemove }) => { if (!files || files.length === 0) { - return null; // Or render a placeholder if desired + return null; } return ( -
{/* Add horizontal scrolling if needed */} +
{files.map((file, index) => (
- {/* Display image preview or file icon */} {imageDataList[index] && (
{file.name} @@ -26,7 +25,7 @@ const FilePreview: React.FC = ({ files, imageDataList, onRemov className="absolute -top-2 -right-2 z-10 bg-white rounded-full p-1 shadow-md hover:bg-gray-100" >
- +
diff --git a/app/components/chat/UserMessage.tsx b/app/components/chat/UserMessage.tsx index a57d4fa83f..d7e1228fd7 100644 --- a/app/components/chat/UserMessage.tsx +++ b/app/components/chat/UserMessage.tsx @@ -21,9 +21,6 @@ export function UserMessage({ content }: UserMessageProps) { ); } -// function sanitizeUserMessage(content: string) { -// return content.replace(modificationsRegex, '').replace(MODEL_REGEX, 'Using: $1').replace(PROVIDER_REGEX, ' ($1)\n\n').trim(); -// } function sanitizeUserMessage(content: string | Array<{type: string, text?: string, image_url?: {url: string}}>) { if (Array.isArray(content)) { return content.map(item => { diff --git a/app/lib/.server/llm/stream-text.ts b/app/lib/.server/llm/stream-text.ts index a50c28eb89..1603396104 100644 --- a/app/lib/.server/llm/stream-text.ts +++ b/app/lib/.server/llm/stream-text.ts @@ -45,12 +45,12 @@ function extractPropertiesFromMessage(message: Message): { model: string; provid if (item.type === 'text') { return { type: 'text', - text: item.text?.replace(/\[Model:.*?\]\n\n/, '').replace(/\[Provider:.*?\]\n\n/, '') + text: item.text?.replace(MODEL_REGEX, '').replace(PROVIDER_REGEX, '') }; } return item; // Preserve image_url and other types as is }) - : textContent.replace(/\[Model:.*?\]\n\n/, '').replace(/\[Provider:.*?\]\n\n/, ''); + : textContent.replace(MODEL_REGEX, '').replace(PROVIDER_REGEX, ''); return { model, provider, content: cleanedContent }; } @@ -80,16 +80,6 @@ export function streamText( return message; // No changes for non-user messages }); - // const modelConfig = getModel(currentProvider, currentModel, env, apiKeys); - // const coreMessages = convertToCoreMessages(processedMessages); - - // console.log('Debug streamText:', JSON.stringify({ - // model: modelConfig, - // messages: processedMessages, - // coreMessages: coreMessages, - // system: getSystemPrompt() - // }, null, 2)); - return _streamText({ model: getModel(currentProvider, currentModel, env, apiKeys), system: getSystemPrompt(), diff --git a/app/routes/api.chat.ts b/app/routes/api.chat.ts index 284fccbcfa..8fdb3d743f 100644 --- a/app/routes/api.chat.ts +++ b/app/routes/api.chat.ts @@ -30,15 +30,15 @@ function parseCookies(cookieHeader) { } async function chatAction({ context, request }: ActionFunctionArgs) { - // console.log('=== API CHAT LOGGING START ==='); - // console.log('Request received:', request.url); - + const { messages, imageData } = await request.json<{ messages: Messages, imageData?: string[] }>(); const cookieHeader = request.headers.get("Cookie"); + + // Parse the cookie's value (returns an object or null if no cookie exists) const apiKeys = JSON.parse(parseCookies(cookieHeader).apiKeys || "{}"); const stream = new SwitchableStream(); @@ -71,13 +71,6 @@ async function chatAction({ context, request }: ActionFunctionArgs) { const result = await streamText(messages, context.cloudflare.env, options, apiKeys); - // console.log('=== API CHAT LOGGING START ==='); - // console.log('StreamText:', JSON.stringify({ - // messages, - // result, - // }, null, 2)); - // console.log('=== API CHAT LOGGING END ==='); - stream.switchSource(result.toAIStream()); return new Response(stream.readable, { diff --git a/package.json b/package.json index 56a9e720ea..40ede0f77a 100644 --- a/package.json +++ b/package.json @@ -74,7 +74,6 @@ "jose": "^5.6.3", "js-cookie": "^3.0.5", "jszip": "^3.10.1", - "lucide-react": "^0.460.0", "nanostores": "^0.10.3", "ollama-ai-provider": "^0.15.2", "react": "^18.2.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ead147e972..4158d19c22 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -155,9 +155,6 @@ importers: jszip: specifier: ^3.10.1 version: 3.10.1 - lucide-react: - specifier: ^0.460.0 - version: 0.460.0(react@18.3.1) nanostores: specifier: ^0.10.3 version: 0.10.3 @@ -3674,11 +3671,6 @@ packages: resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} engines: {node: '>=12'} - lucide-react@0.460.0: - resolution: {integrity: sha512-BVtq/DykVeIvRTJvRAgCsOwaGL8Un3Bxh8MbDxMhEWlZay3T4IpEKDEpwt5KZ0KJMHzgm6jrltxlT5eXOWXDHg==} - peerDependencies: - react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc - magic-string@0.25.9: resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==} @@ -9492,10 +9484,6 @@ snapshots: lru-cache@7.18.3: {} - lucide-react@0.460.0(react@18.3.1): - dependencies: - react: 18.3.1 - magic-string@0.25.9: dependencies: sourcemap-codec: 1.4.8 From 604ab8710b1b72c54d7d3a392faabcaf22951004 Mon Sep 17 00:00:00 2001 From: lassecapel Date: Sun, 17 Nov 2024 20:11:51 +0100 Subject: [PATCH 009/125] feat: add custom unique filename when doanload as zip --- app/lib/stores/workbench.ts | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/app/lib/stores/workbench.ts b/app/lib/stores/workbench.ts index 4db14e7b60..9f0401d77c 100644 --- a/app/lib/stores/workbench.ts +++ b/app/lib/stores/workbench.ts @@ -15,6 +15,7 @@ import { Octokit, type RestEndpointMethodTypes } from "@octokit/rest"; import * as nodePath from 'node:path'; import type { WebContainerProcess } from '@webcontainer/api'; import { extractRelativePath } from '~/utils/diff'; +import { description } from '../persistence'; export interface ArtifactState { id: string; @@ -171,6 +172,7 @@ export class WorkbenchStore { this.#editorStore.setSelectedFile(filePath); } + async saveFile(filePath: string) { const documents = this.#editorStore.documents.get(); const document = documents[filePath]; @@ -325,6 +327,15 @@ export class WorkbenchStore { async downloadZip() { const zip = new JSZip(); const files = this.files.get(); + // Get the project name (assuming it's stored in this.projectName) + const projectName = (description.value ?? 'project').toLocaleLowerCase().split(' ').join('_'); + + // Generate a simple 6-character hash based on the current timestamp + const timestampHash = Date.now().toString(36).slice(-6); + const uniqueProjectName = `${projectName}_${timestampHash}`; + + // Prompt the user for a file name, prefilled with the project name + const fileName = prompt('Enter the file name', `${uniqueProjectName}.zip`); for (const [filePath, dirent] of Object.entries(files)) { if (dirent?.type === 'file' && !dirent.isBinary) { @@ -348,8 +359,14 @@ export class WorkbenchStore { } } + + + + if (fileName) { + // Generate the zip file and save it const content = await zip.generateAsync({ type: 'blob' }); - saveAs(content, 'project.zip'); + saveAs(content, fileName); + } } async syncFiles(targetHandle: FileSystemDirectoryHandle) { From 399affd1e9e0cd113c45cabcdebb8db11a5434b3 Mon Sep 17 00:00:00 2001 From: lassecapel Date: Sun, 17 Nov 2024 20:24:33 +0100 Subject: [PATCH 010/125] update comment to reflect the the codeline --- app/lib/stores/workbench.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/lib/stores/workbench.ts b/app/lib/stores/workbench.ts index 9f0401d77c..dbdd689233 100644 --- a/app/lib/stores/workbench.ts +++ b/app/lib/stores/workbench.ts @@ -327,7 +327,7 @@ export class WorkbenchStore { async downloadZip() { const zip = new JSZip(); const files = this.files.get(); - // Get the project name (assuming it's stored in this.projectName) + // Get the project name from the description input, or use a default name const projectName = (description.value ?? 'project').toLocaleLowerCase().split(' ').join('_'); // Generate a simple 6-character hash based on the current timestamp From 8978ed0ff34c4d164ab67ad25f03951c8d5eaf5f Mon Sep 17 00:00:00 2001 From: Lasse Capel Date: Wed, 20 Nov 2024 09:54:31 +0100 Subject: [PATCH 011/125] use a descriptive anique filename when downloading the files to zip --- app/lib/stores/workbench.ts | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/app/lib/stores/workbench.ts b/app/lib/stores/workbench.ts index dbdd689233..7eed952aba 100644 --- a/app/lib/stores/workbench.ts +++ b/app/lib/stores/workbench.ts @@ -334,9 +334,6 @@ export class WorkbenchStore { const timestampHash = Date.now().toString(36).slice(-6); const uniqueProjectName = `${projectName}_${timestampHash}`; - // Prompt the user for a file name, prefilled with the project name - const fileName = prompt('Enter the file name', `${uniqueProjectName}.zip`); - for (const [filePath, dirent] of Object.entries(files)) { if (dirent?.type === 'file' && !dirent.isBinary) { const relativePath = extractRelativePath(filePath); @@ -358,15 +355,10 @@ export class WorkbenchStore { } } } - - - - - if (fileName) { // Generate the zip file and save it const content = await zip.generateAsync({ type: 'blob' }); - saveAs(content, fileName); - } + saveAs(content, `${uniqueProjectName}.zip`); + } async syncFiles(targetHandle: FileSystemDirectoryHandle) { From 76713c2e6e5b2518f9d8d995647204e4ab66c6b9 Mon Sep 17 00:00:00 2001 From: Andrew Trokhymenko Date: Wed, 20 Nov 2024 17:56:07 -0500 Subject: [PATCH 012/125] fixes for PR #332 --- app/components/chat/UserMessage.tsx | 21 +++++---------------- app/components/workbench/EditorPanel.tsx | 9 +++++---- app/lib/.server/llm/stream-text.ts | 5 +++++ 3 files changed, 15 insertions(+), 20 deletions(-) diff --git a/app/components/chat/UserMessage.tsx b/app/components/chat/UserMessage.tsx index d7e1228fd7..c5d9c9b81a 100644 --- a/app/components/chat/UserMessage.tsx +++ b/app/components/chat/UserMessage.tsx @@ -9,10 +9,7 @@ interface UserMessageProps { } export function UserMessage({ content }: UserMessageProps) { - const sanitizedContent = sanitizeUserMessage(content); - const textContent = Array.isArray(sanitizedContent) - ? sanitizedContent.find(item => item.type === 'text')?.text || '' - : sanitizedContent; + const textContent = sanitizeUserMessage(content); return (
@@ -23,17 +20,9 @@ export function UserMessage({ content }: UserMessageProps) { function sanitizeUserMessage(content: string | Array<{type: string, text?: string, image_url?: {url: string}}>) { if (Array.isArray(content)) { - return content.map(item => { - if (item.type === 'text') { - return { - type: 'text', - text: item.text?.replace(/\[Model:.*?\]\n\n/, '').replace(/\[Provider:.*?\]\n\n/, '') - }; - } - return item; // Keep image_url items unchanged - }); + const textItem = content.find(item => item.type === 'text'); + return textItem?.text?.replace(MODEL_REGEX, '').replace(PROVIDER_REGEX, '') || ''; } - // Handle legacy string content - return content.replace(/\[Model:.*?\]\n\n/, '').replace(/\[Provider:.*?\]\n\n/, ''); -} + return content.replace(MODEL_REGEX, '').replace(PROVIDER_REGEX, ''); +} \ No newline at end of file diff --git a/app/components/workbench/EditorPanel.tsx b/app/components/workbench/EditorPanel.tsx index e789f1d6d8..a9c9d33e71 100644 --- a/app/components/workbench/EditorPanel.tsx +++ b/app/components/workbench/EditorPanel.tsx @@ -23,6 +23,7 @@ import { isMobile } from '~/utils/mobile'; import { FileBreadcrumb } from './FileBreadcrumb'; import { FileTree } from './FileTree'; import { Terminal, type TerminalRef } from './terminal/Terminal'; +import React from 'react'; interface EditorPanelProps { files?: FileMap; @@ -203,7 +204,7 @@ export const EditorPanel = memo( const isActive = activeTerminal === index; return ( - <> + {index == 0 ? ( - + )} - + ); })} {terminalCount < MAX_TERMINALS && } diff --git a/app/lib/.server/llm/stream-text.ts b/app/lib/.server/llm/stream-text.ts index 1603396104..79515120f3 100644 --- a/app/lib/.server/llm/stream-text.ts +++ b/app/lib/.server/llm/stream-text.ts @@ -80,6 +80,11 @@ export function streamText( return message; // No changes for non-user messages }); + console.log('Stream Text:', JSON.stringify({ + model: getModel(currentProvider, currentModel, env, apiKeys), + messages: convertToCoreMessages(processedMessages), + })); + return _streamText({ model: getModel(currentProvider, currentModel, env, apiKeys), system: getSystemPrompt(), From 302cd28775b5abe214817c2b7790a313b2f8f34f Mon Sep 17 00:00:00 2001 From: Andrew Trokhymenko Date: Wed, 20 Nov 2024 19:35:57 -0500 Subject: [PATCH 013/125] . --- app/lib/.server/llm/stream-text.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/app/lib/.server/llm/stream-text.ts b/app/lib/.server/llm/stream-text.ts index 79515120f3..1603396104 100644 --- a/app/lib/.server/llm/stream-text.ts +++ b/app/lib/.server/llm/stream-text.ts @@ -80,11 +80,6 @@ export function streamText( return message; // No changes for non-user messages }); - console.log('Stream Text:', JSON.stringify({ - model: getModel(currentProvider, currentModel, env, apiKeys), - messages: convertToCoreMessages(processedMessages), - })); - return _streamText({ model: getModel(currentProvider, currentModel, env, apiKeys), system: getSystemPrompt(), From 937ba7e61b9ba45d5283fbac3e8a34bd39f7d641 Mon Sep 17 00:00:00 2001 From: Andrew Trokhymenko Date: Thu, 21 Nov 2024 00:17:06 -0500 Subject: [PATCH 014/125] model pickup --- app/lib/.server/llm/stream-text.ts | 2 ++ app/routes/api.chat.ts | 8 ++++++-- app/utils/constants.ts | 6 ++++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/app/lib/.server/llm/stream-text.ts b/app/lib/.server/llm/stream-text.ts index 1603396104..3b563ea262 100644 --- a/app/lib/.server/llm/stream-text.ts +++ b/app/lib/.server/llm/stream-text.ts @@ -64,6 +64,8 @@ export function streamText( let currentModel = DEFAULT_MODEL; let currentProvider = DEFAULT_PROVIDER; + console.log('StreamText:', JSON.stringify(messages)); + const processedMessages = messages.map((message) => { if (message.role === 'user') { const { model, provider, content } = extractPropertiesFromMessage(message); diff --git a/app/routes/api.chat.ts b/app/routes/api.chat.ts index 8fdb3d743f..d622b46499 100644 --- a/app/routes/api.chat.ts +++ b/app/routes/api.chat.ts @@ -31,11 +31,14 @@ function parseCookies(cookieHeader) { async function chatAction({ context, request }: ActionFunctionArgs) { - const { messages, imageData } = await request.json<{ + const { messages, imageData, model } = await request.json<{ messages: Messages, - imageData?: string[] + imageData?: string[], + model: string }>(); + console.log('ChatAction:', JSON.stringify(messages)); + const cookieHeader = request.headers.get("Cookie"); // Parse the cookie's value (returns an object or null if no cookie exists) @@ -47,6 +50,7 @@ async function chatAction({ context, request }: ActionFunctionArgs) { const options: StreamingOptions = { toolChoice: 'none', apiKeys, + model, onFinish: async ({ text: content, finishReason }) => { if (finishReason !== 'length') { return stream.close(); diff --git a/app/utils/constants.ts b/app/utils/constants.ts index 308832b93b..501a87ea4f 100644 --- a/app/utils/constants.ts +++ b/app/utils/constants.ts @@ -30,13 +30,15 @@ const PROVIDER_LIST: ProviderInfo[] = [ icon: "i-ph:cloud-arrow-down", }, { name: 'OpenAILike', - staticModels: [], + staticModels: [ + { name: 'o1-mini', label: 'o1-mini', provider: 'OpenAILike' }, + ], getDynamicModels: getOpenAILikeModels }, { name: 'OpenRouter', staticModels: [ - { name: 'gpt-4o', label: 'GPT-4o', provider: 'OpenAI' }, + { name: 'gpt-4o', label: 'GPT-4o', provider: 'OpenRouter' }, { name: 'anthropic/claude-3.5-sonnet', label: 'Anthropic: Claude 3.5 Sonnet (OpenRouter)', From f644066189333512eec77b24b9c515f734c6b354 Mon Sep 17 00:00:00 2001 From: Qwikode Date: Thu, 21 Nov 2024 15:12:33 +0200 Subject: [PATCH 015/125] fix(ui): mobile friendly --- app/components/chat/APIKeyManager.tsx | 47 +++++---- app/components/chat/BaseChat.tsx | 36 +++---- app/components/chat/Messages.client.tsx | 97 ++++++++++--------- .../header/HeaderActionButtons.client.tsx | 5 +- app/components/workbench/Workbench.client.tsx | 7 +- app/lib/hooks/index.ts | 1 + app/lib/hooks/useViewport.ts | 18 ++++ 7 files changed, 124 insertions(+), 87 deletions(-) create mode 100644 app/lib/hooks/useViewport.ts diff --git a/app/components/chat/APIKeyManager.tsx b/app/components/chat/APIKeyManager.tsx index 5b2c85e467..c61e466dce 100644 --- a/app/components/chat/APIKeyManager.tsx +++ b/app/components/chat/APIKeyManager.tsx @@ -10,11 +10,7 @@ interface APIKeyManagerProps { labelForGetApiKey?: string; } -export const APIKeyManager: React.FC = ({ - provider, - apiKey, - setApiKey, - }) => { +export const APIKeyManager: React.FC = ({ provider, apiKey, setApiKey }) => { const [isEditing, setIsEditing] = useState(false); const [tempKey, setTempKey] = useState(apiKey); @@ -24,15 +20,29 @@ export const APIKeyManager: React.FC = ({ }; return ( -
- {provider?.name} API Key: +
+
+ {provider?.name} API Key: + {!isEditing && ( +
+ + {apiKey ? '••••••••' : 'Not set (will still work if set in .env file)'} + + setIsEditing(true)} title="Edit API Key"> +
+ +
+ )} +
+ {isEditing ? ( - <> +
setTempKey(e.target.value)} - className="flex-1 p-1 text-sm rounded border border-bolt-elements-borderColor bg-bolt-elements-prompt-background text-bolt-elements-textPrimary focus:outline-none focus:ring-2 focus:ring-bolt-elements-focus" + className="flex-1 px-2 py-1 text-xs lg:text-sm rounded border border-bolt-elements-borderColor bg-bolt-elements-prompt-background text-bolt-elements-textPrimary focus:outline-none focus:ring-2 focus:ring-bolt-elements-focus" />
@@ -40,20 +50,15 @@ export const APIKeyManager: React.FC = ({ setIsEditing(false)} title="Cancel">
- +
) : ( <> - - {apiKey ? '••••••••' : 'Not set (will still work if set in .env file)'} - - setIsEditing(true)} title="Edit API Key"> -
- - - {provider?.getApiKeyLink && window.open(provider?.getApiKeyLink)} title="Edit API Key"> - {provider?.labelForGetApiKey || 'Get API Key'} -
- } + {provider?.getApiKeyLink && ( + window.open(provider?.getApiKeyLink)} title="Edit API Key"> + {provider?.labelForGetApiKey || 'Get API Key'} +
+ + )} )}
diff --git a/app/components/chat/BaseChat.tsx b/app/components/chat/BaseChat.tsx index 902cb232cf..396fb012c3 100644 --- a/app/components/chat/BaseChat.tsx +++ b/app/components/chat/BaseChat.tsx @@ -27,9 +27,9 @@ const EXAMPLE_PROMPTS = [ const providerList = PROVIDER_LIST; -const ModelSelector = ({ model, setModel, provider, setProvider, modelList, providerList }) => { +const ModelSelector = ({ model, setModel, provider, setProvider, modelList, providerList, apiKeys }) => { return ( -
+