From d2ba8d3be3861a3e5a3e535547dcc01ef9e826cd Mon Sep 17 00:00:00 2001 From: Anirban Kar Date: Wed, 1 Jan 2025 13:39:09 +0530 Subject: [PATCH 01/47] fix: show warning on starter template failure and continue (#960) --- app/components/chat/Chat.client.tsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/components/chat/Chat.client.tsx b/app/components/chat/Chat.client.tsx index aa89e8c8..135dc8fc 100644 --- a/app/components/chat/Chat.client.tsx +++ b/app/components/chat/Chat.client.tsx @@ -297,7 +297,15 @@ export const ChatImpl = memo( }); if (template !== 'blank') { - const temResp = await getTemplates(template, title); + const temResp = await getTemplates(template, title).catch((e) => { + if (e.message.includes('rate limit')) { + toast.warning('Rate limit exceeded. Skipping starter template\n Continuing with blank template'); + } else { + toast.warning('Failed to import starter template\n Continuing with blank template'); + } + + return null; + }); if (temResp) { const { assistantMessage, userMessage } = temResp; From e9852bfb22c10df1e5a9ad8bee7a48b96cdabbd9 Mon Sep 17 00:00:00 2001 From: Gaurav-Wankhede <73575353+Gaurav-Wankhede@users.noreply.github.com> Date: Wed, 1 Jan 2025 17:59:11 +0530 Subject: [PATCH 02/47] Update hyperbolic.ts Changed updated Hyperbolic Settings link --- app/lib/modules/llm/providers/hyperbolic.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/lib/modules/llm/providers/hyperbolic.ts b/app/lib/modules/llm/providers/hyperbolic.ts index 2f752156..b91a81bc 100644 --- a/app/lib/modules/llm/providers/hyperbolic.ts +++ b/app/lib/modules/llm/providers/hyperbolic.ts @@ -6,7 +6,7 @@ import { createOpenAI } from '@ai-sdk/openai'; export default class HyperbolicProvider extends BaseProvider { name = 'Hyperbolic'; - getApiKeyLink = 'https://hyperbolic.xyz/settings'; + getApiKeyLink = 'https://app.hyperbolic.xyz/settings'; config = { apiTokenKey: 'HYPERBOLIC_API_KEY', From b1f9380c3067190522f771910883fd9077326ecd Mon Sep 17 00:00:00 2001 From: Eduard Ruzga Date: Sun, 5 Jan 2025 13:56:02 +0200 Subject: [PATCH 03/47] fix: introduce our own cors proxy for git import to fix 403 errors on isometric git cors proxy (#924) * Exploration of improving git import * Fix our own git proxy * Clean out file counting for progress, does not seem to work well anyways --- app/components/chat/GitCloneButton.tsx | 91 +++++++----- app/components/git/GitUrlImport.client.tsx | 65 +++++---- app/components/ui/LoadingOverlay.tsx | 22 ++- app/lib/hooks/useGit.ts | 156 ++++++++++++--------- app/routes/api.git-proxy.$.ts | 65 +++++++++ 5 files changed, 264 insertions(+), 135 deletions(-) create mode 100644 app/routes/api.git-proxy.$.ts diff --git a/app/components/chat/GitCloneButton.tsx b/app/components/chat/GitCloneButton.tsx index 4fe4c55e..376d59d6 100644 --- a/app/components/chat/GitCloneButton.tsx +++ b/app/components/chat/GitCloneButton.tsx @@ -3,6 +3,9 @@ import { useGit } from '~/lib/hooks/useGit'; import type { Message } from 'ai'; import { detectProjectCommands, createCommandsMessage } from '~/utils/projectCommands'; import { generateId } from '~/utils/fileUtils'; +import { useState } from 'react'; +import { toast } from 'react-toastify'; +import { LoadingOverlay } from '~/components/ui/LoadingOverlay'; const IGNORE_PATTERNS = [ 'node_modules/**', @@ -37,6 +40,8 @@ interface GitCloneButtonProps { export default function GitCloneButton({ importChat }: GitCloneButtonProps) { const { ready, gitClone } = useGit(); + const [loading, setLoading] = useState(false); + const onClick = async (_e: any) => { if (!ready) { return; @@ -45,33 +50,34 @@ export default function GitCloneButton({ importChat }: GitCloneButtonProps) { const repoUrl = prompt('Enter the Git url'); if (repoUrl) { - const { workdir, data } = await gitClone(repoUrl); + setLoading(true); - if (importChat) { - const filePaths = Object.keys(data).filter((filePath) => !ig.ignores(filePath)); - console.log(filePaths); + try { + const { workdir, data } = await gitClone(repoUrl); - const textDecoder = new TextDecoder('utf-8'); + if (importChat) { + const filePaths = Object.keys(data).filter((filePath) => !ig.ignores(filePath)); + console.log(filePaths); - // Convert files to common format for command detection - const fileContents = filePaths - .map((filePath) => { - const { data: content, encoding } = data[filePath]; - return { - path: filePath, - content: encoding === 'utf8' ? content : content instanceof Uint8Array ? textDecoder.decode(content) : '', - }; - }) - .filter((f) => f.content); + const textDecoder = new TextDecoder('utf-8'); - // Detect and create commands message - const commands = await detectProjectCommands(fileContents); - const commandsMessage = createCommandsMessage(commands); + const fileContents = filePaths + .map((filePath) => { + const { data: content, encoding } = data[filePath]; + return { + path: filePath, + content: + encoding === 'utf8' ? content : content instanceof Uint8Array ? textDecoder.decode(content) : '', + }; + }) + .filter((f) => f.content); - // Create files message - const filesMessage: Message = { - role: 'assistant', - content: `Cloning the repo ${repoUrl} into ${workdir} + const commands = await detectProjectCommands(fileContents); + const commandsMessage = createCommandsMessage(commands); + + const filesMessage: Message = { + role: 'assistant', + content: `Cloning the repo ${repoUrl} into ${workdir} ${fileContents .map( @@ -82,29 +88,38 @@ ${file.content} ) .join('\n')} `, - id: generateId(), - createdAt: new Date(), - }; + id: generateId(), + createdAt: new Date(), + }; - const messages = [filesMessage]; + const messages = [filesMessage]; - if (commandsMessage) { - messages.push(commandsMessage); + if (commandsMessage) { + messages.push(commandsMessage); + } + + await importChat(`Git Project:${repoUrl.split('/').slice(-1)[0]}`, messages); } - - await importChat(`Git Project:${repoUrl.split('/').slice(-1)[0]}`, messages); + } catch (error) { + console.error('Error during import:', error); + toast.error('Failed to import repository'); + } finally { + setLoading(false); } } }; return ( - + <> + + {loading && } + ); } diff --git a/app/components/git/GitUrlImport.client.tsx b/app/components/git/GitUrlImport.client.tsx index c2c949ec..fe8b346b 100644 --- a/app/components/git/GitUrlImport.client.tsx +++ b/app/components/git/GitUrlImport.client.tsx @@ -49,33 +49,32 @@ export function GitUrlImport() { if (repoUrl) { const ig = ignore().add(IGNORE_PATTERNS); - const { workdir, data } = await gitClone(repoUrl); - if (importChat) { - const filePaths = Object.keys(data).filter((filePath) => !ig.ignores(filePath)); + try { + const { workdir, data } = await gitClone(repoUrl); - const textDecoder = new TextDecoder('utf-8'); + if (importChat) { + const filePaths = Object.keys(data).filter((filePath) => !ig.ignores(filePath)); + const textDecoder = new TextDecoder('utf-8'); - // Convert files to common format for command detection - const fileContents = filePaths - .map((filePath) => { - const { data: content, encoding } = data[filePath]; - return { - path: filePath, - content: encoding === 'utf8' ? content : content instanceof Uint8Array ? textDecoder.decode(content) : '', - }; - }) - .filter((f) => f.content); + const fileContents = filePaths + .map((filePath) => { + const { data: content, encoding } = data[filePath]; + return { + path: filePath, + content: + encoding === 'utf8' ? content : content instanceof Uint8Array ? textDecoder.decode(content) : '', + }; + }) + .filter((f) => f.content); - // Detect and create commands message - const commands = await detectProjectCommands(fileContents); - const commandsMessage = createCommandsMessage(commands); + const commands = await detectProjectCommands(fileContents); + const commandsMessage = createCommandsMessage(commands); - // Create files message - const filesMessage: Message = { - role: 'assistant', - content: `Cloning the repo ${repoUrl} into ${workdir} - + const filesMessage: Message = { + role: 'assistant', + content: `Cloning the repo ${repoUrl} into ${workdir} + ${fileContents .map( (file) => @@ -85,17 +84,25 @@ ${file.content} ) .join('\n')} `, - id: generateId(), - createdAt: new Date(), - }; + id: generateId(), + createdAt: new Date(), + }; - const messages = [filesMessage]; + const messages = [filesMessage]; - if (commandsMessage) { - messages.push(commandsMessage); + if (commandsMessage) { + messages.push(commandsMessage); + } + + await importChat(`Git Project:${repoUrl.split('/').slice(-1)[0]}`, messages); } + } catch (error) { + console.error('Error during import:', error); + toast.error('Failed to import repository'); + setLoading(false); + window.location.href = '/'; - await importChat(`Git Project:${repoUrl.split('/').slice(-1)[0]}`, messages); + return; } } }; diff --git a/app/components/ui/LoadingOverlay.tsx b/app/components/ui/LoadingOverlay.tsx index 6c69798f..2ade83b0 100644 --- a/app/components/ui/LoadingOverlay.tsx +++ b/app/components/ui/LoadingOverlay.tsx @@ -1,13 +1,31 @@ -export const LoadingOverlay = ({ message = 'Loading...' }) => { +export const LoadingOverlay = ({ + message = 'Loading...', + progress, + progressText, +}: { + message?: string; + progress?: number; + progressText?: string; +}) => { return (
- {/* Loading content */}

{message}

+ {progress !== undefined && ( +
+
+
+
+ {progressText &&

{progressText}

} +
+ )}
); diff --git a/app/lib/hooks/useGit.ts b/app/lib/hooks/useGit.ts index 3c8c61bb..cfa5027b 100644 --- a/app/lib/hooks/useGit.ts +++ b/app/lib/hooks/useGit.ts @@ -49,50 +49,54 @@ export function useGit() { } fileData.current = {}; - await git.clone({ - fs, - http, - dir: webcontainer.workdir, - url, - depth: 1, - singleBranch: true, - corsProxy: 'https://cors.isomorphic-git.org', - onAuth: (url) => { - // let domain=url.split("/")[2] - let auth = lookupSavedPassword(url); + try { + await git.clone({ + fs, + http, + dir: webcontainer.workdir, + url, + depth: 1, + singleBranch: true, + corsProxy: '/api/git-proxy', + onAuth: (url) => { + let auth = lookupSavedPassword(url); - if (auth) { - return auth; - } + if (auth) { + return auth; + } - if (confirm('This repo is password protected. Ready to enter a username & password?')) { - auth = { - username: prompt('Enter username'), - password: prompt('Enter password'), - }; - return auth; - } else { - return { cancel: true }; - } - }, - onAuthFailure: (url, _auth) => { - toast.error(`Error Authenticating with ${url.split('/')[2]}`); - }, - onAuthSuccess: (url, auth) => { - saveGitAuth(url, auth); - }, - }); + if (confirm('This repo is password protected. Ready to enter a username & password?')) { + auth = { + username: prompt('Enter username'), + password: prompt('Enter password'), + }; + return auth; + } else { + return { cancel: true }; + } + }, + onAuthFailure: (url, _auth) => { + toast.error(`Error Authenticating with ${url.split('/')[2]}`); + }, + onAuthSuccess: (url, auth) => { + saveGitAuth(url, auth); + }, + }); - const data: Record = {}; + const data: Record = {}; - for (const [key, value] of Object.entries(fileData.current)) { - data[key] = value; + for (const [key, value] of Object.entries(fileData.current)) { + data[key] = value; + } + + return { workdir: webcontainer.workdir, data }; + } catch (error) { + console.error('Git clone error:', error); + throw error; } - - return { workdir: webcontainer.workdir, data }; }, - [webcontainer], + [webcontainer, fs, ready], ); return { ready, gitClone }; @@ -104,55 +108,86 @@ const getFs = ( ) => ({ promises: { readFile: async (path: string, options: any) => { - const encoding = options.encoding; + const encoding = options?.encoding; const relativePath = pathUtils.relative(webcontainer.workdir, path); - console.log('readFile', relativePath, encoding); - return await webcontainer.fs.readFile(relativePath, encoding); + try { + const result = await webcontainer.fs.readFile(relativePath, encoding); + + return result; + } catch (error) { + throw error; + } }, writeFile: async (path: string, data: any, options: any) => { const encoding = options.encoding; const relativePath = pathUtils.relative(webcontainer.workdir, path); - console.log('writeFile', { relativePath, data, encoding }); if (record.current) { record.current[relativePath] = { data, encoding }; } - return await webcontainer.fs.writeFile(relativePath, data, { ...options, encoding }); + try { + const result = await webcontainer.fs.writeFile(relativePath, data, { ...options, encoding }); + + return result; + } catch (error) { + throw error; + } }, mkdir: async (path: string, options: any) => { const relativePath = pathUtils.relative(webcontainer.workdir, path); - console.log('mkdir', relativePath, options); - return await webcontainer.fs.mkdir(relativePath, { ...options, recursive: true }); + try { + const result = await webcontainer.fs.mkdir(relativePath, { ...options, recursive: true }); + + return result; + } catch (error) { + throw error; + } }, readdir: async (path: string, options: any) => { const relativePath = pathUtils.relative(webcontainer.workdir, path); - console.log('readdir', relativePath, options); - return await webcontainer.fs.readdir(relativePath, options); + try { + const result = await webcontainer.fs.readdir(relativePath, options); + + return result; + } catch (error) { + throw error; + } }, rm: async (path: string, options: any) => { const relativePath = pathUtils.relative(webcontainer.workdir, path); - console.log('rm', relativePath, options); - return await webcontainer.fs.rm(relativePath, { ...(options || {}) }); + try { + const result = await webcontainer.fs.rm(relativePath, { ...(options || {}) }); + + return result; + } catch (error) { + throw error; + } }, rmdir: async (path: string, options: any) => { const relativePath = pathUtils.relative(webcontainer.workdir, path); - console.log('rmdir', relativePath, options); - return await webcontainer.fs.rm(relativePath, { recursive: true, ...options }); + try { + const result = await webcontainer.fs.rm(relativePath, { recursive: true, ...options }); + + return result; + } catch (error) { + throw error; + } }, - - // Mock implementations for missing functions unlink: async (path: string) => { - // unlink is just removing a single file const relativePath = pathUtils.relative(webcontainer.workdir, path); - return await webcontainer.fs.rm(relativePath, { recursive: false }); - }, + try { + return await webcontainer.fs.rm(relativePath, { recursive: false }); + } catch (error) { + throw error; + } + }, stat: async (path: string) => { try { const relativePath = pathUtils.relative(webcontainer.workdir, path); @@ -185,23 +220,12 @@ const getFs = ( throw err; } }, - lstat: async (path: string) => { - /* - * For basic usage, lstat can return the same as stat - * since we're not handling symbolic links - */ return await getFs(webcontainer, record).promises.stat(path); }, - readlink: async (path: string) => { - /* - * Since WebContainer doesn't support symlinks, - * we'll throw a "not a symbolic link" error - */ throw new Error(`EINVAL: invalid argument, readlink '${path}'`); }, - symlink: async (target: string, path: string) => { /* * Since WebContainer doesn't support symlinks, diff --git a/app/routes/api.git-proxy.$.ts b/app/routes/api.git-proxy.$.ts new file mode 100644 index 00000000..9e6cb3b1 --- /dev/null +++ b/app/routes/api.git-proxy.$.ts @@ -0,0 +1,65 @@ +import { json } from '@remix-run/cloudflare'; +import type { ActionFunctionArgs, LoaderFunctionArgs } from '@remix-run/cloudflare'; + +// Handle all HTTP methods +export async function action({ request, params }: ActionFunctionArgs) { + return handleProxyRequest(request, params['*']); +} + +export async function loader({ request, params }: LoaderFunctionArgs) { + return handleProxyRequest(request, params['*']); +} + +async function handleProxyRequest(request: Request, path: string | undefined) { + try { + if (!path) { + return json({ error: 'Invalid proxy URL format' }, { status: 400 }); + } + + const url = new URL(request.url); + + // Reconstruct the target URL + const targetURL = `https://${path}${url.search}`; + + // Forward the request to the target URL + const response = await fetch(targetURL, { + method: request.method, + headers: { + ...Object.fromEntries(request.headers), + + // Override host header with the target host + host: new URL(targetURL).host, + }, + body: ['GET', 'HEAD'].includes(request.method) ? null : await request.arrayBuffer(), + }); + + // Create response with CORS headers + const corsHeaders = { + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS', + 'Access-Control-Allow-Headers': '*', + }; + + // Handle preflight requests + if (request.method === 'OPTIONS') { + return new Response(null, { + headers: corsHeaders, + status: 204, + }); + } + + // Forward the response with CORS headers + const responseHeaders = new Headers(response.headers); + Object.entries(corsHeaders).forEach(([key, value]) => { + responseHeaders.set(key, value); + }); + + return new Response(response.body, { + status: response.status, + headers: responseHeaders, + }); + } catch (error) { + console.error('Git proxy error:', error); + return json({ error: 'Proxy error' }, { status: 500 }); + } +} From 59cae5733db0bb018f37eba0f553cd30d0e8154b Mon Sep 17 00:00:00 2001 From: Anirban Kar Date: Mon, 6 Jan 2025 01:54:55 +0530 Subject: [PATCH 04/47] fix: git private clone with custom proxy (#1010) * cookie fix * fix: git private clone with custom proxy * list -fix --- app/lib/hooks/useGit.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/app/lib/hooks/useGit.ts b/app/lib/hooks/useGit.ts index cfa5027b..2efc6e8c 100644 --- a/app/lib/hooks/useGit.ts +++ b/app/lib/hooks/useGit.ts @@ -50,6 +50,18 @@ export function useGit() { fileData.current = {}; + const headers: { + [x: string]: string; + } = { + 'User-Agent': 'bolt.diy', + }; + + const auth = lookupSavedPassword(url); + + if (auth) { + headers.Authorization = `Basic ${Buffer.from(`${auth.username}:${auth.password}`).toString('base64')}`; + } + try { await git.clone({ fs, @@ -59,6 +71,8 @@ export function useGit() { depth: 1, singleBranch: true, corsProxy: '/api/git-proxy', + headers, + onAuth: (url) => { let auth = lookupSavedPassword(url); From 481268b941d0193f6aafdbcab6fc8f0d36f11d38 Mon Sep 17 00:00:00 2001 From: Cole Medin Date: Sun, 5 Jan 2025 14:40:26 -0700 Subject: [PATCH 05/47] docs: updating copyright in LICENSE (#796) --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 79290241..8fb312e9 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2024 StackBlitz, Inc. +Copyright (c) 2024 StackBlitz, Inc. and bolt.diy contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 6437ceb5dd93b8a82efdc8a7ede1a9d77d44a98b Mon Sep 17 00:00:00 2001 From: Siddarth Date: Sun, 5 Jan 2025 16:48:07 -0500 Subject: [PATCH 06/47] fix: added XAI to docker config (#274) * commit * Create .env.example * Update docker-compose.yaml --------- Co-authored-by: Anirban Kar --- Dockerfile | 4 ++++ docker-compose.yaml | 2 ++ 2 files changed, 6 insertions(+) diff --git a/Dockerfile b/Dockerfile index 06541d30..e54b74b3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -25,6 +25,7 @@ ARG ANTHROPIC_API_KEY ARG OPEN_ROUTER_API_KEY ARG GOOGLE_GENERATIVE_AI_API_KEY ARG OLLAMA_API_BASE_URL +ARG XAI_API_KEY ARG TOGETHER_API_KEY ARG TOGETHER_API_BASE_URL ARG VITE_LOG_LEVEL=debug @@ -38,6 +39,7 @@ ENV WRANGLER_SEND_METRICS=false \ OPEN_ROUTER_API_KEY=${OPEN_ROUTER_API_KEY} \ GOOGLE_GENERATIVE_AI_API_KEY=${GOOGLE_GENERATIVE_AI_API_KEY} \ OLLAMA_API_BASE_URL=${OLLAMA_API_BASE_URL} \ + XAI_API_KEY=${XAI_API_KEY} \ TOGETHER_API_KEY=${TOGETHER_API_KEY} \ TOGETHER_API_BASE_URL=${TOGETHER_API_BASE_URL} \ VITE_LOG_LEVEL=${VITE_LOG_LEVEL} \ @@ -62,6 +64,7 @@ ARG ANTHROPIC_API_KEY ARG OPEN_ROUTER_API_KEY ARG GOOGLE_GENERATIVE_AI_API_KEY ARG OLLAMA_API_BASE_URL +ARG XAI_API_KEY ARG TOGETHER_API_KEY ARG TOGETHER_API_BASE_URL ARG VITE_LOG_LEVEL=debug @@ -74,6 +77,7 @@ ENV GROQ_API_KEY=${GROQ_API_KEY} \ OPEN_ROUTER_API_KEY=${OPEN_ROUTER_API_KEY} \ GOOGLE_GENERATIVE_AI_API_KEY=${GOOGLE_GENERATIVE_AI_API_KEY} \ OLLAMA_API_BASE_URL=${OLLAMA_API_BASE_URL} \ + XAI_API_KEY=${XAI_API_KEY} \ TOGETHER_API_KEY=${TOGETHER_API_KEY} \ TOGETHER_API_BASE_URL=${TOGETHER_API_BASE_URL} \ VITE_LOG_LEVEL=${VITE_LOG_LEVEL} \ diff --git a/docker-compose.yaml b/docker-compose.yaml index 0c9acd09..d605df6b 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -20,6 +20,7 @@ services: - OPEN_ROUTER_API_KEY=${OPEN_ROUTER_API_KEY} - GOOGLE_GENERATIVE_AI_API_KEY=${GOOGLE_GENERATIVE_AI_API_KEY} - OLLAMA_API_BASE_URL=${OLLAMA_API_BASE_URL} + - XAI_API_KEY=${XAI_API_KEY} - TOGETHER_API_KEY=${TOGETHER_API_KEY} - TOGETHER_API_BASE_URL=${TOGETHER_API_BASE_URL} - VITE_LOG_LEVEL=${VITE_LOG_LEVEL:-debug} @@ -48,6 +49,7 @@ services: - OPENAI_API_KEY=${OPENAI_API_KEY} - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY} - OPEN_ROUTER_API_KEY=${OPEN_ROUTER_API_KEY} + - XAI_API_KEY=${XAI_API_KEY} - GOOGLE_GENERATIVE_AI_API_KEY=${GOOGLE_GENERATIVE_AI_API_KEY} - OLLAMA_API_BASE_URL=${OLLAMA_API_BASE_URL} - TOGETHER_API_KEY=${TOGETHER_API_KEY} From 02a3abd892e9857e790f3490b5c17dd01d8b0eb6 Mon Sep 17 00:00:00 2001 From: twsl <45483159+twsl@users.noreply.github.com> Date: Sun, 5 Jan 2025 23:02:36 +0100 Subject: [PATCH 07/47] ci: docker Image creation pipeline (#1011) * Create docker.yaml * Add build target * Use build target var * Use github token instead --- .github/workflows/docker.yaml | 76 +++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 .github/workflows/docker.yaml diff --git a/.github/workflows/docker.yaml b/.github/workflows/docker.yaml new file mode 100644 index 00000000..016ddf7e --- /dev/null +++ b/.github/workflows/docker.yaml @@ -0,0 +1,76 @@ +--- +name: Docker Publish + +on: + workflow_dispatch: + push: + branches: + - main + tags: + - v* + - "*" + +env: + REGISTRY: ghcr.io + DOCKER_IMAGE: ghcr.io/${{ github.repository }} + BUILD_TARGET: bolt-ai-production # bolt-ai-development + +jobs: + docker-build-publish: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - id: string + uses: ASzc/change-string-case-action@v6 + with: + string: ${{ env.DOCKER_IMAGE }} + + - name: Docker meta + id: meta + uses: crazy-max/ghaction-docker-meta@v5 + with: + images: ${{ steps.string.outputs.lowercase }} + flavor: | + latest=true + prefix= + suffix= + tags: | + type=semver,pattern={{version}} + type=pep440,pattern={{version}} + type=ref,event=tag + type=raw,value={{sha}} + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} # ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.GITHUB_TOKEN }} # ${{ secrets.DOCKER_PASSWORD }} + + - name: Build and push + uses: docker/build-push-action@v6 + with: + context: . + file: ./Dockerfile + target: ${{ env.BUILD_TARGET }} + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=registry,ref=${{ steps.string.outputs.lowercase }}:latest + cache-to: type=inline + + - name: Check manifest + run: | + docker buildx imagetools inspect ${{ steps.string.outputs.lowercase }}:${{ steps.meta.outputs.version }} + + - name: Dump context + if: always() + uses: crazy-max/ghaction-dump-context@v2 From 77f8a368a2692f57fc3636ed2e56950cc262c4d0 Mon Sep 17 00:00:00 2001 From: twsl <45483159+twsl@users.noreply.github.com> Date: Mon, 6 Jan 2025 06:04:31 +0100 Subject: [PATCH 08/47] ci: fix docker image workflow permissions (#1013) * Update docker.yaml * Fix indentation in docker workflow file --- .github/workflows/docker.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/docker.yaml b/.github/workflows/docker.yaml index 016ddf7e..c38f591e 100644 --- a/.github/workflows/docker.yaml +++ b/.github/workflows/docker.yaml @@ -10,6 +10,9 @@ on: - v* - "*" +permissions: + packages: write + env: REGISTRY: ghcr.io DOCKER_IMAGE: ghcr.io/${{ github.repository }} From f2546f12d8090e34fca569bdd79ebd66c806b684 Mon Sep 17 00:00:00 2001 From: Anirban Kar Date: Mon, 6 Jan 2025 13:57:16 +0530 Subject: [PATCH 09/47] ci: added visibility change to public for docker image publish (#1017) --- .github/workflows/docker.yaml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/docker.yaml b/.github/workflows/docker.yaml index c38f591e..34a0c99b 100644 --- a/.github/workflows/docker.yaml +++ b/.github/workflows/docker.yaml @@ -12,6 +12,7 @@ on: permissions: packages: write + contents: read env: REGISTRY: ghcr.io @@ -74,6 +75,18 @@ jobs: run: | docker buildx imagetools inspect ${{ steps.string.outputs.lowercase }}:${{ steps.meta.outputs.version }} + + - name: Make package public + run: | + gh api \ + --method PATCH \ + -H "Accept: application/vnd.github+json" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + "/user/packages/container/${{ github.event.repository.name }}/visibility" \ + -f visibility='public' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Dump context if: always() uses: crazy-max/ghaction-dump-context@v2 From 7e39e924e1cd560414fa705334bb4d8419015479 Mon Sep 17 00:00:00 2001 From: Anirban Kar Date: Mon, 6 Jan 2025 14:05:01 +0530 Subject: [PATCH 10/47] reverted visibility change (#1018) --- .github/workflows/docker.yaml | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/.github/workflows/docker.yaml b/.github/workflows/docker.yaml index 34a0c99b..f5424983 100644 --- a/.github/workflows/docker.yaml +++ b/.github/workflows/docker.yaml @@ -75,18 +75,6 @@ jobs: run: | docker buildx imagetools inspect ${{ steps.string.outputs.lowercase }}:${{ steps.meta.outputs.version }} - - - name: Make package public - run: | - gh api \ - --method PATCH \ - -H "Accept: application/vnd.github+json" \ - -H "X-GitHub-Api-Version: 2022-11-28" \ - "/user/packages/container/${{ github.event.repository.name }}/visibility" \ - -f visibility='public' - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Dump context if: always() uses: crazy-max/ghaction-dump-context@v2 From 3ecac25a352ff7131359132494ce61b3932b0702 Mon Sep 17 00:00:00 2001 From: kunjabijukchhe <43906826+kunjabijukchhe@users.noreply.github.com> Date: Mon, 6 Jan 2025 18:04:16 +0545 Subject: [PATCH 11/47] feat: implement Claude 3, Claude3.5, Nova Pro, Nova Lite and Mistral model integration with AWS Bedrock (#974) * feat: Integrate AWS Bedrock with Claude 3.5 Sonnet, Claude 3 Sonnet, and Claude 3.5 Haiku * update Dockerfile for AWS Bedrock configuration * feat: add new Bedrock model 'Mistral' and update Haiku to version 3 * feat: add new bedrock model Nova Lite and Nova Pro * Update README documentation to reflect the latest changes * Add the icon for aws bedrock * add support for serialized AWS Bedrock configuration in api key --- .env.example | 11 + Dockerfile | 3 + README.md | 1 + app/components/settings/data/DataTab.tsx | 1 + .../modules/llm/providers/amazon-bedrock.ts | 113 ++ app/lib/modules/llm/registry.ts | 2 + docker-compose.yaml | 2 + package.json | 1 + pnpm-lock.yaml | 1075 +++++++++++++++++ public/icons/AmazonBedrock.svg | 1 + worker-configuration.d.ts | 1 + 11 files changed, 1211 insertions(+) create mode 100644 app/lib/modules/llm/providers/amazon-bedrock.ts create mode 100644 public/icons/AmazonBedrock.svg diff --git a/.env.example b/.env.example index 6f2f5f5a..2d736a72 100644 --- a/.env.example +++ b/.env.example @@ -83,6 +83,17 @@ XAI_API_KEY= # You only need this environment variable set if you want to use Perplexity models PERPLEXITY_API_KEY= +# Get your AWS configuration +# https://console.aws.amazon.com/iam/home +# The JSON should include the following keys: +# - region: The AWS region where Bedrock is available. +# - accessKeyId: Your AWS access key ID. +# - secretAccessKey: Your AWS secret access key. +# - sessionToken (optional): Temporary session token if using an IAM role or temporary credentials. +# Example JSON: +# {"region": "us-east-1", "accessKeyId": "yourAccessKeyId", "secretAccessKey": "yourSecretAccessKey", "sessionToken": "yourSessionToken"} +AWS_BEDROCK_CONFIG= + # Include this environment variable if you want more logging for debugging locally VITE_LOG_LEVEL=debug diff --git a/Dockerfile b/Dockerfile index e54b74b3..cd2a6fbf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -28,6 +28,7 @@ ARG OLLAMA_API_BASE_URL ARG XAI_API_KEY ARG TOGETHER_API_KEY ARG TOGETHER_API_BASE_URL +ARG AWS_BEDROCK_CONFIG ARG VITE_LOG_LEVEL=debug ARG DEFAULT_NUM_CTX @@ -42,6 +43,7 @@ ENV WRANGLER_SEND_METRICS=false \ XAI_API_KEY=${XAI_API_KEY} \ TOGETHER_API_KEY=${TOGETHER_API_KEY} \ TOGETHER_API_BASE_URL=${TOGETHER_API_BASE_URL} \ + AWS_BEDROCK_CONFIG=${AWS_BEDROCK_CONFIG} \ VITE_LOG_LEVEL=${VITE_LOG_LEVEL} \ DEFAULT_NUM_CTX=${DEFAULT_NUM_CTX} @@ -80,6 +82,7 @@ ENV GROQ_API_KEY=${GROQ_API_KEY} \ XAI_API_KEY=${XAI_API_KEY} \ TOGETHER_API_KEY=${TOGETHER_API_KEY} \ TOGETHER_API_BASE_URL=${TOGETHER_API_BASE_URL} \ + AWS_BEDROCK_CONFIG=${AWS_BEDROCK_CONFIG} \ VITE_LOG_LEVEL=${VITE_LOG_LEVEL} \ DEFAULT_NUM_CTX=${DEFAULT_NUM_CTX} diff --git a/README.md b/README.md index c50f4277..715faa70 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,7 @@ bolt.diy was originally started by [Cole Medin](https://www.youtube.com/@ColeMed - ⬜ Voice prompting - ⬜ Azure Open AI API Integration - ✅ Perplexity Integration (@meetpateltech) +- ✅ AWS Bedrock Integration (@kunjabijukchhe) - ⬜ Vertex AI Integration ## Features diff --git a/app/components/settings/data/DataTab.tsx b/app/components/settings/data/DataTab.tsx index aac2fe0f..c78491e2 100644 --- a/app/components/settings/data/DataTab.tsx +++ b/app/components/settings/data/DataTab.tsx @@ -22,6 +22,7 @@ const API_KEY_PROVIDERS = [ 'Perplexity', 'Cohere', 'AzureOpenAI', + 'AmazonBedrock', ] as const; interface ApiKeys { diff --git a/app/lib/modules/llm/providers/amazon-bedrock.ts b/app/lib/modules/llm/providers/amazon-bedrock.ts new file mode 100644 index 00000000..f01b13ac --- /dev/null +++ b/app/lib/modules/llm/providers/amazon-bedrock.ts @@ -0,0 +1,113 @@ +import { BaseProvider } from '~/lib/modules/llm/base-provider'; +import type { ModelInfo } from '~/lib/modules/llm/types'; +import type { LanguageModelV1 } from 'ai'; +import type { IProviderSetting } from '~/types/model'; +import { createAmazonBedrock } from '@ai-sdk/amazon-bedrock'; + +interface AWSBedRockConfig { + region: string; + accessKeyId: string; + secretAccessKey: string; + sessionToken?: string; +} + +export default class AmazonBedrockProvider extends BaseProvider { + name = 'AmazonBedrock'; + getApiKeyLink = 'https://console.aws.amazon.com/iam/home'; + + config = { + apiTokenKey: 'AWS_BEDROCK_CONFIG', + }; + + staticModels: ModelInfo[] = [ + { + name: 'anthropic.claude-3-5-sonnet-20240620-v1:0', + label: 'Claude 3.5 Sonnet (Bedrock)', + provider: 'AmazonBedrock', + maxTokenAllowed: 4096, + }, + { + name: 'anthropic.claude-3-sonnet-20240229-v1:0', + label: 'Claude 3 Sonnet (Bedrock)', + provider: 'AmazonBedrock', + maxTokenAllowed: 4096, + }, + { + name: 'anthropic.claude-3-haiku-20240307-v1:0', + label: 'Claude 3 Haiku (Bedrock)', + provider: 'AmazonBedrock', + maxTokenAllowed: 4096, + }, + { + name: 'amazon.nova-pro-v1:0', + label: 'Amazon Nova Pro (Bedrock)', + provider: 'AmazonBedrock', + maxTokenAllowed: 5120, + }, + { + name: 'amazon.nova-lite-v1:0', + label: 'Amazon Nova Lite (Bedrock)', + provider: 'AmazonBedrock', + maxTokenAllowed: 5120, + }, + { + name: 'mistral.mistral-large-2402-v1:0', + label: 'Mistral Large 24.02 (Bedrock)', + provider: 'AmazonBedrock', + maxTokenAllowed: 8192, + }, + ]; + + private _parseAndValidateConfig(apiKey: string): AWSBedRockConfig { + let parsedConfig: AWSBedRockConfig; + + try { + parsedConfig = JSON.parse(apiKey); + } catch { + throw new Error( + 'Invalid AWS Bedrock configuration format. Please provide a valid JSON string containing region, accessKeyId, and secretAccessKey.', + ); + } + + const { region, accessKeyId, secretAccessKey, sessionToken } = parsedConfig; + + if (!region || !accessKeyId || !secretAccessKey) { + throw new Error( + 'Missing required AWS credentials. Configuration must include region, accessKeyId, and secretAccessKey.', + ); + } + + return { + region, + accessKeyId, + secretAccessKey, + ...(sessionToken && { sessionToken }), + }; + } + + getModelInstance(options: { + model: string; + serverEnv: any; + apiKeys?: Record; + providerSettings?: Record; + }): LanguageModelV1 { + const { model, serverEnv, apiKeys, providerSettings } = options; + + const { apiKey } = this.getProviderBaseUrlAndKey({ + apiKeys, + providerSettings: providerSettings?.[this.name], + serverEnv: serverEnv as any, + defaultBaseUrlKey: '', + defaultApiTokenKey: 'AWS_BEDROCK_CONFIG', + }); + + if (!apiKey) { + throw new Error(`Missing API key for ${this.name} provider`); + } + + const config = this._parseAndValidateConfig(apiKey); + const bedrock = createAmazonBedrock(config); + + return bedrock(model); + } +} diff --git a/app/lib/modules/llm/registry.ts b/app/lib/modules/llm/registry.ts index c002eb88..dbbe27ea 100644 --- a/app/lib/modules/llm/registry.ts +++ b/app/lib/modules/llm/registry.ts @@ -14,6 +14,7 @@ import PerplexityProvider from './providers/perplexity'; import TogetherProvider from './providers/together'; import XAIProvider from './providers/xai'; import HyperbolicProvider from './providers/hyperbolic'; +import AmazonBedrockProvider from './providers/amazon-bedrock'; export { AnthropicProvider, @@ -32,4 +33,5 @@ export { XAIProvider, TogetherProvider, LMStudioProvider, + AmazonBedrockProvider, }; diff --git a/docker-compose.yaml b/docker-compose.yaml index d605df6b..9c28c647 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -23,6 +23,7 @@ services: - XAI_API_KEY=${XAI_API_KEY} - TOGETHER_API_KEY=${TOGETHER_API_KEY} - TOGETHER_API_BASE_URL=${TOGETHER_API_BASE_URL} + - AWS_BEDROCK_CONFIG=${AWS_BEDROCK_CONFIG} - VITE_LOG_LEVEL=${VITE_LOG_LEVEL:-debug} - DEFAULT_NUM_CTX=${DEFAULT_NUM_CTX:-32768} - RUNNING_IN_DOCKER=true @@ -54,6 +55,7 @@ services: - OLLAMA_API_BASE_URL=${OLLAMA_API_BASE_URL} - TOGETHER_API_KEY=${TOGETHER_API_KEY} - TOGETHER_API_BASE_URL=${TOGETHER_API_BASE_URL} + - AWS_BEDROCK_CONFIG=${AWS_BEDROCK_CONFIG} - VITE_LOG_LEVEL=${VITE_LOG_LEVEL:-debug} - DEFAULT_NUM_CTX=${DEFAULT_NUM_CTX:-32768} - RUNNING_IN_DOCKER=true diff --git a/package.json b/package.json index 1668d994..5788c003 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "@ai-sdk/google": "^0.0.52", "@ai-sdk/mistral": "^0.0.43", "@ai-sdk/openai": "^0.0.66", + "@ai-sdk/amazon-bedrock": "1.0.6", "@codemirror/autocomplete": "^6.18.3", "@codemirror/commands": "^6.7.1", "@codemirror/lang-cpp": "^6.0.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 128560a5..f625a94c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,6 +11,9 @@ importers: .: dependencies: + '@ai-sdk/amazon-bedrock': + specifier: 1.0.6 + version: 1.0.6(zod@3.23.8) '@ai-sdk/anthropic': specifier: ^0.0.39 version: 0.0.39(zod@3.23.8) @@ -309,6 +312,12 @@ importers: packages: + '@ai-sdk/amazon-bedrock@1.0.6': + resolution: {integrity: sha512-EdbLjy/r9W6ds5/xbkfklr5C9y3PmGh2eXqhd3xyURq0oSoB9ukoOa9jvPTb4b3jS6l4R7yXYJvTZiAkkefUeQ==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.0.0 + '@ai-sdk/anthropic@0.0.39': resolution: {integrity: sha512-Ouku41O9ebyRi0EUW7pB8+lk4sI74SfJKydzK7FjynhNmCSvi42+U4WPlEjP64NluXUzpkYLvBa6BAd36VY4/g==} engines: {node: '>=18'} @@ -384,6 +393,15 @@ packages: zod: optional: true + '@ai-sdk/provider-utils@2.0.5': + resolution: {integrity: sha512-2M7vLhYN0ThGjNlzow7oO/lsL+DyMxvGMIYmVQvEYaCWhDzxH5dOp78VNjJIVwHzVLMbBDigX3rJuzAs853idw==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.0.0 + peerDependenciesMeta: + zod: + optional: true + '@ai-sdk/provider@0.0.12': resolution: {integrity: sha512-oOwPQD8i2Ynpn22cur4sk26FW3mSy6t6/X/K1Ay2yGBKYiSpRyLfObhOrZEGsXDx+3euKy4nEZ193R36NM+tpQ==} engines: {node: '>=18'} @@ -404,6 +422,10 @@ packages: resolution: {integrity: sha512-YYtP6xWQyaAf5LiWLJ+ycGTOeBLWrED7LUrvc+SQIWhGaneylqbaGsyQL7VouQUeQ4JZ1qKYZuhmi3W56HADPA==} engines: {node: '>=18'} + '@ai-sdk/provider@1.0.3': + resolution: {integrity: sha512-WiuJEpHTrltOIzv3x2wx4gwksAHW0h6nK3SoDzjqCOJLu/2OJ1yASESTIX+f07ChFykHElVoP80Ol/fe9dw6tQ==} + engines: {node: '>=18'} + '@ai-sdk/react@1.0.6': resolution: {integrity: sha512-8Hkserq0Ge6AEi7N4hlv2FkfglAGbkoAXEZ8YSp255c3PbnZz6+/5fppw+aROmZMOfNwallSRuy1i/iPa2rBpQ==} engines: {node: '>=18'} @@ -435,6 +457,127 @@ packages: '@antfu/utils@0.7.10': resolution: {integrity: sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww==} + '@aws-crypto/crc32@5.2.0': + resolution: {integrity: sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==} + engines: {node: '>=16.0.0'} + + '@aws-crypto/sha256-browser@5.2.0': + resolution: {integrity: sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==} + + '@aws-crypto/sha256-js@5.2.0': + resolution: {integrity: sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==} + engines: {node: '>=16.0.0'} + + '@aws-crypto/supports-web-crypto@5.2.0': + resolution: {integrity: sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==} + + '@aws-crypto/util@5.2.0': + resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} + + '@aws-sdk/client-bedrock-runtime@3.716.0': + resolution: {integrity: sha512-ZnolSsCZE4IT4A8nn5sOHq+JiOomEV1+pp1SntHdK1SGu6pP5YMWNfwJwujZFrsKkRB+QpSGj7l0W0lr2B/JBw==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/client-sso-oidc@3.716.0': + resolution: {integrity: sha512-lA4IB9FzR2KjH7EVCo+mHGFKqdViVyeBQEIX9oVratL/l7P0bMS1fMwgfHOc3ACazqNxBxDES7x08ZCp32y6Lw==} + engines: {node: '>=16.0.0'} + peerDependencies: + '@aws-sdk/client-sts': ^3.716.0 + + '@aws-sdk/client-sso@3.716.0': + resolution: {integrity: sha512-5Nb0jJXce2TclbjG7WVPufwhgV1TRydz1QnsuBtKU0AdViEpr787YrZhPpGnNIM1Dx+R1H/tmAHZnOoohS6D8g==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/client-sts@3.716.0': + resolution: {integrity: sha512-i4SVNsrdXudp8T4bkm7Fi3YWlRnvXCSwvNDqf6nLqSJxqr4CN3VlBELueDyjBK7TAt453/qSif+eNx+bHmwo4Q==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/core@3.716.0': + resolution: {integrity: sha512-5DkUiTrbyzO8/W4g7UFEqRFpuhgizayHI/Zbh0wtFMcot8801nJV+MP/YMhdjimlvAr/OqYB08FbGsPyWppMTw==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/credential-provider-env@3.716.0': + resolution: {integrity: sha512-JI2KQUnn2arICwP9F3CnqP1W3nAbm4+meQg/yOhp9X0DMzQiHrHRd4HIrK2vyVgi2/6hGhONY5uLF26yRTA7nQ==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/credential-provider-http@3.716.0': + resolution: {integrity: sha512-CZ04pl2z7igQPysQyH2xKZHM3fLwkemxQbKOlje3TmiS1NwXvcKvERhp9PE/H23kOL7beTM19NMRog/Fka/rlw==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/credential-provider-ini@3.716.0': + resolution: {integrity: sha512-P37We2GtZvdROxiwP0zrpEL81/HuYK1qlYxp5VCj3uV+G4mG8UQN2gMIU/baYrpOQqa0h81RfyQGRFUjVaDVqw==} + engines: {node: '>=16.0.0'} + peerDependencies: + '@aws-sdk/client-sts': ^3.716.0 + + '@aws-sdk/credential-provider-node@3.716.0': + resolution: {integrity: sha512-FGQPK2uKfS53dVvoskN/s/t6m0Po24BGd1PzJdzHBFCOjxbZLM6+8mDMXeyi2hCLVVQOUcuW41kOgmJ0+zMbww==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/credential-provider-process@3.716.0': + resolution: {integrity: sha512-0spcu2MWVVHSTHH3WE2E//ttUJPwXRM3BCp+WyI41xLzpNu1Fd8zjOrDpEo0SnGUzsSiRTIJWgkuu/tqv9NJ2A==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/credential-provider-sso@3.716.0': + resolution: {integrity: sha512-J2IA3WuCpRGGoZm6VHZVFCnrxXP+41iUWb9Ct/1spljegTa1XjiaZ5Jf3+Ubj7WKiyvP9/dgz1L0bu2bYEjliw==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/credential-provider-web-identity@3.716.0': + resolution: {integrity: sha512-vzgpWKs2gGXZGdbMKRFrMW4PqEFWkGvwWH2T7ZwQv9m+8lQ7P4Dk2uimqu0f37HZAbpn8HFMqRh4CaySjU354A==} + engines: {node: '>=16.0.0'} + peerDependencies: + '@aws-sdk/client-sts': ^3.716.0 + + '@aws-sdk/middleware-host-header@3.714.0': + resolution: {integrity: sha512-6l68kjNrh5QC8FGX3I3geBDavWN5Tg1RLHJ2HLA8ByGBtJyCwnz3hEkKfaxn0bBx0hF9DzbfjEOUF6cDqy2Kjg==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/middleware-logger@3.714.0': + resolution: {integrity: sha512-RkqHlMvQWUaRklU1bMfUuBvdWwxgUtEqpADaHXlGVj3vtEY2UgBjy+57CveC4MByqKIunNvVHBBbjrGVtwY7Lg==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/middleware-recursion-detection@3.714.0': + resolution: {integrity: sha512-AVU5ixnh93nqtsfgNc284oXsXaadyHGPHpql/jwgaaqQfEXjS/1/j3j9E/vpacfTTz2Vzo7hAOjnvrOXSEVDaA==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/middleware-user-agent@3.716.0': + resolution: {integrity: sha512-FpAtT6nNKrYdkDZndutEraiRMf+TgDzAGvniqRtZ/YTPA+gIsWrsn+TwMKINR81lFC3nQfb9deS5CFtxd021Ew==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/region-config-resolver@3.714.0': + resolution: {integrity: sha512-HJzsQxgMOAzZrbf/YIqEx30or4tZK1oNAk6Wm6xecUQx+23JXIaePRu1YFUOLBBERQ4QBPpISFurZWBMZ5ibAw==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/token-providers@3.714.0': + resolution: {integrity: sha512-vKN064aLE3kl+Zl16Ony3jltHnMddMBT7JRkP1L+lLywhA0PcAKxpdvComul/sTBWnbnwLnaS5NsDUhcWySH8A==} + engines: {node: '>=16.0.0'} + peerDependencies: + '@aws-sdk/client-sso-oidc': ^3.714.0 + + '@aws-sdk/types@3.714.0': + resolution: {integrity: sha512-ZjpP2gYbSFlxxaUDa1Il5AVvfggvUPbjzzB/l3q0gIE5Thd6xKW+yzEpt2mLZ5s5UaYSABZbF94g8NUOF4CVGA==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/util-endpoints@3.714.0': + resolution: {integrity: sha512-Xv+Z2lhe7w7ZZRsgBwBMZgGTVmS+dkkj2S13uNHAx9lhB5ovM8PhK5G/j28xYf6vIibeuHkRAbb7/ozdZIGR+A==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/util-locate-window@3.693.0': + resolution: {integrity: sha512-ttrag6haJLWABhLqtg1Uf+4LgHWIMOVSYL+VYZmAp2v4PUGOwWmWQH0Zk8RM7YuQcLfH/EoR72/Yxz6A4FKcuw==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/util-user-agent-browser@3.714.0': + resolution: {integrity: sha512-OdJJ03cP9/MgIVToPJPCPUImbpZzTcwdIgbXC0tUQPJhbD7b7cB4LdnkhNHko+MptpOrCq4CPY/33EpOjRdofw==} + + '@aws-sdk/util-user-agent-node@3.716.0': + resolution: {integrity: sha512-3PqaXmQbxrtHKAsPCdp7kn5FrQktj8j3YyuNsqFZ8rWZeEQ88GWlsvE61PTsr2peYCKzpFqYVddef2x1axHU0w==} + engines: {node: '>=16.0.0'} + peerDependencies: + aws-crt: '>=1.0.0' + peerDependenciesMeta: + aws-crt: + optional: true + '@babel/code-frame@7.26.2': resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} engines: {node: '>=6.9.0'} @@ -2066,6 +2209,189 @@ packages: '@shikijs/vscode-textmate@9.3.0': resolution: {integrity: sha512-jn7/7ky30idSkd/O5yDBfAnVt+JJpepofP/POZ1iMOxK59cOfqIgg/Dj0eFsjOTMw+4ycJN0uhZH/Eb0bs/EUA==} + '@smithy/abort-controller@3.1.9': + resolution: {integrity: sha512-yiW0WI30zj8ZKoSYNx90no7ugVn3khlyH/z5W8qtKBtVE6awRALbhSG+2SAHA1r6bO/6M9utxYKVZ3PCJ1rWxw==} + engines: {node: '>=16.0.0'} + + '@smithy/config-resolver@3.0.13': + resolution: {integrity: sha512-Gr/qwzyPaTL1tZcq8WQyHhTZREER5R1Wytmz4WnVGL4onA3dNk6Btll55c8Vr58pLdvWZmtG8oZxJTw3t3q7Jg==} + engines: {node: '>=16.0.0'} + + '@smithy/core@2.5.6': + resolution: {integrity: sha512-w494xO+CPwG/5B/N2l0obHv2Fi9U4DAY+sTi1GWT3BVvGpZetJjJXAynIO9IHp4zS1PinGhXtRSZydUXbJO4ag==} + engines: {node: '>=16.0.0'} + + '@smithy/credential-provider-imds@3.2.8': + resolution: {integrity: sha512-ZCY2yD0BY+K9iMXkkbnjo+08T2h8/34oHd0Jmh6BZUSZwaaGlGCyBT/3wnS7u7Xl33/EEfN4B6nQr3Gx5bYxgw==} + engines: {node: '>=16.0.0'} + + '@smithy/eventstream-codec@3.1.10': + resolution: {integrity: sha512-323B8YckSbUH0nMIpXn7HZsAVKHYHFUODa8gG9cHo0ySvA1fr5iWaNT+iIL0UCqUzG6QPHA3BSsBtRQou4mMqQ==} + + '@smithy/eventstream-serde-browser@3.0.14': + resolution: {integrity: sha512-kbrt0vjOIihW3V7Cqj1SXQvAI5BR8SnyQYsandva0AOR307cXAc+IhPngxIPslxTLfxwDpNu0HzCAq6g42kCPg==} + engines: {node: '>=16.0.0'} + + '@smithy/eventstream-serde-config-resolver@3.0.11': + resolution: {integrity: sha512-P2pnEp4n75O+QHjyO7cbw/vsw5l93K/8EWyjNCAAybYwUmj3M+hjSQZ9P5TVdUgEG08ueMAP5R4FkuSkElZ5tQ==} + engines: {node: '>=16.0.0'} + + '@smithy/eventstream-serde-node@3.0.13': + resolution: {integrity: sha512-zqy/9iwbj8Wysmvi7Lq7XFLeDgjRpTbCfwBhJa8WbrylTAHiAu6oQTwdY7iu2lxigbc9YYr9vPv5SzYny5tCXQ==} + engines: {node: '>=16.0.0'} + + '@smithy/eventstream-serde-universal@3.0.13': + resolution: {integrity: sha512-L1Ib66+gg9uTnqp/18Gz4MDpJPKRE44geOjOQ2SVc0eiaO5l255ADziATZgjQjqumC7yPtp1XnjHlF1srcwjKw==} + engines: {node: '>=16.0.0'} + + '@smithy/fetch-http-handler@4.1.2': + resolution: {integrity: sha512-R7rU7Ae3ItU4rC0c5mB2sP5mJNbCfoDc8I5XlYjIZnquyUwec7fEo78F6DA3SmgJgkU1qTMcZJuGblxZsl10ZA==} + + '@smithy/hash-node@3.0.11': + resolution: {integrity: sha512-emP23rwYyZhQBvklqTtwetkQlqbNYirDiEEwXl2v0GYWMnCzxst7ZaRAnWuy28njp5kAH54lvkdG37MblZzaHA==} + engines: {node: '>=16.0.0'} + + '@smithy/invalid-dependency@3.0.11': + resolution: {integrity: sha512-NuQmVPEJjUX6c+UELyVz8kUx8Q539EDeNwbRyu4IIF8MeV7hUtq1FB3SHVyki2u++5XLMFqngeMKk7ccspnNyQ==} + + '@smithy/is-array-buffer@2.2.0': + resolution: {integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==} + engines: {node: '>=14.0.0'} + + '@smithy/is-array-buffer@3.0.0': + resolution: {integrity: sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==} + engines: {node: '>=16.0.0'} + + '@smithy/middleware-content-length@3.0.13': + resolution: {integrity: sha512-zfMhzojhFpIX3P5ug7jxTjfUcIPcGjcQYzB9t+rv0g1TX7B0QdwONW+ATouaLoD7h7LOw/ZlXfkq4xJ/g2TrIw==} + engines: {node: '>=16.0.0'} + + '@smithy/middleware-endpoint@3.2.7': + resolution: {integrity: sha512-GTxSKf280aJBANGN97MomUQhW1VNxZ6w7HAj/pvZM5MUHbMPOGnWOp1PRYKi4czMaHNj9bdiA+ZarmT3Wkdqiw==} + engines: {node: '>=16.0.0'} + + '@smithy/middleware-retry@3.0.32': + resolution: {integrity: sha512-v8gVA9HqibuZkFuFpfkC/EcHE8no/3Mv3JvRUGly63Axt4yyas1WDVOasFSdiqm2hZVpY7/k8mRT1Wd5k7r3Yw==} + engines: {node: '>=16.0.0'} + + '@smithy/middleware-serde@3.0.11': + resolution: {integrity: sha512-KzPAeySp/fOoQA82TpnwItvX8BBURecpx6ZMu75EZDkAcnPtO6vf7q4aH5QHs/F1s3/snQaSFbbUMcFFZ086Mw==} + engines: {node: '>=16.0.0'} + + '@smithy/middleware-stack@3.0.11': + resolution: {integrity: sha512-1HGo9a6/ikgOMrTrWL/WiN9N8GSVYpuRQO5kjstAq4CvV59bjqnh7TbdXGQ4vxLD3xlSjfBjq5t1SOELePsLnA==} + engines: {node: '>=16.0.0'} + + '@smithy/node-config-provider@3.1.12': + resolution: {integrity: sha512-O9LVEu5J/u/FuNlZs+L7Ikn3lz7VB9hb0GtPT9MQeiBmtK8RSY3ULmsZgXhe6VAlgTw0YO+paQx4p8xdbs43vQ==} + engines: {node: '>=16.0.0'} + + '@smithy/node-http-handler@3.3.3': + resolution: {integrity: sha512-BrpZOaZ4RCbcJ2igiSNG16S+kgAc65l/2hmxWdmhyoGWHTLlzQzr06PXavJp9OBlPEG/sHlqdxjWmjzV66+BSQ==} + engines: {node: '>=16.0.0'} + + '@smithy/property-provider@3.1.11': + resolution: {integrity: sha512-I/+TMc4XTQ3QAjXfOcUWbSS073oOEAxgx4aZy8jHaf8JQnRkq2SZWw8+PfDtBvLUjcGMdxl+YwtzWe6i5uhL/A==} + engines: {node: '>=16.0.0'} + + '@smithy/protocol-http@4.1.8': + resolution: {integrity: sha512-hmgIAVyxw1LySOwkgMIUN0kjN8TG9Nc85LJeEmEE/cNEe2rkHDUWhnJf2gxcSRFLWsyqWsrZGw40ROjUogg+Iw==} + engines: {node: '>=16.0.0'} + + '@smithy/querystring-builder@3.0.11': + resolution: {integrity: sha512-u+5HV/9uJaeLj5XTb6+IEF/dokWWkEqJ0XiaRRogyREmKGUgZnNecLucADLdauWFKUNbQfulHFEZEdjwEBjXRg==} + engines: {node: '>=16.0.0'} + + '@smithy/querystring-parser@3.0.11': + resolution: {integrity: sha512-Je3kFvCsFMnso1ilPwA7GtlbPaTixa3WwC+K21kmMZHsBEOZYQaqxcMqeFFoU7/slFjKDIpiiPydvdJm8Q/MCw==} + engines: {node: '>=16.0.0'} + + '@smithy/service-error-classification@3.0.11': + resolution: {integrity: sha512-QnYDPkyewrJzCyaeI2Rmp7pDwbUETe+hU8ADkXmgNusO1bgHBH7ovXJiYmba8t0fNfJx75fE8dlM6SEmZxheog==} + engines: {node: '>=16.0.0'} + + '@smithy/shared-ini-file-loader@3.1.12': + resolution: {integrity: sha512-1xKSGI+U9KKdbG2qDvIR9dGrw3CNx+baqJfyr0igKEpjbHL5stsqAesYBzHChYHlelWtb87VnLWlhvfCz13H8Q==} + engines: {node: '>=16.0.0'} + + '@smithy/signature-v4@4.2.4': + resolution: {integrity: sha512-5JWeMQYg81TgU4cG+OexAWdvDTs5JDdbEZx+Qr1iPbvo91QFGzjy0IkXAKaXUHqmKUJgSHK0ZxnCkgZpzkeNTA==} + engines: {node: '>=16.0.0'} + + '@smithy/smithy-client@3.5.2': + resolution: {integrity: sha512-h7xn+1wlpbXyLrtvo/teHR1SFGIIrQ3imzG0nz43zVLAJgvfC1Mtdwa1pFhoIOYrt/TiNjt4pD0gSYQEdZSBtg==} + engines: {node: '>=16.0.0'} + + '@smithy/types@3.7.2': + resolution: {integrity: sha512-bNwBYYmN8Eh9RyjS1p2gW6MIhSO2rl7X9QeLM8iTdcGRP+eDiIWDt66c9IysCc22gefKszZv+ubV9qZc7hdESg==} + engines: {node: '>=16.0.0'} + + '@smithy/url-parser@3.0.11': + resolution: {integrity: sha512-TmlqXkSk8ZPhfc+SQutjmFr5FjC0av3GZP4B/10caK1SbRwe/v+Wzu/R6xEKxoNqL+8nY18s1byiy6HqPG37Aw==} + + '@smithy/util-base64@3.0.0': + resolution: {integrity: sha512-Kxvoh5Qtt0CDsfajiZOCpJxgtPHXOKwmM+Zy4waD43UoEMA+qPxxa98aE/7ZhdnBFZFXMOiBR5xbcaMhLtznQQ==} + engines: {node: '>=16.0.0'} + + '@smithy/util-body-length-browser@3.0.0': + resolution: {integrity: sha512-cbjJs2A1mLYmqmyVl80uoLTJhAcfzMOyPgjwAYusWKMdLeNtzmMz9YxNl3/jRLoxSS3wkqkf0jwNdtXWtyEBaQ==} + + '@smithy/util-body-length-node@3.0.0': + resolution: {integrity: sha512-Tj7pZ4bUloNUP6PzwhN7K386tmSmEET9QtQg0TgdNOnxhZvCssHji+oZTUIuzxECRfG8rdm2PMw2WCFs6eIYkA==} + engines: {node: '>=16.0.0'} + + '@smithy/util-buffer-from@2.2.0': + resolution: {integrity: sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==} + engines: {node: '>=14.0.0'} + + '@smithy/util-buffer-from@3.0.0': + resolution: {integrity: sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==} + engines: {node: '>=16.0.0'} + + '@smithy/util-config-provider@3.0.0': + resolution: {integrity: sha512-pbjk4s0fwq3Di/ANL+rCvJMKM5bzAQdE5S/6RL5NXgMExFAi6UgQMPOm5yPaIWPpr+EOXKXRonJ3FoxKf4mCJQ==} + engines: {node: '>=16.0.0'} + + '@smithy/util-defaults-mode-browser@3.0.32': + resolution: {integrity: sha512-FAGsnm/xJ19SZeoqGyo9CosqjUlm+XJTmygDMktebvDKw3bKiIiZ40O1MA6Z52KLmekYU2GO7BEK7u6e7ZORKw==} + engines: {node: '>= 10.0.0'} + + '@smithy/util-defaults-mode-node@3.0.32': + resolution: {integrity: sha512-2CzKhkPFCVdd15f3+0D1rldNlvJME8pVRBtVVsea2hy7lcOn0bGB0dTVUwzgfM4LW/aU4IOg3jWf25ZWaxbOiw==} + engines: {node: '>= 10.0.0'} + + '@smithy/util-endpoints@2.1.7': + resolution: {integrity: sha512-tSfcqKcN/Oo2STEYCABVuKgJ76nyyr6skGl9t15hs+YaiU06sgMkN7QYjo0BbVw+KT26zok3IzbdSOksQ4YzVw==} + engines: {node: '>=16.0.0'} + + '@smithy/util-hex-encoding@3.0.0': + resolution: {integrity: sha512-eFndh1WEK5YMUYvy3lPlVmYY/fZcQE1D8oSf41Id2vCeIkKJXPcYDCZD+4+xViI6b1XSd7tE+s5AmXzz5ilabQ==} + engines: {node: '>=16.0.0'} + + '@smithy/util-middleware@3.0.11': + resolution: {integrity: sha512-dWpyc1e1R6VoXrwLoLDd57U1z6CwNSdkM69Ie4+6uYh2GC7Vg51Qtan7ITzczuVpqezdDTKJGJB95fFvvjU/ow==} + engines: {node: '>=16.0.0'} + + '@smithy/util-retry@3.0.11': + resolution: {integrity: sha512-hJUC6W7A3DQgaee3Hp9ZFcOxVDZzmBIRBPlUAk8/fSOEl7pE/aX7Dci0JycNOnm9Mfr0KV2XjIlUOcGWXQUdVQ==} + engines: {node: '>=16.0.0'} + + '@smithy/util-stream@3.3.3': + resolution: {integrity: sha512-bOm0YMMxRjbI3X6QkWwADPFkh2AH2xBMQIB1IQgCsCRqXXpSJatgjUR3oxHthpYwFkw3WPkOt8VgMpJxC0rFqg==} + engines: {node: '>=16.0.0'} + + '@smithy/util-uri-escape@3.0.0': + resolution: {integrity: sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==} + engines: {node: '>=16.0.0'} + + '@smithy/util-utf8@2.3.0': + resolution: {integrity: sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==} + engines: {node: '>=14.0.0'} + + '@smithy/util-utf8@3.0.0': + resolution: {integrity: sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==} + engines: {node: '>=16.0.0'} + '@stylistic/eslint-plugin-ts@2.11.0': resolution: {integrity: sha512-ZBxnfSjzxUiwCibbVCeYCYwZw+P5xaQw+pNA8B8uR42fdMQIOhUstXjJuS2nTHoW5CF4+vGSxbL4gklI8WxhyA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2147,6 +2473,9 @@ packages: '@types/unist@3.0.3': resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + '@types/uuid@9.0.8': + resolution: {integrity: sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==} + '@typescript-eslint/eslint-plugin@8.17.0': resolution: {integrity: sha512-HU1KAdW3Tt8zQkdvNoIijfWDMvdSweFYm4hWh+KwhPstv+sCmWb89hCIP8msFm9N1R/ooh9honpSuvqKWlYy3w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2505,6 +2834,9 @@ packages: resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + bowser@2.11.0: + resolution: {integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==} + brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} @@ -3197,6 +3529,10 @@ packages: fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + fast-xml-parser@4.4.1: + resolution: {integrity: sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==} + hasBin: true + fastq@1.17.1: resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} @@ -5178,6 +5514,9 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} + strnum@1.0.5: + resolution: {integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==} + style-mod@4.1.2: resolution: {integrity: sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==} @@ -5490,6 +5829,10 @@ packages: resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} engines: {node: '>= 0.4.0'} + uuid@9.0.1: + resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} + hasBin: true + uvu@0.5.6: resolution: {integrity: sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==} engines: {node: '>=8'} @@ -5750,6 +6093,15 @@ packages: snapshots: + '@ai-sdk/amazon-bedrock@1.0.6(zod@3.23.8)': + dependencies: + '@ai-sdk/provider': 1.0.3 + '@ai-sdk/provider-utils': 2.0.5(zod@3.23.8) + '@aws-sdk/client-bedrock-runtime': 3.716.0 + zod: 3.23.8 + transitivePeerDependencies: + - aws-crt + '@ai-sdk/anthropic@0.0.39(zod@3.23.8)': dependencies: '@ai-sdk/provider': 0.0.17 @@ -5826,6 +6178,15 @@ snapshots: optionalDependencies: zod: 3.23.8 + '@ai-sdk/provider-utils@2.0.5(zod@3.23.8)': + dependencies: + '@ai-sdk/provider': 1.0.3 + eventsource-parser: 3.0.0 + nanoid: 3.3.8 + secure-json-parse: 2.7.0 + optionalDependencies: + zod: 3.23.8 + '@ai-sdk/provider@0.0.12': dependencies: json-schema: 0.4.0 @@ -5846,6 +6207,10 @@ snapshots: dependencies: json-schema: 0.4.0 + '@ai-sdk/provider@1.0.3': + dependencies: + json-schema: 0.4.0 + '@ai-sdk/react@1.0.6(react@18.3.1)(zod@3.23.8)': dependencies: '@ai-sdk/provider-utils': 2.0.4(zod@3.23.8) @@ -5876,6 +6241,407 @@ snapshots: '@antfu/utils@0.7.10': {} + '@aws-crypto/crc32@5.2.0': + dependencies: + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.714.0 + tslib: 2.8.1 + + '@aws-crypto/sha256-browser@5.2.0': + dependencies: + '@aws-crypto/sha256-js': 5.2.0 + '@aws-crypto/supports-web-crypto': 5.2.0 + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.714.0 + '@aws-sdk/util-locate-window': 3.693.0 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + + '@aws-crypto/sha256-js@5.2.0': + dependencies: + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.714.0 + tslib: 2.8.1 + + '@aws-crypto/supports-web-crypto@5.2.0': + dependencies: + tslib: 2.8.1 + + '@aws-crypto/util@5.2.0': + dependencies: + '@aws-sdk/types': 3.714.0 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + + '@aws-sdk/client-bedrock-runtime@3.716.0': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/client-sso-oidc': 3.716.0(@aws-sdk/client-sts@3.716.0) + '@aws-sdk/client-sts': 3.716.0 + '@aws-sdk/core': 3.716.0 + '@aws-sdk/credential-provider-node': 3.716.0(@aws-sdk/client-sso-oidc@3.716.0(@aws-sdk/client-sts@3.716.0))(@aws-sdk/client-sts@3.716.0) + '@aws-sdk/middleware-host-header': 3.714.0 + '@aws-sdk/middleware-logger': 3.714.0 + '@aws-sdk/middleware-recursion-detection': 3.714.0 + '@aws-sdk/middleware-user-agent': 3.716.0 + '@aws-sdk/region-config-resolver': 3.714.0 + '@aws-sdk/types': 3.714.0 + '@aws-sdk/util-endpoints': 3.714.0 + '@aws-sdk/util-user-agent-browser': 3.714.0 + '@aws-sdk/util-user-agent-node': 3.716.0 + '@smithy/config-resolver': 3.0.13 + '@smithy/core': 2.5.6 + '@smithy/eventstream-serde-browser': 3.0.14 + '@smithy/eventstream-serde-config-resolver': 3.0.11 + '@smithy/eventstream-serde-node': 3.0.13 + '@smithy/fetch-http-handler': 4.1.2 + '@smithy/hash-node': 3.0.11 + '@smithy/invalid-dependency': 3.0.11 + '@smithy/middleware-content-length': 3.0.13 + '@smithy/middleware-endpoint': 3.2.7 + '@smithy/middleware-retry': 3.0.32 + '@smithy/middleware-serde': 3.0.11 + '@smithy/middleware-stack': 3.0.11 + '@smithy/node-config-provider': 3.1.12 + '@smithy/node-http-handler': 3.3.3 + '@smithy/protocol-http': 4.1.8 + '@smithy/smithy-client': 3.5.2 + '@smithy/types': 3.7.2 + '@smithy/url-parser': 3.0.11 + '@smithy/util-base64': 3.0.0 + '@smithy/util-body-length-browser': 3.0.0 + '@smithy/util-body-length-node': 3.0.0 + '@smithy/util-defaults-mode-browser': 3.0.32 + '@smithy/util-defaults-mode-node': 3.0.32 + '@smithy/util-endpoints': 2.1.7 + '@smithy/util-middleware': 3.0.11 + '@smithy/util-retry': 3.0.11 + '@smithy/util-stream': 3.3.3 + '@smithy/util-utf8': 3.0.0 + '@types/uuid': 9.0.8 + tslib: 2.8.1 + uuid: 9.0.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/client-sso-oidc@3.716.0(@aws-sdk/client-sts@3.716.0)': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/client-sts': 3.716.0 + '@aws-sdk/core': 3.716.0 + '@aws-sdk/credential-provider-node': 3.716.0(@aws-sdk/client-sso-oidc@3.716.0(@aws-sdk/client-sts@3.716.0))(@aws-sdk/client-sts@3.716.0) + '@aws-sdk/middleware-host-header': 3.714.0 + '@aws-sdk/middleware-logger': 3.714.0 + '@aws-sdk/middleware-recursion-detection': 3.714.0 + '@aws-sdk/middleware-user-agent': 3.716.0 + '@aws-sdk/region-config-resolver': 3.714.0 + '@aws-sdk/types': 3.714.0 + '@aws-sdk/util-endpoints': 3.714.0 + '@aws-sdk/util-user-agent-browser': 3.714.0 + '@aws-sdk/util-user-agent-node': 3.716.0 + '@smithy/config-resolver': 3.0.13 + '@smithy/core': 2.5.6 + '@smithy/fetch-http-handler': 4.1.2 + '@smithy/hash-node': 3.0.11 + '@smithy/invalid-dependency': 3.0.11 + '@smithy/middleware-content-length': 3.0.13 + '@smithy/middleware-endpoint': 3.2.7 + '@smithy/middleware-retry': 3.0.32 + '@smithy/middleware-serde': 3.0.11 + '@smithy/middleware-stack': 3.0.11 + '@smithy/node-config-provider': 3.1.12 + '@smithy/node-http-handler': 3.3.3 + '@smithy/protocol-http': 4.1.8 + '@smithy/smithy-client': 3.5.2 + '@smithy/types': 3.7.2 + '@smithy/url-parser': 3.0.11 + '@smithy/util-base64': 3.0.0 + '@smithy/util-body-length-browser': 3.0.0 + '@smithy/util-body-length-node': 3.0.0 + '@smithy/util-defaults-mode-browser': 3.0.32 + '@smithy/util-defaults-mode-node': 3.0.32 + '@smithy/util-endpoints': 2.1.7 + '@smithy/util-middleware': 3.0.11 + '@smithy/util-retry': 3.0.11 + '@smithy/util-utf8': 3.0.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/client-sso@3.716.0': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.716.0 + '@aws-sdk/middleware-host-header': 3.714.0 + '@aws-sdk/middleware-logger': 3.714.0 + '@aws-sdk/middleware-recursion-detection': 3.714.0 + '@aws-sdk/middleware-user-agent': 3.716.0 + '@aws-sdk/region-config-resolver': 3.714.0 + '@aws-sdk/types': 3.714.0 + '@aws-sdk/util-endpoints': 3.714.0 + '@aws-sdk/util-user-agent-browser': 3.714.0 + '@aws-sdk/util-user-agent-node': 3.716.0 + '@smithy/config-resolver': 3.0.13 + '@smithy/core': 2.5.6 + '@smithy/fetch-http-handler': 4.1.2 + '@smithy/hash-node': 3.0.11 + '@smithy/invalid-dependency': 3.0.11 + '@smithy/middleware-content-length': 3.0.13 + '@smithy/middleware-endpoint': 3.2.7 + '@smithy/middleware-retry': 3.0.32 + '@smithy/middleware-serde': 3.0.11 + '@smithy/middleware-stack': 3.0.11 + '@smithy/node-config-provider': 3.1.12 + '@smithy/node-http-handler': 3.3.3 + '@smithy/protocol-http': 4.1.8 + '@smithy/smithy-client': 3.5.2 + '@smithy/types': 3.7.2 + '@smithy/url-parser': 3.0.11 + '@smithy/util-base64': 3.0.0 + '@smithy/util-body-length-browser': 3.0.0 + '@smithy/util-body-length-node': 3.0.0 + '@smithy/util-defaults-mode-browser': 3.0.32 + '@smithy/util-defaults-mode-node': 3.0.32 + '@smithy/util-endpoints': 2.1.7 + '@smithy/util-middleware': 3.0.11 + '@smithy/util-retry': 3.0.11 + '@smithy/util-utf8': 3.0.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/client-sts@3.716.0': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/client-sso-oidc': 3.716.0(@aws-sdk/client-sts@3.716.0) + '@aws-sdk/core': 3.716.0 + '@aws-sdk/credential-provider-node': 3.716.0(@aws-sdk/client-sso-oidc@3.716.0(@aws-sdk/client-sts@3.716.0))(@aws-sdk/client-sts@3.716.0) + '@aws-sdk/middleware-host-header': 3.714.0 + '@aws-sdk/middleware-logger': 3.714.0 + '@aws-sdk/middleware-recursion-detection': 3.714.0 + '@aws-sdk/middleware-user-agent': 3.716.0 + '@aws-sdk/region-config-resolver': 3.714.0 + '@aws-sdk/types': 3.714.0 + '@aws-sdk/util-endpoints': 3.714.0 + '@aws-sdk/util-user-agent-browser': 3.714.0 + '@aws-sdk/util-user-agent-node': 3.716.0 + '@smithy/config-resolver': 3.0.13 + '@smithy/core': 2.5.6 + '@smithy/fetch-http-handler': 4.1.2 + '@smithy/hash-node': 3.0.11 + '@smithy/invalid-dependency': 3.0.11 + '@smithy/middleware-content-length': 3.0.13 + '@smithy/middleware-endpoint': 3.2.7 + '@smithy/middleware-retry': 3.0.32 + '@smithy/middleware-serde': 3.0.11 + '@smithy/middleware-stack': 3.0.11 + '@smithy/node-config-provider': 3.1.12 + '@smithy/node-http-handler': 3.3.3 + '@smithy/protocol-http': 4.1.8 + '@smithy/smithy-client': 3.5.2 + '@smithy/types': 3.7.2 + '@smithy/url-parser': 3.0.11 + '@smithy/util-base64': 3.0.0 + '@smithy/util-body-length-browser': 3.0.0 + '@smithy/util-body-length-node': 3.0.0 + '@smithy/util-defaults-mode-browser': 3.0.32 + '@smithy/util-defaults-mode-node': 3.0.32 + '@smithy/util-endpoints': 2.1.7 + '@smithy/util-middleware': 3.0.11 + '@smithy/util-retry': 3.0.11 + '@smithy/util-utf8': 3.0.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/core@3.716.0': + dependencies: + '@aws-sdk/types': 3.714.0 + '@smithy/core': 2.5.6 + '@smithy/node-config-provider': 3.1.12 + '@smithy/property-provider': 3.1.11 + '@smithy/protocol-http': 4.1.8 + '@smithy/signature-v4': 4.2.4 + '@smithy/smithy-client': 3.5.2 + '@smithy/types': 3.7.2 + '@smithy/util-middleware': 3.0.11 + fast-xml-parser: 4.4.1 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-env@3.716.0': + dependencies: + '@aws-sdk/core': 3.716.0 + '@aws-sdk/types': 3.714.0 + '@smithy/property-provider': 3.1.11 + '@smithy/types': 3.7.2 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-http@3.716.0': + dependencies: + '@aws-sdk/core': 3.716.0 + '@aws-sdk/types': 3.714.0 + '@smithy/fetch-http-handler': 4.1.2 + '@smithy/node-http-handler': 3.3.3 + '@smithy/property-provider': 3.1.11 + '@smithy/protocol-http': 4.1.8 + '@smithy/smithy-client': 3.5.2 + '@smithy/types': 3.7.2 + '@smithy/util-stream': 3.3.3 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-ini@3.716.0(@aws-sdk/client-sso-oidc@3.716.0(@aws-sdk/client-sts@3.716.0))(@aws-sdk/client-sts@3.716.0)': + dependencies: + '@aws-sdk/client-sts': 3.716.0 + '@aws-sdk/core': 3.716.0 + '@aws-sdk/credential-provider-env': 3.716.0 + '@aws-sdk/credential-provider-http': 3.716.0 + '@aws-sdk/credential-provider-process': 3.716.0 + '@aws-sdk/credential-provider-sso': 3.716.0(@aws-sdk/client-sso-oidc@3.716.0(@aws-sdk/client-sts@3.716.0)) + '@aws-sdk/credential-provider-web-identity': 3.716.0(@aws-sdk/client-sts@3.716.0) + '@aws-sdk/types': 3.714.0 + '@smithy/credential-provider-imds': 3.2.8 + '@smithy/property-provider': 3.1.11 + '@smithy/shared-ini-file-loader': 3.1.12 + '@smithy/types': 3.7.2 + tslib: 2.8.1 + transitivePeerDependencies: + - '@aws-sdk/client-sso-oidc' + - aws-crt + + '@aws-sdk/credential-provider-node@3.716.0(@aws-sdk/client-sso-oidc@3.716.0(@aws-sdk/client-sts@3.716.0))(@aws-sdk/client-sts@3.716.0)': + dependencies: + '@aws-sdk/credential-provider-env': 3.716.0 + '@aws-sdk/credential-provider-http': 3.716.0 + '@aws-sdk/credential-provider-ini': 3.716.0(@aws-sdk/client-sso-oidc@3.716.0(@aws-sdk/client-sts@3.716.0))(@aws-sdk/client-sts@3.716.0) + '@aws-sdk/credential-provider-process': 3.716.0 + '@aws-sdk/credential-provider-sso': 3.716.0(@aws-sdk/client-sso-oidc@3.716.0(@aws-sdk/client-sts@3.716.0)) + '@aws-sdk/credential-provider-web-identity': 3.716.0(@aws-sdk/client-sts@3.716.0) + '@aws-sdk/types': 3.714.0 + '@smithy/credential-provider-imds': 3.2.8 + '@smithy/property-provider': 3.1.11 + '@smithy/shared-ini-file-loader': 3.1.12 + '@smithy/types': 3.7.2 + tslib: 2.8.1 + transitivePeerDependencies: + - '@aws-sdk/client-sso-oidc' + - '@aws-sdk/client-sts' + - aws-crt + + '@aws-sdk/credential-provider-process@3.716.0': + dependencies: + '@aws-sdk/core': 3.716.0 + '@aws-sdk/types': 3.714.0 + '@smithy/property-provider': 3.1.11 + '@smithy/shared-ini-file-loader': 3.1.12 + '@smithy/types': 3.7.2 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-sso@3.716.0(@aws-sdk/client-sso-oidc@3.716.0(@aws-sdk/client-sts@3.716.0))': + dependencies: + '@aws-sdk/client-sso': 3.716.0 + '@aws-sdk/core': 3.716.0 + '@aws-sdk/token-providers': 3.714.0(@aws-sdk/client-sso-oidc@3.716.0(@aws-sdk/client-sts@3.716.0)) + '@aws-sdk/types': 3.714.0 + '@smithy/property-provider': 3.1.11 + '@smithy/shared-ini-file-loader': 3.1.12 + '@smithy/types': 3.7.2 + tslib: 2.8.1 + transitivePeerDependencies: + - '@aws-sdk/client-sso-oidc' + - aws-crt + + '@aws-sdk/credential-provider-web-identity@3.716.0(@aws-sdk/client-sts@3.716.0)': + dependencies: + '@aws-sdk/client-sts': 3.716.0 + '@aws-sdk/core': 3.716.0 + '@aws-sdk/types': 3.714.0 + '@smithy/property-provider': 3.1.11 + '@smithy/types': 3.7.2 + tslib: 2.8.1 + + '@aws-sdk/middleware-host-header@3.714.0': + dependencies: + '@aws-sdk/types': 3.714.0 + '@smithy/protocol-http': 4.1.8 + '@smithy/types': 3.7.2 + tslib: 2.8.1 + + '@aws-sdk/middleware-logger@3.714.0': + dependencies: + '@aws-sdk/types': 3.714.0 + '@smithy/types': 3.7.2 + tslib: 2.8.1 + + '@aws-sdk/middleware-recursion-detection@3.714.0': + dependencies: + '@aws-sdk/types': 3.714.0 + '@smithy/protocol-http': 4.1.8 + '@smithy/types': 3.7.2 + tslib: 2.8.1 + + '@aws-sdk/middleware-user-agent@3.716.0': + dependencies: + '@aws-sdk/core': 3.716.0 + '@aws-sdk/types': 3.714.0 + '@aws-sdk/util-endpoints': 3.714.0 + '@smithy/core': 2.5.6 + '@smithy/protocol-http': 4.1.8 + '@smithy/types': 3.7.2 + tslib: 2.8.1 + + '@aws-sdk/region-config-resolver@3.714.0': + dependencies: + '@aws-sdk/types': 3.714.0 + '@smithy/node-config-provider': 3.1.12 + '@smithy/types': 3.7.2 + '@smithy/util-config-provider': 3.0.0 + '@smithy/util-middleware': 3.0.11 + tslib: 2.8.1 + + '@aws-sdk/token-providers@3.714.0(@aws-sdk/client-sso-oidc@3.716.0(@aws-sdk/client-sts@3.716.0))': + dependencies: + '@aws-sdk/client-sso-oidc': 3.716.0(@aws-sdk/client-sts@3.716.0) + '@aws-sdk/types': 3.714.0 + '@smithy/property-provider': 3.1.11 + '@smithy/shared-ini-file-loader': 3.1.12 + '@smithy/types': 3.7.2 + tslib: 2.8.1 + + '@aws-sdk/types@3.714.0': + dependencies: + '@smithy/types': 3.7.2 + tslib: 2.8.1 + + '@aws-sdk/util-endpoints@3.714.0': + dependencies: + '@aws-sdk/types': 3.714.0 + '@smithy/types': 3.7.2 + '@smithy/util-endpoints': 2.1.7 + tslib: 2.8.1 + + '@aws-sdk/util-locate-window@3.693.0': + dependencies: + tslib: 2.8.1 + + '@aws-sdk/util-user-agent-browser@3.714.0': + dependencies: + '@aws-sdk/types': 3.714.0 + '@smithy/types': 3.7.2 + bowser: 2.11.0 + tslib: 2.8.1 + + '@aws-sdk/util-user-agent-node@3.716.0': + dependencies: + '@aws-sdk/middleware-user-agent': 3.716.0 + '@aws-sdk/types': 3.714.0 + '@smithy/node-config-provider': 3.1.12 + '@smithy/types': 3.7.2 + tslib: 2.8.1 + '@babel/code-frame@7.26.2': dependencies: '@babel/helper-validator-identifier': 7.25.9 @@ -7470,6 +8236,303 @@ snapshots: '@shikijs/vscode-textmate@9.3.0': {} + '@smithy/abort-controller@3.1.9': + dependencies: + '@smithy/types': 3.7.2 + tslib: 2.8.1 + + '@smithy/config-resolver@3.0.13': + dependencies: + '@smithy/node-config-provider': 3.1.12 + '@smithy/types': 3.7.2 + '@smithy/util-config-provider': 3.0.0 + '@smithy/util-middleware': 3.0.11 + tslib: 2.8.1 + + '@smithy/core@2.5.6': + dependencies: + '@smithy/middleware-serde': 3.0.11 + '@smithy/protocol-http': 4.1.8 + '@smithy/types': 3.7.2 + '@smithy/util-body-length-browser': 3.0.0 + '@smithy/util-middleware': 3.0.11 + '@smithy/util-stream': 3.3.3 + '@smithy/util-utf8': 3.0.0 + tslib: 2.8.1 + + '@smithy/credential-provider-imds@3.2.8': + dependencies: + '@smithy/node-config-provider': 3.1.12 + '@smithy/property-provider': 3.1.11 + '@smithy/types': 3.7.2 + '@smithy/url-parser': 3.0.11 + tslib: 2.8.1 + + '@smithy/eventstream-codec@3.1.10': + dependencies: + '@aws-crypto/crc32': 5.2.0 + '@smithy/types': 3.7.2 + '@smithy/util-hex-encoding': 3.0.0 + tslib: 2.8.1 + + '@smithy/eventstream-serde-browser@3.0.14': + dependencies: + '@smithy/eventstream-serde-universal': 3.0.13 + '@smithy/types': 3.7.2 + tslib: 2.8.1 + + '@smithy/eventstream-serde-config-resolver@3.0.11': + dependencies: + '@smithy/types': 3.7.2 + tslib: 2.8.1 + + '@smithy/eventstream-serde-node@3.0.13': + dependencies: + '@smithy/eventstream-serde-universal': 3.0.13 + '@smithy/types': 3.7.2 + tslib: 2.8.1 + + '@smithy/eventstream-serde-universal@3.0.13': + dependencies: + '@smithy/eventstream-codec': 3.1.10 + '@smithy/types': 3.7.2 + tslib: 2.8.1 + + '@smithy/fetch-http-handler@4.1.2': + dependencies: + '@smithy/protocol-http': 4.1.8 + '@smithy/querystring-builder': 3.0.11 + '@smithy/types': 3.7.2 + '@smithy/util-base64': 3.0.0 + tslib: 2.8.1 + + '@smithy/hash-node@3.0.11': + dependencies: + '@smithy/types': 3.7.2 + '@smithy/util-buffer-from': 3.0.0 + '@smithy/util-utf8': 3.0.0 + tslib: 2.8.1 + + '@smithy/invalid-dependency@3.0.11': + dependencies: + '@smithy/types': 3.7.2 + tslib: 2.8.1 + + '@smithy/is-array-buffer@2.2.0': + dependencies: + tslib: 2.8.1 + + '@smithy/is-array-buffer@3.0.0': + dependencies: + tslib: 2.8.1 + + '@smithy/middleware-content-length@3.0.13': + dependencies: + '@smithy/protocol-http': 4.1.8 + '@smithy/types': 3.7.2 + tslib: 2.8.1 + + '@smithy/middleware-endpoint@3.2.7': + dependencies: + '@smithy/core': 2.5.6 + '@smithy/middleware-serde': 3.0.11 + '@smithy/node-config-provider': 3.1.12 + '@smithy/shared-ini-file-loader': 3.1.12 + '@smithy/types': 3.7.2 + '@smithy/url-parser': 3.0.11 + '@smithy/util-middleware': 3.0.11 + tslib: 2.8.1 + + '@smithy/middleware-retry@3.0.32': + dependencies: + '@smithy/node-config-provider': 3.1.12 + '@smithy/protocol-http': 4.1.8 + '@smithy/service-error-classification': 3.0.11 + '@smithy/smithy-client': 3.5.2 + '@smithy/types': 3.7.2 + '@smithy/util-middleware': 3.0.11 + '@smithy/util-retry': 3.0.11 + tslib: 2.8.1 + uuid: 9.0.1 + + '@smithy/middleware-serde@3.0.11': + dependencies: + '@smithy/types': 3.7.2 + tslib: 2.8.1 + + '@smithy/middleware-stack@3.0.11': + dependencies: + '@smithy/types': 3.7.2 + tslib: 2.8.1 + + '@smithy/node-config-provider@3.1.12': + dependencies: + '@smithy/property-provider': 3.1.11 + '@smithy/shared-ini-file-loader': 3.1.12 + '@smithy/types': 3.7.2 + tslib: 2.8.1 + + '@smithy/node-http-handler@3.3.3': + dependencies: + '@smithy/abort-controller': 3.1.9 + '@smithy/protocol-http': 4.1.8 + '@smithy/querystring-builder': 3.0.11 + '@smithy/types': 3.7.2 + tslib: 2.8.1 + + '@smithy/property-provider@3.1.11': + dependencies: + '@smithy/types': 3.7.2 + tslib: 2.8.1 + + '@smithy/protocol-http@4.1.8': + dependencies: + '@smithy/types': 3.7.2 + tslib: 2.8.1 + + '@smithy/querystring-builder@3.0.11': + dependencies: + '@smithy/types': 3.7.2 + '@smithy/util-uri-escape': 3.0.0 + tslib: 2.8.1 + + '@smithy/querystring-parser@3.0.11': + dependencies: + '@smithy/types': 3.7.2 + tslib: 2.8.1 + + '@smithy/service-error-classification@3.0.11': + dependencies: + '@smithy/types': 3.7.2 + + '@smithy/shared-ini-file-loader@3.1.12': + dependencies: + '@smithy/types': 3.7.2 + tslib: 2.8.1 + + '@smithy/signature-v4@4.2.4': + dependencies: + '@smithy/is-array-buffer': 3.0.0 + '@smithy/protocol-http': 4.1.8 + '@smithy/types': 3.7.2 + '@smithy/util-hex-encoding': 3.0.0 + '@smithy/util-middleware': 3.0.11 + '@smithy/util-uri-escape': 3.0.0 + '@smithy/util-utf8': 3.0.0 + tslib: 2.8.1 + + '@smithy/smithy-client@3.5.2': + dependencies: + '@smithy/core': 2.5.6 + '@smithy/middleware-endpoint': 3.2.7 + '@smithy/middleware-stack': 3.0.11 + '@smithy/protocol-http': 4.1.8 + '@smithy/types': 3.7.2 + '@smithy/util-stream': 3.3.3 + tslib: 2.8.1 + + '@smithy/types@3.7.2': + dependencies: + tslib: 2.8.1 + + '@smithy/url-parser@3.0.11': + dependencies: + '@smithy/querystring-parser': 3.0.11 + '@smithy/types': 3.7.2 + tslib: 2.8.1 + + '@smithy/util-base64@3.0.0': + dependencies: + '@smithy/util-buffer-from': 3.0.0 + '@smithy/util-utf8': 3.0.0 + tslib: 2.8.1 + + '@smithy/util-body-length-browser@3.0.0': + dependencies: + tslib: 2.8.1 + + '@smithy/util-body-length-node@3.0.0': + dependencies: + tslib: 2.8.1 + + '@smithy/util-buffer-from@2.2.0': + dependencies: + '@smithy/is-array-buffer': 2.2.0 + tslib: 2.8.1 + + '@smithy/util-buffer-from@3.0.0': + dependencies: + '@smithy/is-array-buffer': 3.0.0 + tslib: 2.8.1 + + '@smithy/util-config-provider@3.0.0': + dependencies: + tslib: 2.8.1 + + '@smithy/util-defaults-mode-browser@3.0.32': + dependencies: + '@smithy/property-provider': 3.1.11 + '@smithy/smithy-client': 3.5.2 + '@smithy/types': 3.7.2 + bowser: 2.11.0 + tslib: 2.8.1 + + '@smithy/util-defaults-mode-node@3.0.32': + dependencies: + '@smithy/config-resolver': 3.0.13 + '@smithy/credential-provider-imds': 3.2.8 + '@smithy/node-config-provider': 3.1.12 + '@smithy/property-provider': 3.1.11 + '@smithy/smithy-client': 3.5.2 + '@smithy/types': 3.7.2 + tslib: 2.8.1 + + '@smithy/util-endpoints@2.1.7': + dependencies: + '@smithy/node-config-provider': 3.1.12 + '@smithy/types': 3.7.2 + tslib: 2.8.1 + + '@smithy/util-hex-encoding@3.0.0': + dependencies: + tslib: 2.8.1 + + '@smithy/util-middleware@3.0.11': + dependencies: + '@smithy/types': 3.7.2 + tslib: 2.8.1 + + '@smithy/util-retry@3.0.11': + dependencies: + '@smithy/service-error-classification': 3.0.11 + '@smithy/types': 3.7.2 + tslib: 2.8.1 + + '@smithy/util-stream@3.3.3': + dependencies: + '@smithy/fetch-http-handler': 4.1.2 + '@smithy/node-http-handler': 3.3.3 + '@smithy/types': 3.7.2 + '@smithy/util-base64': 3.0.0 + '@smithy/util-buffer-from': 3.0.0 + '@smithy/util-hex-encoding': 3.0.0 + '@smithy/util-utf8': 3.0.0 + tslib: 2.8.1 + + '@smithy/util-uri-escape@3.0.0': + dependencies: + tslib: 2.8.1 + + '@smithy/util-utf8@2.3.0': + dependencies: + '@smithy/util-buffer-from': 2.2.0 + tslib: 2.8.1 + + '@smithy/util-utf8@3.0.0': + dependencies: + '@smithy/util-buffer-from': 3.0.0 + tslib: 2.8.1 + '@stylistic/eslint-plugin-ts@2.11.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2)': dependencies: '@typescript-eslint/utils': 8.17.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) @@ -7557,6 +8620,8 @@ snapshots: '@types/unist@3.0.3': {} + '@types/uuid@9.0.8': {} + '@typescript-eslint/eslint-plugin@8.17.0(@typescript-eslint/parser@8.17.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2)': dependencies: '@eslint-community/regexpp': 4.12.1 @@ -8064,6 +9129,8 @@ snapshots: transitivePeerDependencies: - supports-color + bowser@2.11.0: {} + brace-expansion@1.1.11: dependencies: balanced-match: 1.0.2 @@ -8873,6 +9940,10 @@ snapshots: fast-levenshtein@2.0.6: {} + fast-xml-parser@4.4.1: + dependencies: + strnum: 1.0.5 + fastq@1.17.1: dependencies: reusify: 1.0.4 @@ -11342,6 +12413,8 @@ snapshots: strip-json-comments@3.1.1: {} + strnum@1.0.5: {} + style-mod@4.1.2: {} style-to-object@0.4.4: @@ -11688,6 +12761,8 @@ snapshots: utils-merge@1.0.1: {} + uuid@9.0.1: {} + uvu@0.5.6: dependencies: dequal: 2.0.3 diff --git a/public/icons/AmazonBedrock.svg b/public/icons/AmazonBedrock.svg new file mode 100644 index 00000000..a5649399 --- /dev/null +++ b/public/icons/AmazonBedrock.svg @@ -0,0 +1 @@ +Bedrock \ No newline at end of file diff --git a/worker-configuration.d.ts b/worker-configuration.d.ts index fb5157da..099fba9b 100644 --- a/worker-configuration.d.ts +++ b/worker-configuration.d.ts @@ -16,4 +16,5 @@ interface Env { MISTRAL_API_KEY: string; XAI_API_KEY: string; PERPLEXITY_API_KEY: string; + AWS_BEDROCK_CONFIG: string; } From 49c7129dedb4752e2e69c0ffba15eda170caeb13 Mon Sep 17 00:00:00 2001 From: Anirban Kar Date: Mon, 6 Jan 2025 19:18:42 +0530 Subject: [PATCH 12/47] fix: ollama and lm studio url issue fix for docker and build (#1008) * fix: ollama and lm studio url issue fix for docker and build * vite config fix --- Dockerfile | 8 ++++-- app/lib/modules/llm/providers/lmstudio.ts | 35 +++++++++++++++++++---- app/lib/modules/llm/providers/ollama.ts | 25 +++++++++++++--- vite.config.ts | 9 ++++-- 4 files changed, 63 insertions(+), 14 deletions(-) diff --git a/Dockerfile b/Dockerfile index cd2a6fbf..d287d407 100644 --- a/Dockerfile +++ b/Dockerfile @@ -45,13 +45,14 @@ ENV WRANGLER_SEND_METRICS=false \ TOGETHER_API_BASE_URL=${TOGETHER_API_BASE_URL} \ AWS_BEDROCK_CONFIG=${AWS_BEDROCK_CONFIG} \ VITE_LOG_LEVEL=${VITE_LOG_LEVEL} \ - DEFAULT_NUM_CTX=${DEFAULT_NUM_CTX} + DEFAULT_NUM_CTX=${DEFAULT_NUM_CTX}\ + RUNNING_IN_DOCKER=true # Pre-configure wrangler to disable metrics RUN mkdir -p /root/.config/.wrangler && \ echo '{"enabled":false}' > /root/.config/.wrangler/metrics.json -RUN npm run build +RUN pnpm run build CMD [ "pnpm", "run", "dockerstart"] @@ -84,7 +85,8 @@ ENV GROQ_API_KEY=${GROQ_API_KEY} \ TOGETHER_API_BASE_URL=${TOGETHER_API_BASE_URL} \ AWS_BEDROCK_CONFIG=${AWS_BEDROCK_CONFIG} \ VITE_LOG_LEVEL=${VITE_LOG_LEVEL} \ - DEFAULT_NUM_CTX=${DEFAULT_NUM_CTX} + DEFAULT_NUM_CTX=${DEFAULT_NUM_CTX}\ + RUNNING_IN_DOCKER=true RUN mkdir -p ${WORKDIR}/run CMD pnpm run dev --host diff --git a/app/lib/modules/llm/providers/lmstudio.ts b/app/lib/modules/llm/providers/lmstudio.ts index 4309df0d..ba319ac8 100644 --- a/app/lib/modules/llm/providers/lmstudio.ts +++ b/app/lib/modules/llm/providers/lmstudio.ts @@ -3,6 +3,7 @@ import type { ModelInfo } from '~/lib/modules/llm/types'; import type { IProviderSetting } from '~/types/model'; import { createOpenAI } from '@ai-sdk/openai'; import type { LanguageModelV1 } from 'ai'; +import { logger } from '~/utils/logger'; export default class LMStudioProvider extends BaseProvider { name = 'LMStudio'; @@ -22,7 +23,7 @@ export default class LMStudioProvider extends BaseProvider { settings?: IProviderSetting, serverEnv: Record = {}, ): Promise { - const { baseUrl } = this.getProviderBaseUrlAndKey({ + let { baseUrl } = this.getProviderBaseUrlAndKey({ apiKeys, providerSettings: settings, serverEnv, @@ -31,7 +32,18 @@ export default class LMStudioProvider extends BaseProvider { }); if (!baseUrl) { - return []; + throw new Error('No baseUrl found for LMStudio provider'); + } + + if (typeof window === 'undefined') { + /* + * Running in Server + * Backend: Check if we're running in Docker + */ + const isDocker = process.env.RUNNING_IN_DOCKER === 'true'; + + baseUrl = isDocker ? baseUrl.replace('localhost', 'host.docker.internal') : baseUrl; + baseUrl = isDocker ? baseUrl.replace('127.0.0.1', 'host.docker.internal') : baseUrl; } const response = await fetch(`${baseUrl}/v1/models`); @@ -51,13 +63,26 @@ export default class LMStudioProvider extends BaseProvider { providerSettings?: Record; }) => LanguageModelV1 = (options) => { const { apiKeys, providerSettings, serverEnv, model } = options; - const { baseUrl } = this.getProviderBaseUrlAndKey({ + let { baseUrl } = this.getProviderBaseUrlAndKey({ apiKeys, - providerSettings, + providerSettings: providerSettings?.[this.name], serverEnv: serverEnv as any, - defaultBaseUrlKey: 'OLLAMA_API_BASE_URL', + defaultBaseUrlKey: 'LMSTUDIO_API_BASE_URL', defaultApiTokenKey: '', }); + + if (!baseUrl) { + throw new Error('No baseUrl found for LMStudio provider'); + } + + if (typeof window === 'undefined') { + const isDocker = process.env.RUNNING_IN_DOCKER === 'true'; + baseUrl = isDocker ? baseUrl.replace('localhost', 'host.docker.internal') : baseUrl; + baseUrl = isDocker ? baseUrl.replace('127.0.0.1', 'host.docker.internal') : baseUrl; + } + + logger.debug('LMStudio Base Url used: ', baseUrl); + const lmstudio = createOpenAI({ baseUrl: `${baseUrl}/v1`, apiKey: '', diff --git a/app/lib/modules/llm/providers/ollama.ts b/app/lib/modules/llm/providers/ollama.ts index 8f0ddf22..11cf6a2b 100644 --- a/app/lib/modules/llm/providers/ollama.ts +++ b/app/lib/modules/llm/providers/ollama.ts @@ -3,6 +3,7 @@ import type { ModelInfo } from '~/lib/modules/llm/types'; import type { IProviderSetting } from '~/types/model'; import type { LanguageModelV1 } from 'ai'; import { ollama } from 'ollama-ai-provider'; +import { logger } from '~/utils/logger'; interface OllamaModelDetails { parent_model: string; @@ -45,7 +46,7 @@ export default class OllamaProvider extends BaseProvider { settings?: IProviderSetting, serverEnv: Record = {}, ): Promise { - const { baseUrl } = this.getProviderBaseUrlAndKey({ + let { baseUrl } = this.getProviderBaseUrlAndKey({ apiKeys, providerSettings: settings, serverEnv, @@ -54,7 +55,18 @@ export default class OllamaProvider extends BaseProvider { }); if (!baseUrl) { - return []; + throw new Error('No baseUrl found for OLLAMA provider'); + } + + if (typeof window === 'undefined') { + /* + * Running in Server + * Backend: Check if we're running in Docker + */ + const isDocker = process.env.RUNNING_IN_DOCKER === 'true'; + + baseUrl = isDocker ? baseUrl.replace('localhost', 'host.docker.internal') : baseUrl; + baseUrl = isDocker ? baseUrl.replace('127.0.0.1', 'host.docker.internal') : baseUrl; } const response = await fetch(`${baseUrl}/api/tags`); @@ -78,18 +90,23 @@ export default class OllamaProvider extends BaseProvider { const { apiKeys, providerSettings, serverEnv, model } = options; let { baseUrl } = this.getProviderBaseUrlAndKey({ apiKeys, - providerSettings, + providerSettings: providerSettings?.[this.name], serverEnv: serverEnv as any, defaultBaseUrlKey: 'OLLAMA_API_BASE_URL', defaultApiTokenKey: '', }); // Backend: Check if we're running in Docker - const isDocker = process.env.RUNNING_IN_DOCKER === 'true'; + if (!baseUrl) { + throw new Error('No baseUrl found for OLLAMA provider'); + } + const isDocker = process.env.RUNNING_IN_DOCKER === 'true'; baseUrl = isDocker ? baseUrl.replace('localhost', 'host.docker.internal') : baseUrl; baseUrl = isDocker ? baseUrl.replace('127.0.0.1', 'host.docker.internal') : baseUrl; + logger.debug('Ollama Base Url used: ', baseUrl); + const ollamaInstance = ollama(model, { numCtx: DEFAULT_NUM_CTX, }) as LanguageModelV1 & { config: any }; diff --git a/vite.config.ts b/vite.config.ts index 312230a0..2510acbc 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -4,9 +4,11 @@ import { defineConfig, type ViteDevServer } from 'vite'; import { nodePolyfills } from 'vite-plugin-node-polyfills'; import { optimizeCssModules } from 'vite-plugin-optimize-css-modules'; import tsconfigPaths from 'vite-tsconfig-paths'; - +import * as dotenv from 'dotenv'; import { execSync } from 'child_process'; +dotenv.config(); + // Get git hash with fallback const getGitHash = () => { try { @@ -17,18 +19,21 @@ const getGitHash = () => { }; + + export default defineConfig((config) => { return { define: { __COMMIT_HASH: JSON.stringify(getGitHash()), __APP_VERSION: JSON.stringify(process.env.npm_package_version), + // 'process.env': JSON.stringify(process.env) }, build: { target: 'esnext', }, plugins: [ nodePolyfills({ - include: ['path', 'buffer'], + include: ['path', 'buffer', 'process'], }), config.mode !== 'test' && remixCloudflareDevProxy(), remixVitePlugin({ From 78eb3a5f34e254f0753056d87ff40e87628b8e6c Mon Sep 17 00:00:00 2001 From: Anirban Kar Date: Mon, 6 Jan 2025 19:18:52 +0530 Subject: [PATCH 13/47] fix: streaming issue fixed for build versions (#1006) * fix: streaming issue fixed for build versions * added keep-alive header --- app/routes/api.chat.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/routes/api.chat.ts b/app/routes/api.chat.ts index 05f8746c..8c15bf27 100644 --- a/app/routes/api.chat.ts +++ b/app/routes/api.chat.ts @@ -139,7 +139,8 @@ async function chatAction({ context, request }: ActionFunctionArgs) { return new Response(stream.readable, { status: 200, headers: { - contentType: 'text/plain; charset=utf-8', + contentType: 'text/event-stream', + connection: 'keep-alive', }, }); } catch (error: any) { From 6f524fdf2751b6cc0f47418b4d33e8cc7dadbbf4 Mon Sep 17 00:00:00 2001 From: Anirban Kar Date: Mon, 6 Jan 2025 19:19:40 +0530 Subject: [PATCH 14/47] ci: added arm64 platform for docker published images (#1021) --- .github/workflows/docker.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/docker.yaml b/.github/workflows/docker.yaml index f5424983..d3bd2f1b 100644 --- a/.github/workflows/docker.yaml +++ b/.github/workflows/docker.yaml @@ -65,6 +65,7 @@ jobs: context: . file: ./Dockerfile target: ${{ env.BUILD_TARGET }} + platforms: linux/amd64,linux/arm64 push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} From 354f4165591db19c613b4fbae8a99d8b9fb8d9f2 Mon Sep 17 00:00:00 2001 From: Cole Medin <47287758+coleam00@users.noreply.github.com> Date: Mon, 6 Jan 2025 10:15:19 -0600 Subject: [PATCH 15/47] Updating README with resources and small fixes. --- README.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 715faa70..f99948b8 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,9 @@ 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. -Check the [bolt.diy Docs](https://stackblitz-labs.github.io/bolt.diy/) for more information. +Check the [bolt.diy Docs](https://stackblitz-labs.github.io/bolt.diy/) for more information. + +Also [this pinned post in our community](https://thinktank.ottomator.ai/t/videos-tutorial-helpful-content/3243) has a bunch of incredible resources for running and deploying bolt.diy yourself! 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/). @@ -23,7 +25,7 @@ bolt.diy was originally started by [Cole Medin](https://www.youtube.com/@ColeMed ## Join the community -[Join the bolt.diy community here, in the thinktank on ottomator.ai!](https://thinktank.ottomator.ai) +[Join the bolt.diy community here, in the oTTomator Think Tank!](https://thinktank.ottomator.ai) ## Requested Additions @@ -64,6 +66,8 @@ bolt.diy was originally started by [Cole Medin](https://www.youtube.com/@ColeMed - ✅ Detect terminal Errors and ask bolt to fix it (@thecodacus) - ✅ Detect preview Errors and ask bolt to fix it (@wonderwhy-er) - ✅ Add Starter Template Options (@thecodacus) +- ✅ Perplexity Integration (@meetpateltech) +- ✅ AWS Bedrock Integration (@kunjabijukchhe) - ⬜ **HIGH PRIORITY** - Prevent bolt from rewriting files as often (file locking and diffs) - ⬜ **HIGH PRIORITY** - Better prompting for smaller LLMs (code window sometimes doesn't start) - ⬜ **HIGH PRIORITY** - Run agents in the backend as opposed to a single model call @@ -73,8 +77,6 @@ bolt.diy was originally started by [Cole Medin](https://www.youtube.com/@ColeMed - ⬜ Upload documents for knowledge - UI design templates, a code base to reference coding style, etc. - ⬜ Voice prompting - ⬜ Azure Open AI API Integration -- ✅ Perplexity Integration (@meetpateltech) -- ✅ AWS Bedrock Integration (@kunjabijukchhe) - ⬜ Vertex AI Integration ## Features From 441b797f169515b41eb77357d0e2aa840bfe4d64 Mon Sep 17 00:00:00 2001 From: Cole Medin <47287758+coleam00@users.noreply.github.com> Date: Mon, 6 Jan 2025 10:20:43 -0600 Subject: [PATCH 16/47] Adding resources page to index.md for docs. --- docs/docs/index.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/docs/index.md b/docs/docs/index.md index 641d45a7..7f12f5dd 100644 --- a/docs/docs/index.md +++ b/docs/docs/index.md @@ -25,6 +25,8 @@ bolt.diy allows you to choose the LLM that you use for each prompt! Currently, y [Join the community!](https://thinktank.ottomator.ai) +Also [this pinned post in our community](https://thinktank.ottomator.ai/t/videos-tutorial-helpful-content/3243) has a bunch of incredible resources for running and deploying bolt.diy yourself! + --- ## Features From 7004c897f7c7d914c289ff1f25b264a78df2fb90 Mon Sep 17 00:00:00 2001 From: Anirban Kar Date: Tue, 7 Jan 2025 00:43:35 +0530 Subject: [PATCH 17/47] updated docs (#1025) --- docs/docs/FAQ.md | 42 ++++++++++++++---------------------------- 1 file changed, 14 insertions(+), 28 deletions(-) diff --git a/docs/docs/FAQ.md b/docs/docs/FAQ.md index a09fae88..ea1056f8 100644 --- a/docs/docs/FAQ.md +++ b/docs/docs/FAQ.md @@ -1,7 +1,6 @@ # Frequently Asked Questions (FAQ) -
-What are the best models for bolt.diy? +## What are the best models for bolt.diy? For the best experience with bolt.diy, we recommend using the following models: @@ -12,10 +11,8 @@ For the best experience with bolt.diy, we recommend using the following models: - **Qwen 2.5 Coder 32b**: Best model for self-hosting with reasonable hardware requirements **Note**: Models with less than 7b parameters typically lack the capability to properly interact with bolt! -
-
-How do I get the best results with bolt.diy? +## How do I get the best results with bolt.diy? - **Be specific about your stack**: Mention the frameworks or libraries you want to use (e.g., Astro, Tailwind, ShadCN) in your initial prompt. This ensures that bolt.diy scaffolds the project according to your preferences. @@ -29,63 +26,52 @@ For the best experience with bolt.diy, we recommend using the following models: - **Batch simple instructions**: Combine simple tasks into a single prompt to save time and reduce API credit consumption. For example: *"Change the color scheme, add mobile responsiveness, and restart the dev server."* -
-
-How do I contribute to bolt.diy? +## How do I contribute to bolt.diy? Check out our [Contribution Guide](CONTRIBUTING.md) for more details on how to get involved! -
-
-What are the future plans for bolt.diy? +## What are the future plans for bolt.diy? Visit our [Roadmap](https://roadmap.sh/r/ottodev-roadmap-2ovzo) for the latest updates. New features and improvements are on the way! -
-
-Why are there so many open issues/pull requests? +## Why are there so many open issues/pull requests? bolt.diy began as a small showcase project on @ColeMedin's YouTube channel to explore editing open-source projects with local LLMs. However, it quickly grew into a massive community effort! We're forming a team of maintainers to manage demand and streamline issue resolution. The maintainers are rockstars, and we're also exploring partnerships to help the project thrive. -
-
-How do local LLMs compare to larger models like Claude 3.5 Sonnet for bolt.diy? +## How do local LLMs compare to larger models like Claude 3.5 Sonnet for bolt.diy? While local LLMs are improving rapidly, larger models like GPT-4o, Claude 3.5 Sonnet, and DeepSeek Coder V2 236b still offer the best results for complex applications. Our ongoing focus is to improve prompts, agents, and the platform to better support smaller local LLMs. -
-
-Common Errors and Troubleshooting +## Common Errors and Troubleshooting -### **"There was an error processing this request"** +### "There was an error processing this request" This generic error message means something went wrong. Check both: - The terminal (if you started the app with Docker or `pnpm`). - The developer console in your browser (press `F12` or right-click > *Inspect*, then go to the *Console* tab). -### **"x-api-key header missing"** +### "x-api-key header missing" This error is sometimes resolved by restarting the Docker container. If that doesn't work, try switching from Docker to `pnpm` or vice versa. We're actively investigating this issue. -### **Blank preview when running the app** +### Blank preview when running the app A blank preview often occurs due to hallucinated bad code or incorrect commands. To troubleshoot: - Check the developer console for errors. - Remember, previews are core functionality, so the app isn't broken! We're working on making these errors more transparent. -### **"Everything works, but the results are bad"** +### "Everything works, but the results are bad" Local LLMs like Qwen-2.5-Coder are powerful for small applications but still experimental for larger projects. For better results, consider using larger models like GPT-4o, Claude 3.5 Sonnet, or DeepSeek Coder V2 236b. -### **"Received structured exception #0xc0000005: access violation"** +### "Received structured exception #0xc0000005: access violation" 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) -### **"Miniflare or Wrangler errors in Windows"** +### "Miniflare or Wrangler errors in Windows" You will need to make sure you have the latest version of Visual Studio C++ installed (14.40.33816), more information here https://github.com/stackblitz-labs/bolt.diy/issues/19. -
--- -Got more questions? Feel free to reach out or open an issue in our GitHub repo! +Got more questions? Feel free to reach out or open an issue in our GitHub repo! \ No newline at end of file From 3aed93aeed9549f0257c559331acfa255ac7563c Mon Sep 17 00:00:00 2001 From: Dave Nielsen Date: Mon, 6 Jan 2025 11:21:13 -0800 Subject: [PATCH 18/47] Update README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added ⬜ Granite Integration --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index f99948b8..863a504a 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,7 @@ bolt.diy was originally started by [Cole Medin](https://www.youtube.com/@ColeMed - ⬜ Voice prompting - ⬜ Azure Open AI API Integration - ⬜ Vertex AI Integration +- ⬜ Granite Integration (@dnielsen) ## Features From 4fd50403557bcf83ecffd59dacee019436e25f60 Mon Sep 17 00:00:00 2001 From: Siddharth V <94043668+sidbetatester@users.noreply.github.com> Date: Tue, 7 Jan 2025 06:46:42 -0800 Subject: [PATCH 19/47] feat: enhance chat import with multi-format support (#936) * feat: enhance chat import with multi-format support - Add support for importing chats from different formats: - Standard Bolt format - Chrome extension format - History array format - Bolt export format - Add Import Chats button to Data Management - Add proper error handling and logging - Update README with backup/restore feature * refactor: simplify chat import formats - Remove multi-format support from DataTab - Keep only standard Bolt export formats - Simplify ImportButtons to handle standard format only --- README.md | 1 + .../chatExportAndImport/ImportButtons.tsx | 17 ++-- app/components/settings/data/DataTab.tsx | 79 ++++++++++++++++++- 3 files changed, 91 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index f99948b8..8d0c1571 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,7 @@ bolt.diy was originally started by [Cole Medin](https://www.youtube.com/@ColeMed - ✅ Bolt terminal to see the output of LLM run commands (@thecodacus) - ✅ Streaming of code output (@thecodacus) - ✅ Ability to revert code to earlier version (@wonderwhy-er) +- ✅ Chat history backup and restore functionality (@sidbetatester) - ✅ Cohere Integration (@hasanraiyan) - ✅ Dynamic model max token length (@hasanraiyan) - ✅ Better prompt enhancing (@SujalXplores) diff --git a/app/components/chat/chatExportAndImport/ImportButtons.tsx b/app/components/chat/chatExportAndImport/ImportButtons.tsx index 208fd02b..c6b25579 100644 --- a/app/components/chat/chatExportAndImport/ImportButtons.tsx +++ b/app/components/chat/chatExportAndImport/ImportButtons.tsx @@ -2,6 +2,11 @@ import type { Message } from 'ai'; import { toast } from 'react-toastify'; import { ImportFolderButton } from '~/components/chat/ImportFolderButton'; +type ChatData = { + messages?: Message[]; // Standard Bolt format + description?: string; // Optional description +}; + export function ImportButtons(importChat: ((description: string, messages: Message[]) => Promise) | undefined) { return (
@@ -20,14 +25,16 @@ export function ImportButtons(importChat: ((description: string, messages: Messa reader.onload = async (e) => { try { const content = e.target?.result as string; - const data = JSON.parse(content); + const data = JSON.parse(content) as ChatData; - if (!Array.isArray(data.messages)) { - toast.error('Invalid chat file format'); + // Standard format + if (Array.isArray(data.messages)) { + await importChat(data.description || 'Imported Chat', data.messages); + toast.success('Chat imported successfully'); + return; } - await importChat(data.description, data.messages); - toast.success('Chat imported successfully'); + toast.error('Invalid chat file format'); } catch (error: unknown) { if (error instanceof Error) { toast.error('Failed to parse chat file: ' + error.message); diff --git a/app/components/settings/data/DataTab.tsx b/app/components/settings/data/DataTab.tsx index c78491e2..531db3c0 100644 --- a/app/components/settings/data/DataTab.tsx +++ b/app/components/settings/data/DataTab.tsx @@ -2,9 +2,10 @@ import React, { useState } from 'react'; import { useNavigate } from '@remix-run/react'; import Cookies from 'js-cookie'; import { toast } from 'react-toastify'; -import { db, deleteById, getAll } from '~/lib/persistence'; +import { db, deleteById, getAll, setMessages } from '~/lib/persistence'; import { logStore } from '~/lib/stores/logs'; import { classNames } from '~/utils/classNames'; +import type { Message } from 'ai'; // List of supported providers that can have API keys const API_KEY_PROVIDERS = [ @@ -232,6 +233,76 @@ export default function DataTab() { event.target.value = ''; }; + const processChatData = (data: any): Array<{ + id: string; + messages: Message[]; + description: string; + urlId?: string; + }> => { + // Handle Bolt standard format (single chat) + if (data.messages && Array.isArray(data.messages)) { + const chatId = crypto.randomUUID(); + return [{ + id: chatId, + messages: data.messages, + description: data.description || 'Imported Chat', + urlId: chatId + }]; + } + + // Handle Bolt export format (multiple chats) + if (data.chats && Array.isArray(data.chats)) { + return data.chats.map((chat: { id?: string; messages: Message[]; description?: string; urlId?: string; }) => ({ + id: chat.id || crypto.randomUUID(), + messages: chat.messages, + description: chat.description || 'Imported Chat', + urlId: chat.urlId, + })); + } + + console.error('No matching format found for:', data); + throw new Error('Unsupported chat format'); + }; + + const handleImportChats = () => { + const input = document.createElement('input'); + input.type = 'file'; + input.accept = '.json'; + + input.onchange = async (e) => { + const file = (e.target as HTMLInputElement).files?.[0]; + + if (!file || !db) { + toast.error('Something went wrong'); + return; + } + + try { + const content = await file.text(); + const data = JSON.parse(content); + const chatsToImport = processChatData(data); + + for (const chat of chatsToImport) { + await setMessages(db, chat.id, chat.messages, chat.urlId, chat.description); + } + + logStore.logSystem('Chats imported successfully', { count: chatsToImport.length }); + toast.success(`Successfully imported ${chatsToImport.length} chat${chatsToImport.length > 1 ? 's' : ''}`); + window.location.reload(); + } catch (error) { + if (error instanceof Error) { + logStore.logError('Failed to import chats:', error); + toast.error('Failed to import chats: ' + error.message); + } else { + toast.error('Failed to import chats'); + } + console.error(error); + } + }; + + input.click(); + }; + return (
@@ -248,6 +319,12 @@ export default function DataTab() { > Export All Chats + + ))} +
+ + )} +
{ title="preview" className="border-none w-full h-full bg-white" src={iframeUrl} - allowFullScreen + sandbox="allow-scripts allow-forms allow-popups allow-modals allow-storage-access-by-user-activation allow-same-origin" + allow="cross-origin-isolated" /> { {isDeviceModeOn && ( <> - {/* Left handle */}
startResizing(e, 'left')} style={{ @@ -333,7 +400,6 @@ export const Preview = memo(() => {
- {/* Right handle */}
startResizing(e, 'right')} style={{ diff --git a/app/lib/stores/previews.ts b/app/lib/stores/previews.ts index 79480d1c..28954844 100644 --- a/app/lib/stores/previews.ts +++ b/app/lib/stores/previews.ts @@ -1,27 +1,192 @@ import type { WebContainer } from '@webcontainer/api'; import { atom } from 'nanostores'; +// Extend Window interface to include our custom property +declare global { + interface Window { + _tabId?: string; + } +} + export interface PreviewInfo { port: number; ready: boolean; baseUrl: string; } +// Create a broadcast channel for preview updates +const PREVIEW_CHANNEL = 'preview-updates'; + export class PreviewsStore { #availablePreviews = new Map(); #webcontainer: Promise; + #broadcastChannel: BroadcastChannel; + #lastUpdate = new Map(); + #watchedFiles = new Set(); + #refreshTimeouts = new Map(); + #REFRESH_DELAY = 300; + #storageChannel: BroadcastChannel; previews = atom([]); constructor(webcontainerPromise: Promise) { this.#webcontainer = webcontainerPromise; + this.#broadcastChannel = new BroadcastChannel(PREVIEW_CHANNEL); + this.#storageChannel = new BroadcastChannel('storage-sync-channel'); + + // Listen for preview updates from other tabs + this.#broadcastChannel.onmessage = (event) => { + const { type, previewId } = event.data; + + if (type === 'file-change') { + const timestamp = event.data.timestamp; + const lastUpdate = this.#lastUpdate.get(previewId) || 0; + + if (timestamp > lastUpdate) { + this.#lastUpdate.set(previewId, timestamp); + this.refreshPreview(previewId); + } + } + }; + + // Listen for storage sync messages + this.#storageChannel.onmessage = (event) => { + const { storage, source } = event.data; + + if (storage && source !== this._getTabId()) { + this._syncStorage(storage); + } + }; + + // Override localStorage setItem to catch all changes + if (typeof window !== 'undefined') { + const originalSetItem = localStorage.setItem; + + localStorage.setItem = (...args) => { + originalSetItem.apply(localStorage, args); + this._broadcastStorageSync(); + }; + } this.#init(); } + // Generate a unique ID for this tab + private _getTabId(): string { + if (typeof window !== 'undefined') { + if (!window._tabId) { + window._tabId = Math.random().toString(36).substring(2, 15); + } + + return window._tabId; + } + + return ''; + } + + // Sync storage data between tabs + private _syncStorage(storage: Record) { + if (typeof window !== 'undefined') { + Object.entries(storage).forEach(([key, value]) => { + try { + const originalSetItem = Object.getPrototypeOf(localStorage).setItem; + originalSetItem.call(localStorage, key, value); + } catch (error) { + console.error('[Preview] Error syncing storage:', error); + } + }); + + // Force a refresh after syncing storage + const previews = this.previews.get(); + previews.forEach((preview) => { + const previewId = this.getPreviewId(preview.baseUrl); + + if (previewId) { + this.refreshPreview(previewId); + } + }); + + // Reload the page content + if (typeof window !== 'undefined' && window.location) { + const iframe = document.querySelector('iframe'); + + if (iframe) { + iframe.src = iframe.src; + } + } + } + } + + // Broadcast storage state to other tabs + private _broadcastStorageSync() { + if (typeof window !== 'undefined') { + const storage: Record = {}; + + for (let i = 0; i < localStorage.length; i++) { + const key = localStorage.key(i); + + if (key) { + storage[key] = localStorage.getItem(key) || ''; + } + } + + this.#storageChannel.postMessage({ + type: 'storage-sync', + storage, + source: this._getTabId(), + timestamp: Date.now(), + }); + } + } + async #init() { const webcontainer = await this.#webcontainer; + // Listen for server ready events + webcontainer.on('server-ready', (port, url) => { + console.log('[Preview] Server ready on port:', port, url); + this.broadcastUpdate(url); + + // Initial storage sync when preview is ready + this._broadcastStorageSync(); + }); + + try { + // Watch for file changes + const watcher = await webcontainer.fs.watch('**/*', { persistent: true }); + + // Use the native watch events + (watcher as any).addEventListener('change', async () => { + const previews = this.previews.get(); + + for (const preview of previews) { + const previewId = this.getPreviewId(preview.baseUrl); + + if (previewId) { + this.broadcastFileChange(previewId); + } + } + }); + + // Watch for DOM changes that might affect storage + if (typeof window !== 'undefined') { + const observer = new MutationObserver((_mutations) => { + // Broadcast storage changes when DOM changes + this._broadcastStorageSync(); + }); + + observer.observe(document.body, { + childList: true, + subtree: true, + characterData: true, + attributes: true, + }); + } + } catch (error) { + console.error('[Preview] Error setting up watchers:', error); + } + + // Listen for port events webcontainer.on('port', (port, type, url) => { let previewInfo = this.#availablePreviews.get(port); @@ -44,6 +209,101 @@ export class PreviewsStore { previewInfo.baseUrl = url; this.previews.set([...previews]); + + if (type === 'open') { + this.broadcastUpdate(url); + } }); } + + // Helper to extract preview ID from URL + getPreviewId(url: string): string | null { + const match = url.match(/^https?:\/\/([^.]+)\.local-credentialless\.webcontainer-api\.io/); + return match ? match[1] : null; + } + + // Broadcast state change to all tabs + broadcastStateChange(previewId: string) { + const timestamp = Date.now(); + this.#lastUpdate.set(previewId, timestamp); + + this.#broadcastChannel.postMessage({ + type: 'state-change', + previewId, + timestamp, + }); + } + + // Broadcast file change to all tabs + broadcastFileChange(previewId: string) { + const timestamp = Date.now(); + this.#lastUpdate.set(previewId, timestamp); + + this.#broadcastChannel.postMessage({ + type: 'file-change', + previewId, + timestamp, + }); + } + + // Broadcast update to all tabs + broadcastUpdate(url: string) { + const previewId = this.getPreviewId(url); + + if (previewId) { + const timestamp = Date.now(); + this.#lastUpdate.set(previewId, timestamp); + + this.#broadcastChannel.postMessage({ + type: 'file-change', + previewId, + timestamp, + }); + } + } + + // Method to refresh a specific preview + refreshPreview(previewId: string) { + // Clear any pending refresh for this preview + const existingTimeout = this.#refreshTimeouts.get(previewId); + + if (existingTimeout) { + clearTimeout(existingTimeout); + } + + // Set a new timeout for this refresh + const timeout = setTimeout(() => { + const previews = this.previews.get(); + const preview = previews.find((p) => this.getPreviewId(p.baseUrl) === previewId); + + if (preview) { + preview.ready = false; + this.previews.set([...previews]); + + requestAnimationFrame(() => { + preview.ready = true; + this.previews.set([...previews]); + }); + } + + this.#refreshTimeouts.delete(previewId); + }, this.#REFRESH_DELAY); + + this.#refreshTimeouts.set(previewId, timeout); + } +} + +// Create a singleton instance +let previewsStore: PreviewsStore | null = null; + +export function usePreviewStore() { + if (!previewsStore) { + /* + * Initialize with a Promise that resolves to WebContainer + * This should match how you're initializing WebContainer elsewhere + */ + previewsStore = new PreviewsStore(Promise.resolve({} as WebContainer)); + } + + return previewsStore; } diff --git a/app/routes/webcontainer.preview.$id.tsx b/app/routes/webcontainer.preview.$id.tsx new file mode 100644 index 00000000..a52ccf92 --- /dev/null +++ b/app/routes/webcontainer.preview.$id.tsx @@ -0,0 +1,92 @@ +import { json, type LoaderFunctionArgs } from '@remix-run/cloudflare'; +import { useLoaderData } from '@remix-run/react'; +import { useCallback, useEffect, useRef, useState } from 'react'; + +const PREVIEW_CHANNEL = 'preview-updates'; + +export async function loader({ params }: LoaderFunctionArgs) { + const previewId = params.id; + + if (!previewId) { + throw new Response('Preview ID is required', { status: 400 }); + } + + return json({ previewId }); +} + +export default function WebContainerPreview() { + const { previewId } = useLoaderData(); + const iframeRef = useRef(null); + const broadcastChannelRef = useRef(); + const [previewUrl, setPreviewUrl] = useState(''); + + // Handle preview refresh + const handleRefresh = useCallback(() => { + if (iframeRef.current && previewUrl) { + // Force a clean reload + iframeRef.current.src = ''; + requestAnimationFrame(() => { + if (iframeRef.current) { + iframeRef.current.src = previewUrl; + } + }); + } + }, [previewUrl]); + + // Notify other tabs that this preview is ready + const notifyPreviewReady = useCallback(() => { + if (broadcastChannelRef.current && previewUrl) { + broadcastChannelRef.current.postMessage({ + type: 'preview-ready', + previewId, + url: previewUrl, + timestamp: Date.now(), + }); + } + }, [previewId, previewUrl]); + + useEffect(() => { + // Initialize broadcast channel + broadcastChannelRef.current = new BroadcastChannel(PREVIEW_CHANNEL); + + // Listen for preview updates + broadcastChannelRef.current.onmessage = (event) => { + if (event.data.previewId === previewId) { + if (event.data.type === 'refresh-preview' || event.data.type === 'file-change') { + handleRefresh(); + } + } + }; + + // Construct the WebContainer preview URL + const url = `https://${previewId}.local-credentialless.webcontainer-api.io`; + setPreviewUrl(url); + + // Set the iframe src + if (iframeRef.current) { + iframeRef.current.src = url; + } + + // Notify other tabs that this preview is ready + notifyPreviewReady(); + + // Cleanup + return () => { + broadcastChannelRef.current?.close(); + }; + }, [previewId, handleRefresh, notifyPreviewReady]); + + return ( +
+