feat: added programming tool

This commit is contained in:
zaidmukaddam 2024-08-12 22:14:50 +05:30
parent 1f945118c5
commit 2c731de3cb
8 changed files with 405 additions and 79 deletions

View File

@ -1,6 +1,7 @@
import { openai } from "@ai-sdk/openai";
import { anthropic } from '@ai-sdk/anthropic'
import { convertToCoreMessages, streamText, tool } from "ai";
import { CodeInterpreter } from '@e2b/code-interpreter'
import { z } from "zod";
import { geolocation } from '@vercel/functions'
@ -24,8 +25,12 @@ export async function POST(req: Request) {
messages: convertToCoreMessages(messages),
system:
"You are an AI web search engine that helps users find information on the internet." +
"Always start with running the tool(s) and then and then only write your response AT ALL COSTS!" +
"Never write a response without running the tool(s) first!\n\n" +
"Do not announce that your going to run a tool, just run it and then write your response AT ALL COSTS!!!!!." +
"Tool Usage Instructions:\n" +
"The user is located in " + city + " at latitude " + latitude + " and longitude " + longitude + "." +
"Use this geolocation data for weather tool." +
"Use this geolocation data for weather tool, when the user doesn't provide a specific location." +
"You use the 'web_search' tool to search for information on the internet." +
"Always call the 'web_search' tool to get the information, no need to do a chain of thought or say anything else, go straight to the point." +
"Once you have found the information, you provide the user with the information you found in brief like a news paper detail." +
@ -34,7 +39,9 @@ export async function POST(req: Request) {
"Do not start the responses with newline characters, always start with the first sentence." +
"When the user asks about a Stock, you should 'always' first gather news about it with web search tool, then show the chart and then write your response. Follow these steps in this order only!" +
"Never use the retrieve tool for general search. Always use it when the user provides an url! " +
"For weather related questions, use get_weather_data tool and write your response. No need to call any other tool. Put citation to OpenWeatherMaps API everytime." +
"For weather related questions, use get_weather_data tool and write your response. No need to call any other tool. Put citation to OpenWeatherMaps API everytime." +
"Use the 'programming' tool to execute Python code for cases like calculating, sorting, etc. that require computation. " +
"The environment is like a jupyter notebook so don't write or use print statements at all costs!, just the variables.\n\n" +
"The current date is: " +
new Date()
.toLocaleDateString("en-US", {
@ -44,8 +51,10 @@ export async function POST(req: Request) {
weekday: "short",
})
.replace(/(\w+), (\w+) (\d+), (\d+)/, "$4-$2-$3 ($1)") +
"." +
"Rules for the response:\n" +
"Never use the heading format in your response!." +
"Refrain from saying things like 'Certainly! I'll search for information about OpenAI GPT-4o mini using the web search tool.'",
"IMPORTANT!!!: Refrain from saying things like that mention that your going to perform a certain action, example: 'Certainly! I'll search for information about OpenAI GPT-4o mini using the web search tool.'",
tools: {
web_search: tool({
description: 'Search the web for information with the given query, max results and search depth.',
@ -54,7 +63,7 @@ export async function POST(req: Request) {
.describe('The search query to look up on the web.'),
maxResults: z.number()
.describe('The maximum number of results to return. Default to be used is 10.'),
searchDepth: // use basic | advanced
searchDepth:
z.enum(['basic', 'advanced'])
.describe('The search depth to use for the search. Default is basic.')
}),
@ -92,7 +101,7 @@ export async function POST(req: Request) {
}
}),
retrieve: tool({
description: 'Retrieve the information from the web search tool.',
description: 'Retrieve the information from a URL.',
parameters: z.object({
url: z.string().describe('The URL to retrieve the information from.')
}),
@ -159,11 +168,49 @@ export async function POST(req: Request) {
symbol: z.string().describe('The stock symbol to display the chart for.')
}),
}),
programming: tool({
description: 'Write and execute Python code.',
parameters: z.object({
code: z.string().describe('The Python code to execute.')
}),
execute: async ({ code }: { code: string }) => {
const sandbox = await CodeInterpreter.create()
const execution = await sandbox.notebook.execCell(code)
if (execution.results.length > 0) {
let message: string = '';
for (const result of execution.results) {
if (result.isMainResult) {
message += `${result.text}\n`
} else {
message += `${result.text}\n`
}
if (result.formats().length > 0) {
message += `It has following formats: ${result.formats()}\n`
}
}
return message
}
if (
execution.logs.stdout.length > 0 ||
execution.logs.stderr.length > 0
) {
let message = ''
if (execution.logs.stdout.length > 0) {
message += `${execution.logs.stdout.join('\n')}\n`
}
if (execution.logs.stderr.length > 0) {
message += `${execution.logs.stderr.join('\n')}\n`
}
return message
}
return 'There was no output of the execution.'
}
}),
},
onFinish: async (event) => {
console.log(event.text);
console.log("Called " + event.toolCalls?.map((toolCall) => toolCall.toolName));
}
});
return result.toAIStreamResponse();

View File

@ -6,6 +6,7 @@
:root {
--font-serif: "Instrument Serif", serif;
--font-sans: "Inter", sans-serif;
--font-mono: "IBM Plex Mono", monospace;
}
body {

View File

@ -1,24 +1,19 @@
import "./globals.css";
import { Metadata, Viewport } from "next";
import { Toaster } from "sonner";
import { Inter, Instrument_Serif } from 'next/font/google';
import { Inter, Instrument_Serif, IBM_Plex_Mono } from 'next/font/google';
import { Analytics } from "@vercel/analytics/react";
export const metadata: Metadata = {
metadataBase: new URL("https://miniperplx.vercel.app"),
metadataBase: new URL("https://mplx.za16.co"),
title: "MiniPerplx",
description: "MiniPerplx is a minimalistic AI-powered search engine that helps you find information on the internet.",
openGraph : {
url: "https://miniperplx.vercel.app",
url: "https://mplx.za16.co",
siteName: "MiniPerplx",
}
};
const inter = Inter({
weight: "variable",
subsets: ["latin"],
})
export const viewport: Viewport = {
width: "device-width",
initialScale: 1,
@ -27,6 +22,17 @@ export const viewport: Viewport = {
userScalable: false,
}
const inter = Inter({
weight: "variable",
subsets: ["latin"],
})
const plexMono = IBM_Plex_Mono({
weight: "400",
subsets: ["latin"],
variable: "--font-mono"
})
const instrumentSerif = Instrument_Serif({
weight: "400",
subsets: ["latin"],
@ -39,7 +45,7 @@ export default function RootLayout({
}>) {
return (
<html lang="en">
<body className={`${inter.className} ${instrumentSerif.className}`}>
<body className={`${inter.className} ${instrumentSerif.className} ${plexMono.className}`}>
<Toaster position="top-center" richColors />
{children}
<Analytics />

View File

@ -31,6 +31,10 @@ import {
Copy,
TrendingUp,
Cloud,
Code,
Check,
Loader2,
User2,
} from 'lucide-react';
import {
HoverCard,
@ -57,6 +61,13 @@ import {
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip"
import { Input } from '@/components/ui/input';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
@ -104,7 +115,7 @@ export default function Home() {
}
setIsAnimating(false);
},
onToolCall({ toolCall, }) {
onToolCall({ toolCall }) {
if (toolCall.toolName === 'stock_chart_ui') {
return 'Stock chart was shown to the user.';
}
@ -191,7 +202,7 @@ export default function Home() {
onSelect={() => onModelSelect(model.name)}
className={`flex items-start p-3 !font-sans rounded-md ${selectedModel === model.name ? 'bg-muted' : ''}`}
>
<model.icon className={`w-5 h-5 mr-3 mt-0.5 flex-shrink-0 ${model.name.includes('Quality') ? 'text-purple-500' : 'text-green-500'}`} />
<model.icon className={`w-5 h-5 mr-1 mt-0.5 flex-shrink-0 ${model.name.includes('Quality') ? 'text-purple-500' : 'text-green-500'}`} />
<div className="flex-grow">
<div className="font-semibold flex items-center justify-between">
{model.name}
@ -317,10 +328,8 @@ export default function Home() {
);
});
WeatherChart.displayName = 'WeatherChart';
const renderToolInvocation = (toolInvocation: ToolInvocation, index: number) => {
const args = JSON.parse(JSON.stringify(toolInvocation.args));
const result = 'result' in toolInvocation ? JSON.parse(JSON.stringify(toolInvocation.result)) : null;
@ -385,6 +394,75 @@ export default function Home() {
return <WeatherChart result={result} />;
}
if (toolInvocation.toolName === 'programming') {
return (
<Accordion type="single" collapsible className="w-full my-4">
<AccordionItem value="programming" className="border-none">
<AccordionTrigger className="hover:no-underline">
<div className="flex items-center justify-between w-full">
<div className="flex items-center gap-2 text-left">
<Code className="h-5 w-5 text-primary" />
<span className="font-semibold">Programming</span>
</div>
{result ? (
<Badge variant="secondary" className="ml-auto mr-2 rounded-full">
<Check className="h-3 w-3 mr-1" />
Run Complete
</Badge>
) : (
<Badge variant="secondary" className="ml-auto mr-2 rounded-full">
<Loader2 className="h-3 w-3 mr-1 animate-spin" />
Running
</Badge>
)}
</div>
</AccordionTrigger>
<AccordionContent className="pt-4 pb-2 space-y-4">
{args?.code && (
<div>
<h3 className="text-sm font-medium mb-2">Code</h3>
<pre className="bg-muted p-3 rounded-md overflow-x-auto text-sm">
<code className='font-mono'>{args.code}</code>
</pre>
</div>
)}
<div>
<h3 className="text-sm font-medium mb-2">Result</h3>
{result ? (
<pre className="bg-muted p-3 rounded-md overflow-x-auto text-sm">
<code>{result}</code>
</pre>
) : (
<div className="flex items-center justify-between w-full bg-muted p-3 rounded-md">
<div className="flex items-center gap-2">
<Loader2 className="h-5 w-5 text-muted-foreground animate-spin" />
<span className="text-muted-foreground text-sm">Executing code...</span>
</div>
<div className="flex space-x-1">
{[0, 1, 2].map((index) => (
<motion.div
key={index}
className="w-1.5 h-1.5 bg-muted-foreground rounded-full"
initial={{ opacity: 0.3 }}
animate={{ opacity: 1 }}
transition={{
repeat: Infinity,
duration: 0.8,
delay: index * 0.2,
repeatType: "reverse",
}}
/>
))}
</div>
</div>
)}
</div>
</AccordionContent>
</AccordionItem>
</Accordion>
);
}
return (
<div>
{!result ? (
@ -596,7 +674,7 @@ export default function Home() {
const exampleQueries = [
"Weather in Doha",
"Latest on Paris Olympics",
"Summary: https://openai.com/index/gpt-4o-system-card/",
"Count the number of r's in strawberry",
"OpenAI GPT-4o mini"
];
@ -724,18 +802,37 @@ export default function Home() {
onAnimationComplete={() => setIsAnimating(false)}
>
<div className="flex items-center space-x-2 mb-4">
<motion.p
<motion.div
initial={{ opacity: 0, scale: 0.8 }}
animate={{ opacity: 1, scale: 1 }}
transition={{ duration: 0.5, delay: 0.2 }}
>
<User2 className="w-6 h-6 text-primary flex-shrink-0" />
</motion.div>
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5, delay: 0.2 }}
className="text-2xl font-medium font-serif"
className="flex-grow min-w-0"
>
{lastSubmittedQuery}
</motion.p>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<p className="text-xl sm:text-2xl font-medium font-serif truncate">
{lastSubmittedQuery}
</p>
</TooltipTrigger>
<TooltipContent>
<p>{lastSubmittedQuery}</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</motion.div>
<motion.div
initial={{ opacity: 0, scale: 0.8 }}
animate={{ opacity: 1, scale: 1 }}
transition={{ duration: 0.5, delay: 0.4 }}
className="flex-shrink-0"
>
<ModelSelector
selectedModel={selectedModel}
@ -759,15 +856,13 @@ export default function Home() {
<h2 className="text-base font-semibold">Answer</h2>
</div>
<Button
variant="secondary"
variant="ghost"
size="sm"
className={`flex items-center gap-2 ${isLoading ? 'hidden' : ''}`}
onClick={() => {
copyToClipboard(message.content)
.then(() => {
toast.success("Copied to clipboard", {
description: "The answer has been copied to your clipboard.",
});
toast.success("Copied to clipboard");
})
.catch((error) => {
console.error('Failed to copy:', error);

30
components/ui/tooltip.tsx Normal file
View File

@ -0,0 +1,30 @@
"use client"
import * as React from "react"
import * as TooltipPrimitive from "@radix-ui/react-tooltip"
import { cn } from "@/lib/utils"
const TooltipProvider = TooltipPrimitive.Provider
const Tooltip = TooltipPrimitive.Root
const TooltipTrigger = TooltipPrimitive.Trigger
const TooltipContent = React.forwardRef<
React.ElementRef<typeof TooltipPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
>(({ className, sideOffset = 4, ...props }, ref) => (
<TooltipPrimitive.Content
ref={ref}
sideOffset={sideOffset}
className={cn(
"z-50 overflow-hidden rounded-md bg-primary px-3 py-1.5 text-xs text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className
)}
{...props}
/>
))
TooltipContent.displayName = TooltipPrimitive.Content.displayName
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }

View File

@ -11,6 +11,7 @@
"dependencies": {
"@ai-sdk/anthropic": "^0.0.37",
"@ai-sdk/openai": "^0.0.40",
"@e2b/code-interpreter": "^0.0.8",
"@radix-ui/react-accordion": "^1.2.0",
"@radix-ui/react-dialog": "^1.1.1",
"@radix-ui/react-dropdown-menu": "^2.1.1",
@ -18,6 +19,7 @@
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-scroll-area": "^1.1.0",
"@radix-ui/react-slot": "^1.1.0",
"@radix-ui/react-tooltip": "^1.1.2",
"@tailwindcss/typography": "^0.5.13",
"@vercel/analytics": "^1.3.1",
"@vercel/functions": "^1.4.0",

View File

@ -11,6 +11,9 @@ dependencies:
'@ai-sdk/openai':
specifier: ^0.0.40
version: 0.0.40(zod@3.23.8)
'@e2b/code-interpreter':
specifier: ^0.0.8
version: 0.0.8
'@radix-ui/react-accordion':
specifier: ^1.2.0
version: 1.2.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1)
@ -32,6 +35,9 @@ dependencies:
'@radix-ui/react-slot':
specifier: ^1.1.0
version: 1.1.0(@types/react@18.3.3)(react@18.3.1)
'@radix-ui/react-tooltip':
specifier: ^1.1.2
version: 1.1.2(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1)
'@tailwindcss/typography':
specifier: ^0.5.13
version: 0.5.13(tailwindcss@3.4.7)
@ -43,7 +49,7 @@ dependencies:
version: 1.4.0
ai:
specifier: latest
version: 3.3.5(react@18.3.1)(svelte@4.2.18)(vue@3.4.35)(zod@3.23.8)
version: 3.3.6(react@18.3.1)(svelte@4.2.18)(vue@3.4.35)(zod@3.23.8)
class-variance-authority:
specifier: ^0.7.0
version: 0.7.0
@ -140,6 +146,22 @@ packages:
zod: 3.23.8
dev: false
/@ai-sdk/provider-utils@1.0.10(zod@3.23.8):
resolution: {integrity: sha512-xciXF2PorLQMNdhYe+n9CafVkXZANHURsME85RXjtAoZSs631l2t8Blqwz2C/pHUb9bxLdMRRuIEB4PnHLnHvQ==}
engines: {node: '>=18'}
peerDependencies:
zod: ^3.0.0
peerDependenciesMeta:
zod:
optional: true
dependencies:
'@ai-sdk/provider': 0.0.18
eventsource-parser: 1.1.2
nanoid: 3.3.6
secure-json-parse: 2.7.0
zod: 3.23.8
dev: false
/@ai-sdk/provider-utils@1.0.5(zod@3.23.8):
resolution: {integrity: sha512-XfOawxk95X3S43arn2iQIFyWGMi0DTxsf9ETc6t7bh91RPWOOPYN1tsmS5MTKD33OGJeaDQ/gnVRzXUCRBrckQ==}
engines: {node: '>=18'}
@ -172,22 +194,6 @@ packages:
zod: 3.23.8
dev: false
/@ai-sdk/provider-utils@1.0.9(zod@3.23.8):
resolution: {integrity: sha512-yfdanjUiCJbtGoRGXrcrmXn0pTyDfRIeY6ozDG96D66f2wupZaZvAgKptUa3zDYXtUCQQvcNJ+tipBBfQD/UYA==}
engines: {node: '>=18'}
peerDependencies:
zod: ^3.0.0
peerDependenciesMeta:
zod:
optional: true
dependencies:
'@ai-sdk/provider': 0.0.17
eventsource-parser: 1.1.2
nanoid: 3.3.6
secure-json-parse: 2.7.0
zod: 3.23.8
dev: false
/@ai-sdk/provider@0.0.14:
resolution: {integrity: sha512-gaQ5Y033nro9iX1YUjEDFDRhmMcEiCk56LJdIUbX5ozEiCNCfpiBpEqrjSp/Gp5RzBS2W0BVxfG7UGW6Ezcrzg==}
engines: {node: '>=18'}
@ -202,15 +208,15 @@ packages:
json-schema: 0.4.0
dev: false
/@ai-sdk/provider@0.0.17:
resolution: {integrity: sha512-f9j+P5yYRkqKFHxvWae5FI0j6nqROPCoPnMkpc2hc2vC7vKjqzrxBJucD8rpSaUjqiBnY/QuRJ0QeV717Uz5tg==}
/@ai-sdk/provider@0.0.18:
resolution: {integrity: sha512-LF4aUAKDTKIHa2e7ozwRJDMhUC9cs7t224sUilG1HfyFWyyh+01oPZwMob/hj111SozZkvXIukN0BIa+sXS0mw==}
engines: {node: '>=18'}
dependencies:
json-schema: 0.4.0
dev: false
/@ai-sdk/react@0.0.41(react@18.3.1)(zod@3.23.8):
resolution: {integrity: sha512-T4M/73Ye/5dU8Ub4qnqPPhAX+KGMj4bhbRNESEuWv/NQPK2OLhAU+1mmLl2LkRwgP6qfFcILWaYssULuJ7ihcQ==}
/@ai-sdk/react@0.0.42(react@18.3.1)(zod@3.23.8):
resolution: {integrity: sha512-oiwXKLc5n7SwaTZWldMrpyJEWTgLh35NXuxQIGDGVHTIryxxMk9lgOQ+vQ8uri3WGMzGQQGRfwh8MTijJ8cN2A==}
engines: {node: '>=18'}
peerDependencies:
react: ^18 || ^19
@ -221,15 +227,15 @@ packages:
zod:
optional: true
dependencies:
'@ai-sdk/provider-utils': 1.0.9(zod@3.23.8)
'@ai-sdk/ui-utils': 0.0.29(zod@3.23.8)
'@ai-sdk/provider-utils': 1.0.10(zod@3.23.8)
'@ai-sdk/ui-utils': 0.0.30(zod@3.23.8)
react: 18.3.1
swr: 2.2.5(react@18.3.1)
zod: 3.23.8
dev: false
/@ai-sdk/solid@0.0.32(zod@3.23.8):
resolution: {integrity: sha512-cYtidoiI6V0gFpUfF5223CUGz6TZJiJdbYDZta985dnT9aGKSIg0rVl+7E6FLoPPqGSclJ+Omh/TAMvXXTknyw==}
/@ai-sdk/solid@0.0.33(zod@3.23.8):
resolution: {integrity: sha512-6AV4g6IrQ7bPcfQgwOjNMT50W2lljk/sgzJ3qx+Bt/lobvhA7khyW1RVYTnxx3OBdf4/qB1D2BAAbUrrm/na8A==}
engines: {node: '>=18'}
peerDependencies:
solid-js: ^1.7.7
@ -237,14 +243,14 @@ packages:
solid-js:
optional: true
dependencies:
'@ai-sdk/provider-utils': 1.0.9(zod@3.23.8)
'@ai-sdk/ui-utils': 0.0.29(zod@3.23.8)
'@ai-sdk/provider-utils': 1.0.10(zod@3.23.8)
'@ai-sdk/ui-utils': 0.0.30(zod@3.23.8)
transitivePeerDependencies:
- zod
dev: false
/@ai-sdk/svelte@0.0.34(svelte@4.2.18)(zod@3.23.8):
resolution: {integrity: sha512-9WlpChuCnVQgcqRuHIcDDFeswmaGUUzFddLqYTDo5bP/mmeWvFm5RD+fnJ6AiHrsALbrOnUusDwxXvW6ydTz2A==}
/@ai-sdk/svelte@0.0.35(svelte@4.2.18)(zod@3.23.8):
resolution: {integrity: sha512-vbDmvcu2MRZvvxoOtCUH8ydKSaugaQkhiBtZRp/U1YvSIuzR7xUkYSf0EQ173kWBWsaoPO9PFava0WxF7k1q4g==}
engines: {node: '>=18'}
peerDependencies:
svelte: ^3.0.0 || ^4.0.0
@ -252,16 +258,16 @@ packages:
svelte:
optional: true
dependencies:
'@ai-sdk/provider-utils': 1.0.9(zod@3.23.8)
'@ai-sdk/ui-utils': 0.0.29(zod@3.23.8)
'@ai-sdk/provider-utils': 1.0.10(zod@3.23.8)
'@ai-sdk/ui-utils': 0.0.30(zod@3.23.8)
sswr: 2.1.0(svelte@4.2.18)
svelte: 4.2.18
transitivePeerDependencies:
- zod
dev: false
/@ai-sdk/ui-utils@0.0.29(zod@3.23.8):
resolution: {integrity: sha512-1d+8ogA/xm8xiVdKQt2uJ5HDbkowMYUDS4a30kYkaGNXk7JHy65feEtDHQnnUZKqHdqAruyPB8sLNA75gi6OHQ==}
/@ai-sdk/ui-utils@0.0.30(zod@3.23.8):
resolution: {integrity: sha512-ifmYSQtSVdeY1XlOFirAdbgWVnSg5hYPhG8bEiNI9TvR1HFdMN/zZhxscjLyKXXAelf/ACYvUjwNQmCnWSurZQ==}
engines: {node: '>=18'}
peerDependencies:
zod: ^3.0.0
@ -269,14 +275,16 @@ packages:
zod:
optional: true
dependencies:
'@ai-sdk/provider': 0.0.17
'@ai-sdk/provider-utils': 1.0.9(zod@3.23.8)
'@ai-sdk/provider': 0.0.18
'@ai-sdk/provider-utils': 1.0.10(zod@3.23.8)
json-schema: 0.4.0
secure-json-parse: 2.7.0
zod: 3.23.8
zod-to-json-schema: 3.22.5(zod@3.23.8)
dev: false
/@ai-sdk/vue@0.0.33(vue@3.4.35)(zod@3.23.8):
resolution: {integrity: sha512-P+grVsbH/QoKiC/8Efc/bUdYpd8ySXXaeV8BAwp3Y2A6P745Kifw/J5MIirHBVSdZulcLcsMFIpnpm4Xc280IA==}
/@ai-sdk/vue@0.0.34(vue@3.4.35)(zod@3.23.8):
resolution: {integrity: sha512-Nbht63i4NJrau5Yrf6dH6paH2mj/5CSmHopjA0IRHdOTvh3lKe382oZP2hLnN/xa575r25as67l7P/j/iq8ULQ==}
engines: {node: '>=18'}
peerDependencies:
vue: ^3.3.4
@ -284,8 +292,8 @@ packages:
vue:
optional: true
dependencies:
'@ai-sdk/provider-utils': 1.0.9(zod@3.23.8)
'@ai-sdk/ui-utils': 0.0.29(zod@3.23.8)
'@ai-sdk/provider-utils': 1.0.10(zod@3.23.8)
'@ai-sdk/ui-utils': 0.0.30(zod@3.23.8)
swrv: 1.0.4(vue@3.4.35)
vue: 3.4.35(typescript@5.5.4)
transitivePeerDependencies:
@ -338,6 +346,18 @@ packages:
to-fast-properties: 2.0.0
dev: false
/@e2b/code-interpreter@0.0.8:
resolution: {integrity: sha512-cKDFY9js9l3MfL71x0IDvaz0mAhvHIurVFnimtFRXNzuV0TxhuFqsauKabet0TMOrcDF3H3trC7pct6mNgRYTA==}
engines: {node: '>=18'}
dependencies:
e2b: 0.16.2
isomorphic-ws: 5.0.0(ws@8.18.0)
ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@6.0.4)
transitivePeerDependencies:
- bufferutil
- utf-8-validate
dev: false
/@eslint-community/eslint-utils@4.4.0(eslint@8.57.0):
resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@ -1092,6 +1112,37 @@ packages:
react: 18.3.1
dev: false
/@radix-ui/react-tooltip@1.1.2(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1):
resolution: {integrity: sha512-9XRsLwe6Yb9B/tlnYCPVUd/TFS4J7HuOZW345DCeC6vKIxQGMZdx21RK4VoZauPD5frgkXTYVS5y90L+3YBn4w==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
dependencies:
'@radix-ui/primitive': 1.1.0
'@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.3)(react@18.3.1)
'@radix-ui/react-context': 1.1.0(@types/react@18.3.3)(react@18.3.1)
'@radix-ui/react-dismissable-layer': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1)
'@radix-ui/react-id': 1.1.0(@types/react@18.3.3)(react@18.3.1)
'@radix-ui/react-popper': 1.2.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1)
'@radix-ui/react-portal': 1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1)
'@radix-ui/react-presence': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1)
'@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1)
'@radix-ui/react-slot': 1.1.0(@types/react@18.3.3)(react@18.3.1)
'@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.3)(react@18.3.1)
'@radix-ui/react-visually-hidden': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1)
'@types/react': 18.3.3
'@types/react-dom': 18.3.0
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
dev: false
/@radix-ui/react-use-callback-ref@1.1.0(@types/react@18.3.3)(react@18.3.1):
resolution: {integrity: sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==}
peerDependencies:
@ -1174,6 +1225,26 @@ packages:
react: 18.3.1
dev: false
/@radix-ui/react-visually-hidden@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1):
resolution: {integrity: sha512-N8MDZqtgCgG5S3aV60INAB475osJousYpZ4cTJ2cFbMpdHS5Y6loLTH8LPtkj2QN0x93J30HT/M3qJXM0+lyeQ==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
dependencies:
'@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1)
'@types/react': 18.3.3
'@types/react-dom': 18.3.0
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
dev: false
/@radix-ui/rect@1.1.0:
resolution: {integrity: sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==}
dev: false
@ -1495,8 +1566,8 @@ packages:
engines: {node: '>=0.4.0'}
hasBin: true
/ai@3.3.5(react@18.3.1)(svelte@4.2.18)(vue@3.4.35)(zod@3.23.8):
resolution: {integrity: sha512-aIWnEVL0BN/dSsQGYKoKsV9CInnl7bdKUsXLLFRfiAFfBH1Vu/azMCVRNf1PIS+MCR4GTtjN4c1URgMthfivdg==}
/ai@3.3.6(react@18.3.1)(svelte@4.2.18)(vue@3.4.35)(zod@3.23.8):
resolution: {integrity: sha512-XrbjYyugNF0SlTEVAO8B7tlW6iW47+DYk1hkyGj0vwp93J0F19bdrtN6NbFJOzSHj/R4FGvGk0IPQz5A3Eq1IQ==}
engines: {node: '>=18'}
peerDependencies:
openai: ^4.42.0
@ -1516,13 +1587,13 @@ packages:
zod:
optional: true
dependencies:
'@ai-sdk/provider': 0.0.17
'@ai-sdk/provider-utils': 1.0.9(zod@3.23.8)
'@ai-sdk/react': 0.0.41(react@18.3.1)(zod@3.23.8)
'@ai-sdk/solid': 0.0.32(zod@3.23.8)
'@ai-sdk/svelte': 0.0.34(svelte@4.2.18)(zod@3.23.8)
'@ai-sdk/ui-utils': 0.0.29(zod@3.23.8)
'@ai-sdk/vue': 0.0.33(vue@3.4.35)(zod@3.23.8)
'@ai-sdk/provider': 0.0.18
'@ai-sdk/provider-utils': 1.0.10(zod@3.23.8)
'@ai-sdk/react': 0.0.42(react@18.3.1)(zod@3.23.8)
'@ai-sdk/solid': 0.0.33(zod@3.23.8)
'@ai-sdk/svelte': 0.0.35(svelte@4.2.18)(zod@3.23.8)
'@ai-sdk/ui-utils': 0.0.30(zod@3.23.8)
'@ai-sdk/vue': 0.0.34(vue@3.4.35)(zod@3.23.8)
'@opentelemetry/api': 1.9.0
eventsource-parser: 1.1.2
json-schema: 0.4.0
@ -1751,6 +1822,14 @@ packages:
dependencies:
fill-range: 7.1.1
/bufferutil@4.0.8:
resolution: {integrity: sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==}
engines: {node: '>=6.14.2'}
requiresBuild: true
dependencies:
node-gyp-build: 4.8.1
dev: false
/busboy@1.6.0:
resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==}
engines: {node: '>=10.16.0'}
@ -2141,6 +2220,21 @@ packages:
csstype: 3.1.3
dev: false
/e2b@0.16.2:
resolution: {integrity: sha512-xKmVK4ipgVQPJ/uyyrfH9LnaawERRWt8U2UZhdhGfzdL/QU/OpBjuhoIbFCv1Uy6qXV4nIiJ6Nw4MBC4HmXf1g==}
engines: {node: '>=18'}
dependencies:
isomorphic-ws: 5.0.0(ws@8.18.0)
normalize-path: 3.0.0
openapi-typescript-fetch: 1.1.3
path-browserify: 1.0.1
platform: 1.3.6
ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@6.0.4)
optionalDependencies:
bufferutil: 4.0.8
utf-8-validate: 6.0.4
dev: false
/eastasianwidth@0.2.0:
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
@ -3192,6 +3286,14 @@ packages:
/isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
/isomorphic-ws@5.0.0(ws@8.18.0):
resolution: {integrity: sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==}
peerDependencies:
ws: '*'
dependencies:
ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@6.0.4)
dev: false
/iterator.prototype@1.1.2:
resolution: {integrity: sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==}
dependencies:
@ -3911,6 +4013,11 @@ packages:
- babel-plugin-macros
dev: false
/node-gyp-build@4.8.1:
resolution: {integrity: sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==}
hasBin: true
dev: false
/normalize-path@3.0.0:
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
engines: {node: '>=0.10.0'}
@ -3994,6 +4101,11 @@ packages:
wrappy: 1.0.2
dev: true
/openapi-typescript-fetch@1.1.3:
resolution: {integrity: sha512-smLZPck4OkKMNExcw8jMgrMOGgVGx2N/s6DbKL2ftNl77g5HfoGpZGFy79RBzU/EkaO0OZpwBnslfdBfh7ZcWg==}
engines: {node: '>= 12.0.0', npm: '>= 7.0.0'}
dev: false
/optionator@0.9.4:
resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
engines: {node: '>= 0.8.0'}
@ -4043,6 +4155,10 @@ packages:
is-hexadecimal: 2.0.1
dev: false
/path-browserify@1.0.1:
resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==}
dev: false
/path-exists@4.0.0:
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
engines: {node: '>=8'}
@ -4095,6 +4211,10 @@ packages:
resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==}
engines: {node: '>= 6'}
/platform@1.3.6:
resolution: {integrity: sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==}
dev: false
/possible-typed-array-names@1.0.0:
resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==}
engines: {node: '>= 0.4'}
@ -5081,6 +5201,14 @@ packages:
react: 18.3.1
dev: false
/utf-8-validate@6.0.4:
resolution: {integrity: sha512-xu9GQDeFp+eZ6LnCywXN/zBancWvOpUMzgjLPSjy4BRHSmTelvn2E0DG0o1sTiw5hkCKBHo8rwSKncfRfv2EEQ==}
engines: {node: '>=6.14.2'}
requiresBuild: true
dependencies:
node-gyp-build: 4.8.1
dev: false
/util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
@ -5215,6 +5343,22 @@ packages:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
dev: true
/ws@8.18.0(bufferutil@4.0.8)(utf-8-validate@6.0.4):
resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==}
engines: {node: '>=10.0.0'}
peerDependencies:
bufferutil: ^4.0.1
utf-8-validate: '>=5.0.2'
peerDependenciesMeta:
bufferutil:
optional: true
utf-8-validate:
optional: true
dependencies:
bufferutil: 4.0.8
utf-8-validate: 6.0.4
dev: false
/yaml@2.5.0:
resolution: {integrity: sha512-2wWLbGbYDiSqqIKoPjar3MPgB94ErzCtrNE1FdqGuaO0pi2JGjmE8aW8TDZwzU7vuxcGRdL/4gPQwQ7hD5AMSw==}
engines: {node: '>= 14'}

View File

@ -21,6 +21,7 @@ const config = {
fontFamily: {
sans: ['Inter', 'sans-serif'],
serif: ['var(--font-serif)', 'serif'],
mono: ['var(--font-mono)', 'monospace'],
},
colors: {
border: "hsl(var(--border))",