diff --git a/.github/workflows/commit.yaml b/.github/workflows/commit.yaml index d5db06b0..4e8545b0 100644 --- a/.github/workflows/commit.yaml +++ b/.github/workflows/commit.yaml @@ -17,12 +17,18 @@ jobs: - name: Checkout the code uses: actions/checkout@v3 + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' - name: Get the latest commit hash - run: echo "COMMIT_HASH=$(git rev-parse HEAD)" >> $GITHUB_ENV - + run: | + echo "COMMIT_HASH=$(git rev-parse HEAD)" >> $GITHUB_ENV + echo "CURRENT_VERSION=$(node -p "require('./package.json').version")" >> $GITHUB_ENV + - name: Update commit file run: | - echo "{ \"commit\": \"$COMMIT_HASH\" }" > app/commit.json + echo "{ \"commit\": \"$COMMIT_HASH\" , \"version\": \"$CURRENT_VERSION\" }" > app/commit.json - name: Commit and push the update run: | diff --git a/.github/workflows/update-stable.yml b/.github/workflows/update-stable.yml index 2956f64c..d930fbd1 100644 --- a/.github/workflows/update-stable.yml +++ b/.github/workflows/update-stable.yml @@ -9,30 +9,7 @@ permissions: contents: write jobs: - update-commit: - if: contains(github.event.head_commit.message, '#release') - runs-on: ubuntu-latest - - steps: - - name: Checkout the code - uses: actions/checkout@v3 - - - name: Get the latest commit hash - run: echo "COMMIT_HASH=$(git rev-parse HEAD)" >> $GITHUB_ENV - - - name: Update commit file - run: | - echo "{ \"commit\": \"$COMMIT_HASH\" }" > app/commit.json - - - name: Commit and push the update - run: | - git config --global user.name "github-actions[bot]" - git config --global user.email "github-actions[bot]@users.noreply.github.com" - git add app/commit.json - git commit -m "chore: update commit hash to $COMMIT_HASH" - git push prepare-release: - needs: update-commit if: contains(github.event.head_commit.message, '#release') runs-on: ubuntu-latest @@ -181,10 +158,16 @@ jobs: echo "$CHANGELOG_CONTENT" >> $GITHUB_OUTPUT echo "EOF" >> $GITHUB_OUTPUT + - name: Get the latest commit hash and version tag + run: | + echo "COMMIT_HASH=$(git rev-parse HEAD)" >> $GITHUB_ENV + echo "CURRENT_VERSION=$(node -p "require('./package.json').version")" >> $GITHUB_ENV + - name: Commit and Tag Release run: | git pull - git add package.json pnpm-lock.yaml changelog.md + echo "{ \"commit\": \"$COMMIT_HASH\" , \"version\": \"$CURRENT_VERSION\" }" > app/commit.json + git add package.json pnpm-lock.yaml changelog.md app/commit.json git commit -m "chore: release version ${{ steps.bump_version.outputs.new_version }}" git tag "v${{ steps.bump_version.outputs.new_version }}" git push diff --git a/README.md b/README.md index 405e3887..84235f8c 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,9 @@ https://thinktank.ottomator.ai - ✅ Mobile friendly (@qwikode) - ✅ Better prompt enhancing (@SujalXplores) - ✅ Attach images to prompts (@atrokhym) +- ✅ Added Git Clone button (@thecodacus) +- ✅ Git Import from url (@thecodacus) +- ✅ PromptLibrary to have different variations of prompts for different use cases (@thecodacus) - ✅ Detect package.json and commands to auto install & run preview for folder and git import (@wonderwhy-er) - ✅ Selection tool to target changes visually (@emcconnell) - ⬜ **HIGH PRIORITY** - Prevent bolt from rewriting files as often (file locking and diffs) diff --git a/app/components/chat/AssistantMessage.tsx b/app/components/chat/AssistantMessage.tsx index a5698e97..be304c7b 100644 --- a/app/components/chat/AssistantMessage.tsx +++ b/app/components/chat/AssistantMessage.tsx @@ -1,13 +1,30 @@ import { memo } from 'react'; import { Markdown } from './Markdown'; +import type { JSONValue } from 'ai'; interface AssistantMessageProps { content: string; + annotations?: JSONValue[]; } -export const AssistantMessage = memo(({ content }: AssistantMessageProps) => { +export const AssistantMessage = memo(({ content, annotations }: AssistantMessageProps) => { + const filteredAnnotations = (annotations?.filter( + (annotation: JSONValue) => annotation && typeof annotation === 'object' && Object.keys(annotation).includes('type'), + ) || []) as { type: string; value: any }[]; + + const usage: { + completionTokens: number; + promptTokens: number; + totalTokens: number; + } = filteredAnnotations.find((annotation) => annotation.type === 'usage')?.value; + return (
+ {usage && ( +
+ Tokens: {usage.totalTokens} (prompt: {usage.promptTokens}, completion: {usage.completionTokens}) +
+ )} {content}
); diff --git a/app/components/chat/BaseChat.tsx b/app/components/chat/BaseChat.tsx index 162241d9..2084cbb3 100644 --- a/app/components/chat/BaseChat.tsx +++ b/app/components/chat/BaseChat.tsx @@ -77,7 +77,8 @@ export const BaseChat = React.forwardRef( input = '', enhancingPrompt, handleInputChange, - promptEnhanced, + + // promptEnhanced, enhancePrompt, sendMessage, handleStop, @@ -490,10 +491,7 @@ export const BaseChat = React.forwardRef( { enhancePrompt?.(); toast.success('Prompt enhanced!'); diff --git a/app/components/chat/Chat.client.tsx b/app/components/chat/Chat.client.tsx index 751ea9c6..cff4e367 100644 --- a/app/components/chat/Chat.client.tsx +++ b/app/components/chat/Chat.client.tsx @@ -93,7 +93,7 @@ export const ChatImpl = memo( const [uploadedFiles, setUploadedFiles] = useState([]); // Move here const [imageDataList, setImageDataList] = useState([]); // Move here const files = useStore(workbenchStore.files); - const { activeProviders } = useSettings(); + const { activeProviders, promptId } = useSettings(); const [model, setModel] = useState(() => { const savedModel = Cookies.get('selectedModel'); @@ -115,14 +115,24 @@ export const ChatImpl = memo( body: { apiKeys, files, + promptId, }, + sendExtraMessageFields: true, onError: (error) => { logger.error('Request failed\n\n', error); toast.error( 'There was an error processing your request: ' + (error.message ? error.message : 'No details were returned'), ); }, - onFinish: () => { + onFinish: (message, response) => { + const usage = response.usage; + + if (usage) { + console.log('Token usage:', usage); + + // You can now use the usage data as needed + } + logger.debug('Finished streaming'); }, initialMessages, diff --git a/app/components/chat/Messages.client.tsx b/app/components/chat/Messages.client.tsx index 4a2ac6ac..3b619180 100644 --- a/app/components/chat/Messages.client.tsx +++ b/app/components/chat/Messages.client.tsx @@ -65,12 +65,16 @@ export const Messages = React.forwardRef((props: )}
- {isUserMessage ? : } + {isUserMessage ? ( + + ) : ( + + )}
{!isUserMessage && (
- - {messageId && ( + {messageId && ( +
@@ -34,10 +47,28 @@ export default function FeaturesTab() {

Disclaimer: Experimental features may be unstable and are subject to change.

+
Experimental Providers
+
+
+ Prompt Library +

+ Choose a prompt from the library to use as the system prompt. +

+
+ +
); diff --git a/app/components/settings/providers/ProvidersTab.tsx b/app/components/settings/providers/ProvidersTab.tsx index 926a3c89..281b4c80 100644 --- a/app/components/settings/providers/ProvidersTab.tsx +++ b/app/components/settings/providers/ProvidersTab.tsx @@ -56,7 +56,8 @@ export default function ProvidersTab() {
{ // Fallback to default icon on error + onError={(e) => { + // Fallback to default icon on error e.currentTarget.src = DefaultIcon; }} alt={`${provider.name} icon`} diff --git a/app/components/ui/IconButton.tsx b/app/components/ui/IconButton.tsx index 4eef7fb2..1e830bb5 100644 --- a/app/components/ui/IconButton.tsx +++ b/app/components/ui/IconButton.tsx @@ -1,4 +1,4 @@ -import { memo } from 'react'; +import { memo, forwardRef, type ForwardedRef } from 'react'; import { classNames } from '~/utils/classNames'; type IconSize = 'sm' | 'md' | 'lg' | 'xl' | 'xxl'; @@ -25,41 +25,48 @@ type IconButtonWithChildrenProps = { type IconButtonProps = IconButtonWithoutChildrenProps | IconButtonWithChildrenProps; +// Componente IconButton com suporte a refs export const IconButton = memo( - ({ - icon, - size = 'xl', - className, - iconClassName, - disabledClassName, - disabled = false, - title, - onClick, - children, - }: IconButtonProps) => { - return ( - - ); - }, + onClick?.(event); + }} + > + {children ? children :
} + + ); + }, + ), ); function getIconSize(size: IconSize) { diff --git a/app/components/ui/Tooltip.tsx b/app/components/ui/Tooltip.tsx index 4e22f540..278fa1ea 100644 --- a/app/components/ui/Tooltip.tsx +++ b/app/components/ui/Tooltip.tsx @@ -1,8 +1,9 @@ import * as Tooltip from '@radix-ui/react-tooltip'; +import { forwardRef, type ForwardedRef, type ReactElement } from 'react'; interface TooltipProps { tooltip: React.ReactNode; - children: React.ReactNode; + children: ReactElement; sideOffset?: number; className?: string; arrowClassName?: string; @@ -12,62 +13,67 @@ interface TooltipProps { delay?: number; } -const WithTooltip = ({ - tooltip, - children, - sideOffset = 5, - className = '', - arrowClassName = '', - tooltipStyle = {}, - position = 'top', - maxWidth = 250, - delay = 0, -}: TooltipProps) => { - return ( - - {children} - - -
{tooltip}
- , + ) => { + return ( + + {children} + + - - - - ); -}; + sideOffset={sideOffset} + style={{ + maxWidth, + ...tooltipStyle, + }} + > +
{tooltip}
+ +
+
+
+ ); + }, +); export default WithTooltip; diff --git a/app/lib/.server/llm/stream-text.ts b/app/lib/.server/llm/stream-text.ts index 11ac99bd..74cdd9d4 100644 --- a/app/lib/.server/llm/stream-text.ts +++ b/app/lib/.server/llm/stream-text.ts @@ -1,10 +1,20 @@ import { convertToCoreMessages, streamText as _streamText } from 'ai'; import { getModel } from '~/lib/.server/llm/model'; import { MAX_TOKENS } from './constants'; -import { getSystemPrompt } from './prompts'; -import { DEFAULT_MODEL, DEFAULT_PROVIDER, getModelList, MODEL_REGEX, PROVIDER_REGEX } from '~/utils/constants'; +import { getSystemPrompt } from '~/lib/common/prompts/prompts'; +import { + DEFAULT_MODEL, + DEFAULT_PROVIDER, + getModelList, + MODEL_REGEX, + MODIFICATIONS_TAG_NAME, + PROVIDER_REGEX, + WORK_DIR, +} from '~/utils/constants'; import ignore from 'ignore'; import type { IProviderSetting } from '~/types/model'; +import { PromptLibrary } from '~/lib/common/prompt-library'; +import { allowedHTMLElements } from '~/utils/markdown'; interface ToolResult { toolCallId: string; @@ -139,8 +149,9 @@ export async function streamText(props: { apiKeys?: Record; files?: FileMap; providerSettings?: Record; + promptId?: string; }) { - const { messages, env, options, apiKeys, files, providerSettings } = props; + const { messages, env, options, apiKeys, files, providerSettings, promptId } = props; let currentModel = DEFAULT_MODEL; let currentProvider = DEFAULT_PROVIDER.name; const MODEL_LIST = await getModelList(apiKeys || {}, providerSettings); @@ -170,11 +181,17 @@ export async function streamText(props: { const dynamicMaxTokens = modelDetails && modelDetails.maxTokenAllowed ? modelDetails.maxTokenAllowed : MAX_TOKENS; - let systemPrompt = getSystemPrompt(); + let systemPrompt = + PromptLibrary.getPropmtFromLibrary(promptId || 'default', { + cwd: WORK_DIR, + allowedHtmlElements: allowedHTMLElements, + modificationTagName: MODIFICATIONS_TAG_NAME, + }) ?? getSystemPrompt(); let codeContext = ''; if (files) { codeContext = createFilesContext(files); + codeContext = ''; systemPrompt = `${systemPrompt}\n\n ${codeContext}`; } diff --git a/app/lib/common/prompt-library.ts b/app/lib/common/prompt-library.ts new file mode 100644 index 00000000..7513e811 --- /dev/null +++ b/app/lib/common/prompt-library.ts @@ -0,0 +1,49 @@ +import { getSystemPrompt } from './prompts/prompts'; +import optimized from './prompts/optimized'; + +export interface PromptOptions { + cwd: string; + allowedHtmlElements: string[]; + modificationTagName: string; +} + +export class PromptLibrary { + static library: Record< + string, + { + label: string; + description: string; + get: (options: PromptOptions) => string; + } + > = { + default: { + label: 'Default Prompt', + description: 'This is the battle tested default system Prompt', + get: (options) => getSystemPrompt(options.cwd), + }, + optimized: { + label: 'Optimized Prompt (experimental)', + description: 'an Experimental version of the prompt for lower token usage', + get: (options) => optimized(options), + }, + }; + static getList() { + return Object.entries(this.library).map(([key, value]) => { + const { label, description } = value; + return { + id: key, + label, + description, + }; + }); + } + static getPropmtFromLibrary(promptId: string, options: PromptOptions) { + const prompt = this.library[promptId]; + + if (!prompt) { + throw 'Prompt Now Found'; + } + + return this.library[promptId]?.get(options); + } +} diff --git a/app/lib/common/prompts/optimized.ts b/app/lib/common/prompts/optimized.ts new file mode 100644 index 00000000..26eb2da5 --- /dev/null +++ b/app/lib/common/prompts/optimized.ts @@ -0,0 +1,199 @@ +import type { PromptOptions } from '~/lib/common/prompt-library'; + +export default (options: PromptOptions) => { + const { cwd, allowedHtmlElements, modificationTagName } = options; + return ` +You are Bolt, an expert AI assistant and exceptional senior software developer with vast knowledge across multiple programming languages, frameworks, and best practices. + + + - Operating in WebContainer, an in-browser Node.js runtime + - Limited Python support: standard library only, no pip + - No C/C++ compiler, native binaries, or Git + - Prefer Node.js scripts over shell scripts + - Use Vite for web servers + - Databases: prefer libsql, sqlite, or non-native solutions + - When for react dont forget to write vite config and index.html to the project + + Available shell commands: cat, cp, ls, mkdir, mv, rm, rmdir, touch, hostname, ps, pwd, uptime, env, node, python3, code, jq, curl, head, sort, tail, clear, which, export, chmod, scho, kill, ln, xxd, alias, getconf, loadenv, wasm, xdg-open, command, exit, source + + + + Use 2 spaces for indentation + + + + Available HTML elements: ${allowedHtmlElements.join(', ')} + + + + File modifications in \`<${modificationTagName}>\` section: + - \`\`: GNU unified diff format + - \`\`: Full new content + + + + do not mention the phrase "chain of thought" + Before solutions, briefly outline implementation steps (2-4 lines max): + - List concrete steps + - Identify key components + - Note potential challenges + - Do not write the actual code just the plan and structure if needed + - Once completed planning start writing the artifacts + + + + Create a single, comprehensive artifact for each project: + - Use \`\` tags with \`title\` and \`id\` attributes + - Use \`\` tags with \`type\` attribute: + - shell: Run commands + - file: Write/update files (use \`filePath\` attribute) + - start: Start dev server (only when necessary) + - Order actions logically + - Install dependencies first + - Provide full, updated content for all files + - Use coding best practices: modular, clean, readable code + + + +# CRITICAL RULES - NEVER IGNORE + +## File and Command Handling +1. ALWAYS use artifacts for file contents and commands - NO EXCEPTIONS +2. When writing a file, INCLUDE THE ENTIRE FILE CONTENT - NO PARTIAL UPDATES +3. For modifications, ONLY alter files that require changes - DO NOT touch unaffected files + +## Response Format +4. Use markdown EXCLUSIVELY - HTML tags are ONLY allowed within artifacts +5. Be concise - Explain ONLY when explicitly requested +6. NEVER use the word "artifact" in responses + +## Development Process +7. ALWAYS think and plan comprehensively before providing a solution +8. Current working directory: \`${cwd} \` - Use this for all file paths +9. Don't use cli scaffolding to steup the project, use cwd as Root of the project +11. For nodejs projects ALWAYS install dependencies after writing package.json file + +## Coding Standards +10. ALWAYS create smaller, atomic components and modules +11. Modularity is PARAMOUNT - Break down functionality into logical, reusable parts +12. IMMEDIATELY refactor any file exceeding 250 lines +13. ALWAYS plan refactoring before implementation - Consider impacts on the entire system + +## Artifact Usage +22. Use \`\` tags with \`title\` and \`id\` attributes for each project +23. Use \`\` tags with appropriate \`type\` attribute: + - \`shell\`: For running commands + - \`file\`: For writing/updating files (include \`filePath\` attribute) + - \`start\`: For starting dev servers (use only when necessary/ or new dependencies are installed) +24. Order actions logically - dependencies MUST be installed first +25. For Vite project must include vite config and index.html for entry point +26. Provide COMPLETE, up-to-date content for all files - NO placeholders or partial updates + +CRITICAL: These rules are ABSOLUTE and MUST be followed WITHOUT EXCEPTION in EVERY response. + +Examples: + + + Can you help me create a JavaScript function to calculate the factorial of a number? + + Certainly, I can help you create a JavaScript function to calculate the factorial of a number. + + + +function factorial(n) { + ... +} + +... + + +node index.js + + + + + + + Build a snake game + + Certainly! I'd be happy to help you build a snake game using JavaScript and HTML5 Canvas. This will be a basic implementation that you can later expand upon. Let's create the game step by step. + + + +{ + "name": "snake", + "scripts": { + "dev": "vite" + } + ... +} + + +npm install --save-dev vite + + +... + + +npm run dev + + + + Now you can play the Snake game by opening the provided local server URL in your browser. Use the arrow keys to control the snake. Eat the red food to grow and increase your score. The game ends if you hit the wall or your own tail. + + + + + Make a bouncing ball with real gravity using React + + Certainly! I'll create a bouncing ball with real gravity using React. We'll use the react-spring library for physics-based animations. + + + +{ + "name": "bouncing-ball", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "dependencies": { + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-spring": "^9.7.1" + }, + "devDependencies": { + "@types/react": "^18.0.28", + "@types/react-dom": "^18.0.11", + "@vitejs/plugin-react": "^3.1.0", + "vite": "^4.2.0" + } +} + + +... + + +... + + +... + + +... + + +npm run dev + + + + You can now view the bouncing ball animation in the preview. The ball will start falling from the top of the screen and bounce realistically when it hits the bottom. + + + +Always use artifacts for file contents and commands, following the format shown in these examples. +`; +}; diff --git a/app/lib/.server/llm/prompts.ts b/app/lib/common/prompts/prompts.ts similarity index 100% rename from app/lib/.server/llm/prompts.ts rename to app/lib/common/prompts/prompts.ts diff --git a/app/lib/hooks/useSettings.tsx b/app/lib/hooks/useSettings.tsx index 0a7d65eb..cbdc1894 100644 --- a/app/lib/hooks/useSettings.tsx +++ b/app/lib/hooks/useSettings.tsx @@ -4,8 +4,9 @@ import { isEventLogsEnabled, isLocalModelsEnabled, LOCAL_PROVIDERS, + promptStore, providersStore, - latestBranch, + latestBranchStore, } from '~/lib/stores/settings'; import { useCallback, useEffect, useState } from 'react'; import Cookies from 'js-cookie'; @@ -15,25 +16,34 @@ import commit from '~/commit.json'; interface CommitData { commit: string; + version?: string; } +const commitJson: CommitData = commit; + export function useSettings() { const providers = useStore(providersStore); const debug = useStore(isDebugMode); const eventLogs = useStore(isEventLogsEnabled); + const promptId = useStore(promptStore); const isLocalModel = useStore(isLocalModelsEnabled); - const useLatest = useStore(latestBranch); + const isLatestBranch = useStore(latestBranchStore); const [activeProviders, setActiveProviders] = useState([]); // Function to check if we're on stable version const checkIsStableVersion = async () => { try { - const stableResponse = await fetch('https://raw.githubusercontent.com/stackblitz-labs/bolt.diy/stable/app/commit.json'); + const stableResponse = await fetch( + `https://raw.githubusercontent.com/stackblitz-labs/bolt.diy/refs/tags/v${commitJson.version}/app/commit.json`, + ); + if (!stableResponse.ok) { console.warn('Failed to fetch stable commit info'); return false; } - const stableData = await stableResponse.json() as CommitData; + + const stableData = (await stableResponse.json()) as CommitData; + return commit.commit === stableData.commit; } catch (error) { console.warn('Error checking stable version:', error); @@ -84,17 +94,30 @@ export function useSettings() { isLocalModelsEnabled.set(savedLocalModels === 'true'); } + const promptId = Cookies.get('promptId'); + + if (promptId) { + promptStore.set(promptId); + } + // load latest branch setting from cookies or determine based on version - const savedLatestBranch = Cookies.get('useLatestBranch'); - if (savedLatestBranch === undefined) { + const savedLatestBranch = Cookies.get('isLatestBranch'); + let checkCommit = Cookies.get('commitHash'); + + if (checkCommit === undefined) { + checkCommit = commit.commit; + } + + if (savedLatestBranch === undefined || checkCommit !== commit.commit) { // If setting hasn't been set by user, check version - checkIsStableVersion().then(isStable => { + checkIsStableVersion().then((isStable) => { const shouldUseLatest = !isStable; - latestBranch.set(shouldUseLatest); - Cookies.set('useLatestBranch', String(shouldUseLatest)); + latestBranchStore.set(shouldUseLatest); + Cookies.set('isLatestBranch', String(shouldUseLatest)); + Cookies.set('commitHash', String(commit.commit)); }); } else { - latestBranch.set(savedLatestBranch === 'true'); + latestBranchStore.set(savedLatestBranch === 'true'); } }, []); @@ -147,10 +170,14 @@ export function useSettings() { Cookies.set('isLocalModelsEnabled', String(enabled)); }, []); + const setPromptId = useCallback((promptId: string) => { + promptStore.set(promptId); + Cookies.set('promptId', promptId); + }, []); const enableLatestBranch = useCallback((enabled: boolean) => { - latestBranch.set(enabled); + latestBranchStore.set(enabled); logStore.logSystem(`Main branch updates ${enabled ? 'enabled' : 'disabled'}`); - Cookies.set('useLatestBranch', String(enabled)); + Cookies.set('isLatestBranch', String(enabled)); }, []); return { @@ -163,7 +190,9 @@ export function useSettings() { enableEventLogs, isLocalModel, enableLocalModels, - useLatestBranch: useLatest, + promptId, + setPromptId, + isLatestBranch, enableLatestBranch, }; } diff --git a/app/lib/stores/settings.ts b/app/lib/stores/settings.ts index 2e410a60..cbaf30e9 100644 --- a/app/lib/stores/settings.ts +++ b/app/lib/stores/settings.ts @@ -47,4 +47,6 @@ export const isEventLogsEnabled = atom(false); export const isLocalModelsEnabled = atom(true); -export const latestBranch = atom(false); +export const promptStore = atom('default'); + +export const latestBranchStore = atom(false); diff --git a/app/routes/api.chat.ts b/app/routes/api.chat.ts index 87ca5c7c..16ce9134 100644 --- a/app/routes/api.chat.ts +++ b/app/routes/api.chat.ts @@ -1,6 +1,7 @@ import { type ActionFunctionArgs } from '@remix-run/cloudflare'; +import { createDataStream } from 'ai'; import { MAX_RESPONSE_SEGMENTS, MAX_TOKENS } from '~/lib/.server/llm/constants'; -import { CONTINUE_PROMPT } from '~/lib/.server/llm/prompts'; +import { CONTINUE_PROMPT } from '~/lib/common/prompts/prompts'; import { streamText, type Messages, type StreamingOptions } from '~/lib/.server/llm/stream-text'; import SwitchableStream from '~/lib/.server/llm/switchable-stream'; import type { IProviderSetting } from '~/types/model'; @@ -9,17 +10,15 @@ export async function action(args: ActionFunctionArgs) { return chatAction(args); } -function parseCookies(cookieHeader: string) { - const cookies: any = {}; +function parseCookies(cookieHeader: string): Record { + const cookies: Record = {}; - // Split the cookie string by semicolons and spaces const items = cookieHeader.split(';').map((cookie) => cookie.trim()); items.forEach((item) => { const [name, ...rest] = item.split('='); if (name && rest) { - // Decode the name and value, and join value parts in case it contains '=' const decodedName = decodeURIComponent(name.trim()); const decodedValue = decodeURIComponent(rest.join('=').trim()); cookies[decodedName] = decodedValue; @@ -30,14 +29,13 @@ function parseCookies(cookieHeader: string) { } async function chatAction({ context, request }: ActionFunctionArgs) { - const { messages, files } = await request.json<{ + const { messages, files, promptId } = await request.json<{ messages: Messages; files: any; + promptId?: string; }>(); const cookieHeader = request.headers.get('Cookie'); - - // Parse the cookie's value (returns an object or null if no cookie exists) const apiKeys = JSON.parse(parseCookies(cookieHeader || '').apiKeys || '{}'); const providerSettings: Record = JSON.parse( parseCookies(cookieHeader || '').providers || '{}', @@ -45,12 +43,42 @@ async function chatAction({ context, request }: ActionFunctionArgs) { const stream = new SwitchableStream(); + const cumulativeUsage = { + completionTokens: 0, + promptTokens: 0, + totalTokens: 0, + }; + try { const options: StreamingOptions = { toolChoice: 'none', - onFinish: async ({ text: content, finishReason }) => { + onFinish: async ({ text: content, finishReason, usage }) => { + console.log('usage', usage); + + if (usage) { + cumulativeUsage.completionTokens += usage.completionTokens || 0; + cumulativeUsage.promptTokens += usage.promptTokens || 0; + cumulativeUsage.totalTokens += usage.totalTokens || 0; + } + if (finishReason !== 'length') { - return stream.close(); + return stream + .switchSource( + createDataStream({ + async execute(dataStream) { + dataStream.writeMessageAnnotation({ + type: 'usage', + value: { + completionTokens: cumulativeUsage.completionTokens, + promptTokens: cumulativeUsage.promptTokens, + totalTokens: cumulativeUsage.totalTokens, + }, + }); + }, + onError: (error: any) => `Custom error: ${error.message}`, + }), + ) + .then(() => stream.close()); } if (stream.switches >= MAX_RESPONSE_SEGMENTS) { @@ -71,9 +99,10 @@ async function chatAction({ context, request }: ActionFunctionArgs) { apiKeys, files, providerSettings, + promptId, }); - return stream.switchSource(result.toAIStream()); + return stream.switchSource(result.toDataStream()); }, }; @@ -84,9 +113,10 @@ async function chatAction({ context, request }: ActionFunctionArgs) { apiKeys, files, providerSettings, + promptId, }); - stream.switchSource(result.toAIStream()); + stream.switchSource(result.toDataStream()); return new Response(stream.readable, { status: 200, @@ -95,7 +125,7 @@ async function chatAction({ context, request }: ActionFunctionArgs) { }, }); } catch (error: any) { - console.log(error); + console.error(error); if (error.message?.includes('API key')) { throw new Response('Invalid or missing API key', { diff --git a/app/routes/api.enhancer.ts b/app/routes/api.enhancer.ts index cc51116f..c2dbba4a 100644 --- a/app/routes/api.enhancer.ts +++ b/app/routes/api.enhancer.ts @@ -1,5 +1,6 @@ import { type ActionFunctionArgs } from '@remix-run/cloudflare'; -import { StreamingTextResponse, parseStreamPart } from 'ai'; + +//import { StreamingTextResponse, parseStreamPart } from 'ai'; import { streamText } from '~/lib/.server/llm/stream-text'; import { stripIndents } from '~/utils/stripIndent'; import type { IProviderSetting, ProviderInfo } from '~/types/model'; @@ -73,32 +74,32 @@ async function enhancerAction({ context, request }: ActionFunctionArgs) { `[Model: ${model}]\n\n[Provider: ${providerName}]\n\n` + stripIndents` You are a professional prompt engineer specializing in crafting precise, effective prompts. - Your task is to enhance prompts by making them more specific, actionable, and effective. + Your task is to enhance prompts by making them more specific, actionable, and effective. - I want you to improve the user prompt that is wrapped in \`\` tags. + I want you to improve the user prompt that is wrapped in \`\` tags. - For valid prompts: - - Make instructions explicit and unambiguous - - Add relevant context and constraints - - Remove redundant information - - Maintain the core intent - - Ensure the prompt is self-contained - - Use professional language + For valid prompts: + - Make instructions explicit and unambiguous + - Add relevant context and constraints + - Remove redundant information + - Maintain the core intent + - Ensure the prompt is self-contained + - Use professional language - For invalid or unclear prompts: - - Respond with a clear, professional guidance message - - Keep responses concise and actionable - - Maintain a helpful, constructive tone - - Focus on what the user should provide - - Use a standard template for consistency + For invalid or unclear prompts: + - Respond with clear, professional guidance + - Keep responses concise and actionable + - Maintain a helpful, constructive tone + - Focus on what the user should provide + - Use a standard template for consistency - IMPORTANT: Your response must ONLY contain the enhanced prompt text. - Do not include any explanations, metadata, or wrapper tags. + IMPORTANT: Your response must ONLY contain the enhanced prompt text. + Do not include any explanations, metadata, or wrapper tags. - - ${message} - - `, + + ${message} + + `, }, ], env: context.cloudflare.env, @@ -113,7 +114,7 @@ async function enhancerAction({ context, request }: ActionFunctionArgs) { for (const line of lines) { try { - const parsed = parseStreamPart(line); + const parsed = JSON.parse(line); if (parsed.type === 'text') { controller.enqueue(encoder.encode(parsed.value)); @@ -128,7 +129,12 @@ async function enhancerAction({ context, request }: ActionFunctionArgs) { const transformedStream = result.toDataStream().pipeThrough(transformStream); - return new StreamingTextResponse(transformedStream); + return new Response(transformedStream, { + status: 200, + headers: { + 'Content-Type': 'text/plain; charset=utf-8', + }, + }); } catch (error: unknown) { console.log(error); diff --git a/app/utils/constants.ts b/app/utils/constants.ts index 75f40905..64259954 100644 --- a/app/utils/constants.ts +++ b/app/utils/constants.ts @@ -141,7 +141,7 @@ const PROVIDER_LIST: ProviderInfo[] = [ staticModels: [ { name: 'llama-3.1-8b-instant', label: 'Llama 3.1 8b (Groq)', provider: 'Groq', maxTokenAllowed: 8000 }, { name: 'llama-3.2-11b-vision-preview', label: 'Llama 3.2 11b (Groq)', provider: 'Groq', maxTokenAllowed: 8000 }, - { name: 'llama-3.2-90b-vision-preview', label: 'Llama 3.2 90b (Groq)', provider: 'Groq', maxTokenAllowed: 8000 }, + { name: 'llama-3.2-90b-vision-preview', label: 'Llama 3.2 90b (Groq)', provider: 'Groq', maxTokenAllowed: 8000 }, { name: 'llama-3.2-3b-preview', label: 'Llama 3.2 3b (Groq)', provider: 'Groq', maxTokenAllowed: 8000 }, { name: 'llama-3.2-1b-preview', label: 'Llama 3.2 1b (Groq)', provider: 'Groq', maxTokenAllowed: 8000 }, { name: 'llama-3.3-70b-versatile', label: 'Llama 3.3 70b (Groq)', provider: 'Groq', maxTokenAllowed: 8000 }, diff --git a/package.json b/package.json index 878c44cd..6b197f80 100644 --- a/package.json +++ b/package.json @@ -73,7 +73,7 @@ "@xterm/addon-fit": "^0.10.0", "@xterm/addon-web-links": "^0.11.0", "@xterm/xterm": "^5.5.0", - "ai": "^3.4.33", + "ai": "^4.0.13", "date-fns": "^3.6.0", "diff": "^5.2.0", "file-saver": "^2.0.5", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 17bdc899..efec8986 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -141,8 +141,8 @@ importers: specifier: ^5.5.0 version: 5.5.0 ai: - specifier: ^3.4.33 - version: 3.4.33(react@18.3.1)(sswr@2.1.0(svelte@5.4.0))(svelte@5.4.0)(vue@3.5.13(typescript@5.7.2))(zod@3.23.8) + specifier: ^4.0.13 + version: 4.0.18(react@18.3.1)(zod@3.23.8) date-fns: specifier: ^3.6.0 version: 3.6.0 @@ -351,15 +351,6 @@ packages: zod: optional: true - '@ai-sdk/provider-utils@1.0.22': - resolution: {integrity: sha512-YHK2rpj++wnLVc9vPGzGFP3Pjeld2MwhKinetA0zKXOoHAT/Jit5O8kZsxcSlJPu9wvcGT1UGZEjZrtO7PfFOQ==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.0.0 - peerDependenciesMeta: - zod: - optional: true - '@ai-sdk/provider-utils@1.0.9': resolution: {integrity: sha512-yfdanjUiCJbtGoRGXrcrmXn0pTyDfRIeY6ozDG96D66f2wupZaZvAgKptUa3zDYXtUCQQvcNJ+tipBBfQD/UYA==} engines: {node: '>=18'} @@ -378,6 +369,15 @@ packages: zod: optional: true + '@ai-sdk/provider-utils@2.0.4': + resolution: {integrity: sha512-GMhcQCZbwM6RoZCri0MWeEWXRt/T+uCxsmHEsTwNvEH3GDjNzchfX25C8ftry2MeEOOn6KfqCLSKomcgK6RoOg==} + 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'} @@ -390,16 +390,16 @@ packages: resolution: {integrity: sha512-XMsNGJdGO+L0cxhhegtqZ8+T6nn4EoShS819OvCgI2kLbYTIvk0GWFGD0AXJmxkxs3DrpsJxKAFukFR7bvTkgQ==} engines: {node: '>=18'} - '@ai-sdk/provider@0.0.26': - resolution: {integrity: sha512-dQkfBDs2lTYpKM8389oopPdQgIU007GQyCbuPPrV+K6MtSII3HBfE0stUIMXUb44L+LK1t6GXPP7wjSzjO6uKg==} - engines: {node: '>=18'} - '@ai-sdk/provider@1.0.1': resolution: {integrity: sha512-mV+3iNDkzUsZ0pR2jG0sVzU6xtQY5DtSCBy3JFycLp6PwjyLw/iodfL3MwdmMCRJWgs3dadcHejRnMvF9nGTBg==} engines: {node: '>=18'} - '@ai-sdk/react@0.0.70': - resolution: {integrity: sha512-GnwbtjW4/4z7MleLiW+TOZC2M29eCg1tOUpuEiYFMmFNZK8mkrqM0PFZMo6UsYeUYMWqEOOcPOU9OQVJMJh7IQ==} + '@ai-sdk/provider@1.0.2': + resolution: {integrity: sha512-YYtP6xWQyaAf5LiWLJ+ycGTOeBLWrED7LUrvc+SQIWhGaneylqbaGsyQL7VouQUeQ4JZ1qKYZuhmi3W56HADPA==} + engines: {node: '>=18'} + + '@ai-sdk/react@1.0.6': + resolution: {integrity: sha512-8Hkserq0Ge6AEi7N4hlv2FkfglAGbkoAXEZ8YSp255c3PbnZz6+/5fppw+aROmZMOfNwallSRuy1i/iPa2rBpQ==} engines: {node: '>=18'} peerDependencies: react: ^18 || ^19 || ^19.0.0-rc @@ -410,26 +410,8 @@ packages: zod: optional: true - '@ai-sdk/solid@0.0.54': - resolution: {integrity: sha512-96KWTVK+opdFeRubqrgaJXoNiDP89gNxFRWUp0PJOotZW816AbhUf4EnDjBjXTLjXL1n0h8tGSE9sZsRkj9wQQ==} - engines: {node: '>=18'} - peerDependencies: - solid-js: ^1.7.7 - peerDependenciesMeta: - solid-js: - optional: true - - '@ai-sdk/svelte@0.0.57': - resolution: {integrity: sha512-SyF9ItIR9ALP9yDNAD+2/5Vl1IT6kchgyDH8xkmhysfJI6WrvJbtO1wdQ0nylvPLcsPoYu+cAlz1krU4lFHcYw==} - engines: {node: '>=18'} - peerDependencies: - svelte: ^3.0.0 || ^4.0.0 || ^5.0.0 - peerDependenciesMeta: - svelte: - optional: true - - '@ai-sdk/ui-utils@0.0.50': - resolution: {integrity: sha512-Z5QYJVW+5XpSaJ4jYCCAVG7zIAuKOOdikhgpksneNmKvx61ACFaf98pmOd+xnjahl0pIlc/QIe6O4yVaJ1sEaw==} + '@ai-sdk/ui-utils@1.0.5': + resolution: {integrity: sha512-DGJSbDf+vJyWmFNexSPUsS1AAy7gtsmFmoSyNbNbJjwl9hRIf2dknfA1V0ahx6pg3NNklNYFm53L8Nphjovfvg==} engines: {node: '>=18'} peerDependencies: zod: ^3.0.0 @@ -437,15 +419,6 @@ packages: zod: optional: true - '@ai-sdk/vue@0.0.59': - resolution: {integrity: sha512-+ofYlnqdc8c4F6tM0IKF0+7NagZRAiqBJpGDJ+6EYhDW8FHLUP/JFBgu32SjxSxC6IKFZxEnl68ZoP/Z38EMlw==} - engines: {node: '>=18'} - peerDependencies: - vue: ^3.3.4 - peerDependenciesMeta: - vue: - optional: true - '@ampproject/remapping@2.3.0': resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} @@ -2370,35 +2343,6 @@ packages: '@vitest/utils@2.1.8': resolution: {integrity: sha512-dwSoui6djdwbfFmIgbIjX2ZhIoG7Ex/+xpxyiEgIGzjliY8xGkcpITKTlp6B4MgtGkF2ilvm97cPM96XZaAgcA==} - '@vue/compiler-core@3.5.13': - resolution: {integrity: sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==} - - '@vue/compiler-dom@3.5.13': - resolution: {integrity: sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==} - - '@vue/compiler-sfc@3.5.13': - resolution: {integrity: sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==} - - '@vue/compiler-ssr@3.5.13': - resolution: {integrity: sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==} - - '@vue/reactivity@3.5.13': - resolution: {integrity: sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==} - - '@vue/runtime-core@3.5.13': - resolution: {integrity: sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw==} - - '@vue/runtime-dom@3.5.13': - resolution: {integrity: sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog==} - - '@vue/server-renderer@3.5.13': - resolution: {integrity: sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA==} - peerDependencies: - vue: 3.5.13 - - '@vue/shared@3.5.13': - resolution: {integrity: sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==} - '@web3-storage/multipart-parser@1.0.0': resolution: {integrity: sha512-BEO6al7BYqcnfX15W2cnGR+Q566ACXAT9UQykORCWW80lmkpWsnEob6zJS1ZVBKsSJC8+7vJkHwlp+lXG1UCdw==} @@ -2434,11 +2378,6 @@ packages: peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - acorn-typescript@1.4.13: - resolution: {integrity: sha512-xsc9Xv0xlVfwp2o7sQ+GCQ1PgbkdcpWdTzrwXxO3xDMTAywVS3oXVOcOHuRjAPkS4P9b+yc/qNF15460v+jp4Q==} - peerDependencies: - acorn: '>=8.9.0' - acorn-walk@8.3.4: resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} engines: {node: '>=0.4.0'} @@ -2452,24 +2391,15 @@ packages: resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} engines: {node: '>=8'} - ai@3.4.33: - resolution: {integrity: sha512-plBlrVZKwPoRTmM8+D1sJac9Bq8eaa2jiZlHLZIWekKWI1yMWYZvCCEezY9ASPwRhULYDJB2VhKOBUUeg3S5JQ==} + ai@4.0.18: + resolution: {integrity: sha512-BTWzalLNE1LQphEka5xzJXDs5v4xXy1Uzr7dAVk+C/CnO3WNpuMBgrCymwUv0VrWaWc8xMQuh+OqsT7P7JyekQ==} engines: {node: '>=18'} peerDependencies: - openai: ^4.42.0 react: ^18 || ^19 || ^19.0.0-rc - sswr: ^2.1.0 - svelte: ^3.0.0 || ^4.0.0 || ^5.0.0 zod: ^3.0.0 peerDependenciesMeta: - openai: - optional: true react: optional: true - sswr: - optional: true - svelte: - optional: true zod: optional: true @@ -2506,10 +2436,6 @@ packages: resolution: {integrity: sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==} engines: {node: '>=10'} - aria-query@5.3.2: - resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} - engines: {node: '>= 0.4'} - array-flatten@1.1.1: resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} @@ -2537,10 +2463,6 @@ packages: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} - axobject-query@4.1.0: - resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} - engines: {node: '>= 0.4'} - bail@2.0.2: resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} @@ -3149,9 +3071,6 @@ packages: jiti: optional: true - esm-env@1.2.1: - resolution: {integrity: sha512-U9JedYYjCnadUlXk7e1Kr+aENQhtUaoaV9+gZm1T8LC/YBAPJx3NSPIAurFOC0U5vrdSevnUJS2/wUVxGwPhng==} - espree@10.3.0: resolution: {integrity: sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -3164,9 +3083,6 @@ packages: resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} engines: {node: '>=0.10'} - esrap@1.2.3: - resolution: {integrity: sha512-ZlQmCCK+n7SGoqo7DnfKaP1sJZa49P01/dXzmjCASSo04p72w8EksT2NMK8CEX8DhKsfJXANioIw8VyHNsBfvQ==} - esrecurse@4.3.0: resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} engines: {node: '>=4.0'} @@ -3820,9 +3736,6 @@ packages: resolution: {integrity: sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ==} engines: {node: '>=14'} - locate-character@3.0.0: - resolution: {integrity: sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==} - locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} @@ -5190,11 +5103,6 @@ packages: resolution: {integrity: sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - sswr@2.1.0: - resolution: {integrity: sha512-Cqc355SYlTAaUt8iDPaC/4DPPXK925PePLMxyBKuWd5kKc5mwsG3nT9+Mq2tyguL5s7b4Jg+IRMpTRsNTAfpSQ==} - peerDependencies: - svelte: ^4.0.0 || ^5.0.0-next.0 - stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} @@ -5285,23 +5193,11 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - svelte@5.4.0: - resolution: {integrity: sha512-2I/mjD8cXDpKfdfUK+T6yo/OzugMXIm8lhyJUFM5F/gICMYnkl3C/+4cOSpia8TqpDsi6Qfm5+fdmBNMNmaf2g==} - engines: {node: '>=18'} - swr@2.2.5: resolution: {integrity: sha512-QtxqyclFeAsxEUeZIYmsaQ0UjimSq1RZ9Un7I68/0ClKK/U3LoyQunwkQfJZr2fc22DfIXLNDc2wFyTEikCUpg==} peerDependencies: react: ^16.11.0 || ^17.0.0 || ^18.0.0 - swrev@4.0.0: - resolution: {integrity: sha512-LqVcOHSB4cPGgitD1riJ1Hh4vdmITOp+BkmfmXRh4hSF/t7EnS4iD+SOTmq7w5pPm/SiPeto4ADbKS6dHUDWFA==} - - swrv@1.0.4: - resolution: {integrity: sha512-zjEkcP8Ywmj+xOJW3lIT65ciY/4AL4e/Or7Gj0MzU3zBJNMdJiT8geVZhINavnlHRMMCcJLHhraLTAiDOTmQ9g==} - peerDependencies: - vue: '>=3.2.26 < 4' - sync-child-process@1.0.2: resolution: {integrity: sha512-8lD+t2KrrScJ/7KXCSyfhT3/hRq78rC0wBFqNJXv3mZyn6hW2ypM05JmlSvtqRbeq6jqA94oHbxAr2vYsJ8vDA==} engines: {node: '>=16.0.0'} @@ -5721,14 +5617,6 @@ packages: vm-browserify@1.1.2: resolution: {integrity: sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==} - vue@3.5.13: - resolution: {integrity: sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - w3c-keyname@2.2.8: resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} @@ -5843,9 +5731,6 @@ packages: youch@3.3.4: resolution: {integrity: sha512-UeVBXie8cA35DS6+nBkls68xaBBXCye0CNznrhszZjTbRVnJKQuNsyLKBTTL4ln1o1rh2PKtv35twV7irj5SEg==} - zimmerframe@1.1.2: - resolution: {integrity: sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==} - zod-to-json-schema@3.23.5: resolution: {integrity: sha512-5wlSS0bXfF/BrL4jPAbz9da5hDlDptdEppYfe+x4eIJ7jioqKG9uUxOwPzqof09u/XeVdrgFu29lZi+8XNDJtA==} peerDependencies: @@ -5908,15 +5793,6 @@ snapshots: optionalDependencies: zod: 3.23.8 - '@ai-sdk/provider-utils@1.0.22(zod@3.23.8)': - dependencies: - '@ai-sdk/provider': 0.0.26 - eventsource-parser: 1.1.2 - nanoid: 3.3.8 - secure-json-parse: 2.7.0 - optionalDependencies: - zod: 3.23.8 - '@ai-sdk/provider-utils@1.0.9(zod@3.23.8)': dependencies: '@ai-sdk/provider': 0.0.17 @@ -5935,6 +5811,15 @@ snapshots: optionalDependencies: zod: 3.23.8 + '@ai-sdk/provider-utils@2.0.4(zod@3.23.8)': + dependencies: + '@ai-sdk/provider': 1.0.2 + 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 @@ -5947,61 +5832,32 @@ snapshots: dependencies: json-schema: 0.4.0 - '@ai-sdk/provider@0.0.26': - dependencies: - json-schema: 0.4.0 - '@ai-sdk/provider@1.0.1': dependencies: json-schema: 0.4.0 - '@ai-sdk/react@0.0.70(react@18.3.1)(zod@3.23.8)': + '@ai-sdk/provider@1.0.2': dependencies: - '@ai-sdk/provider-utils': 1.0.22(zod@3.23.8) - '@ai-sdk/ui-utils': 0.0.50(zod@3.23.8) + 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) + '@ai-sdk/ui-utils': 1.0.5(zod@3.23.8) swr: 2.2.5(react@18.3.1) throttleit: 2.1.0 optionalDependencies: react: 18.3.1 zod: 3.23.8 - '@ai-sdk/solid@0.0.54(zod@3.23.8)': + '@ai-sdk/ui-utils@1.0.5(zod@3.23.8)': dependencies: - '@ai-sdk/provider-utils': 1.0.22(zod@3.23.8) - '@ai-sdk/ui-utils': 0.0.50(zod@3.23.8) - transitivePeerDependencies: - - zod - - '@ai-sdk/svelte@0.0.57(svelte@5.4.0)(zod@3.23.8)': - dependencies: - '@ai-sdk/provider-utils': 1.0.22(zod@3.23.8) - '@ai-sdk/ui-utils': 0.0.50(zod@3.23.8) - sswr: 2.1.0(svelte@5.4.0) - optionalDependencies: - svelte: 5.4.0 - transitivePeerDependencies: - - zod - - '@ai-sdk/ui-utils@0.0.50(zod@3.23.8)': - dependencies: - '@ai-sdk/provider': 0.0.26 - '@ai-sdk/provider-utils': 1.0.22(zod@3.23.8) - json-schema: 0.4.0 - secure-json-parse: 2.7.0 + '@ai-sdk/provider': 1.0.2 + '@ai-sdk/provider-utils': 2.0.4(zod@3.23.8) zod-to-json-schema: 3.23.5(zod@3.23.8) optionalDependencies: zod: 3.23.8 - '@ai-sdk/vue@0.0.59(vue@3.5.13(typescript@5.7.2))(zod@3.23.8)': - dependencies: - '@ai-sdk/provider-utils': 1.0.22(zod@3.23.8) - '@ai-sdk/ui-utils': 0.0.50(zod@3.23.8) - swrv: 1.0.4(vue@3.5.13(typescript@5.7.2)) - optionalDependencies: - vue: 3.5.13(typescript@5.7.2) - transitivePeerDependencies: - - zod - '@ampproject/remapping@2.3.0': dependencies: '@jridgewell/gen-mapping': 0.3.5 @@ -8045,60 +7901,6 @@ snapshots: loupe: 3.1.2 tinyrainbow: 1.2.0 - '@vue/compiler-core@3.5.13': - dependencies: - '@babel/parser': 7.26.2 - '@vue/shared': 3.5.13 - entities: 4.5.0 - estree-walker: 2.0.2 - source-map-js: 1.2.1 - - '@vue/compiler-dom@3.5.13': - dependencies: - '@vue/compiler-core': 3.5.13 - '@vue/shared': 3.5.13 - - '@vue/compiler-sfc@3.5.13': - dependencies: - '@babel/parser': 7.26.2 - '@vue/compiler-core': 3.5.13 - '@vue/compiler-dom': 3.5.13 - '@vue/compiler-ssr': 3.5.13 - '@vue/shared': 3.5.13 - estree-walker: 2.0.2 - magic-string: 0.30.14 - postcss: 8.4.49 - source-map-js: 1.2.1 - - '@vue/compiler-ssr@3.5.13': - dependencies: - '@vue/compiler-dom': 3.5.13 - '@vue/shared': 3.5.13 - - '@vue/reactivity@3.5.13': - dependencies: - '@vue/shared': 3.5.13 - - '@vue/runtime-core@3.5.13': - dependencies: - '@vue/reactivity': 3.5.13 - '@vue/shared': 3.5.13 - - '@vue/runtime-dom@3.5.13': - dependencies: - '@vue/reactivity': 3.5.13 - '@vue/runtime-core': 3.5.13 - '@vue/shared': 3.5.13 - csstype: 3.1.3 - - '@vue/server-renderer@3.5.13(vue@3.5.13(typescript@5.7.2))': - dependencies: - '@vue/compiler-ssr': 3.5.13 - '@vue/shared': 3.5.13 - vue: 3.5.13(typescript@5.7.2) - - '@vue/shared@3.5.13': {} - '@web3-storage/multipart-parser@1.0.0': {} '@webcontainer/api@1.3.0-internal.10': {} @@ -8129,10 +7931,6 @@ snapshots: dependencies: acorn: 8.14.0 - acorn-typescript@1.4.13(acorn@8.14.0): - dependencies: - acorn: 8.14.0 - acorn-walk@8.3.4: dependencies: acorn: 8.14.0 @@ -8144,29 +7942,18 @@ snapshots: clean-stack: 2.2.0 indent-string: 4.0.0 - ai@3.4.33(react@18.3.1)(sswr@2.1.0(svelte@5.4.0))(svelte@5.4.0)(vue@3.5.13(typescript@5.7.2))(zod@3.23.8): + ai@4.0.18(react@18.3.1)(zod@3.23.8): dependencies: - '@ai-sdk/provider': 0.0.26 - '@ai-sdk/provider-utils': 1.0.22(zod@3.23.8) - '@ai-sdk/react': 0.0.70(react@18.3.1)(zod@3.23.8) - '@ai-sdk/solid': 0.0.54(zod@3.23.8) - '@ai-sdk/svelte': 0.0.57(svelte@5.4.0)(zod@3.23.8) - '@ai-sdk/ui-utils': 0.0.50(zod@3.23.8) - '@ai-sdk/vue': 0.0.59(vue@3.5.13(typescript@5.7.2))(zod@3.23.8) + '@ai-sdk/provider': 1.0.2 + '@ai-sdk/provider-utils': 2.0.4(zod@3.23.8) + '@ai-sdk/react': 1.0.6(react@18.3.1)(zod@3.23.8) + '@ai-sdk/ui-utils': 1.0.5(zod@3.23.8) '@opentelemetry/api': 1.9.0 - eventsource-parser: 1.1.2 - json-schema: 0.4.0 jsondiffpatch: 0.6.0 - secure-json-parse: 2.7.0 zod-to-json-schema: 3.23.5(zod@3.23.8) optionalDependencies: react: 18.3.1 - sswr: 2.1.0(svelte@5.4.0) - svelte: 5.4.0 zod: 3.23.8 - transitivePeerDependencies: - - solid-js - - vue ajv@6.12.6: dependencies: @@ -8198,8 +7985,6 @@ snapshots: dependencies: tslib: 2.8.1 - aria-query@5.3.2: {} - array-flatten@1.1.1: {} as-table@1.0.55: @@ -8230,8 +8015,6 @@ snapshots: dependencies: possible-typed-array-names: 1.0.0 - axobject-query@4.1.0: {} - bail@2.0.2: {} balanced-match@1.0.2: {} @@ -8931,8 +8714,6 @@ snapshots: transitivePeerDependencies: - supports-color - esm-env@1.2.1: {} - espree@10.3.0: dependencies: acorn: 8.14.0 @@ -8949,11 +8730,6 @@ snapshots: dependencies: estraverse: 5.3.0 - esrap@1.2.3: - dependencies: - '@jridgewell/sourcemap-codec': 1.5.0 - '@types/estree': 1.0.6 - esrecurse@4.3.0: dependencies: estraverse: 5.3.0 @@ -9680,8 +9456,6 @@ snapshots: mlly: 1.7.3 pkg-types: 1.2.1 - locate-character@3.0.0: {} - locate-path@6.0.0: dependencies: p-locate: 5.0.0 @@ -11492,11 +11266,6 @@ snapshots: dependencies: minipass: 7.1.2 - sswr@2.1.0(svelte@5.4.0): - dependencies: - svelte: 5.4.0 - swrev: 4.0.0 - stackback@0.0.2: {} stacktracey@2.1.8: @@ -11587,34 +11356,12 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} - svelte@5.4.0: - dependencies: - '@ampproject/remapping': 2.3.0 - '@jridgewell/sourcemap-codec': 1.5.0 - '@types/estree': 1.0.6 - acorn: 8.14.0 - acorn-typescript: 1.4.13(acorn@8.14.0) - aria-query: 5.3.2 - axobject-query: 4.1.0 - esm-env: 1.2.1 - esrap: 1.2.3 - is-reference: 3.0.3 - locate-character: 3.0.0 - magic-string: 0.30.14 - zimmerframe: 1.1.2 - swr@2.2.5(react@18.3.1): dependencies: client-only: 0.0.1 react: 18.3.1 use-sync-external-store: 1.2.2(react@18.3.1) - swrev@4.0.0: {} - - swrv@1.0.4(vue@3.5.13(typescript@5.7.2)): - dependencies: - vue: 3.5.13(typescript@5.7.2) - sync-child-process@1.0.2: dependencies: sync-message-port: 1.1.3 @@ -12092,16 +11839,6 @@ snapshots: vm-browserify@1.1.2: {} - vue@3.5.13(typescript@5.7.2): - dependencies: - '@vue/compiler-dom': 3.5.13 - '@vue/compiler-sfc': 3.5.13 - '@vue/runtime-dom': 3.5.13 - '@vue/server-renderer': 3.5.13(vue@3.5.13(typescript@5.7.2)) - '@vue/shared': 3.5.13 - optionalDependencies: - typescript: 5.7.2 - w3c-keyname@2.2.8: {} wcwidth@1.0.1: @@ -12214,8 +11951,6 @@ snapshots: mustache: 4.2.0 stacktracey: 2.1.8 - zimmerframe@1.1.2: {} - zod-to-json-schema@3.23.5(zod@3.23.8): dependencies: zod: 3.23.8 diff --git a/public/apple-touch-icon-precomposed.png b/public/apple-touch-icon-precomposed.png new file mode 100644 index 00000000..ef0af665 Binary files /dev/null and b/public/apple-touch-icon-precomposed.png differ diff --git a/public/apple-touch-icon.png b/public/apple-touch-icon.png new file mode 100644 index 00000000..ef0af665 Binary files /dev/null and b/public/apple-touch-icon.png differ