feat: readded claude models from Google Vertex AI using anthropic-vertex-ai and added ModelSwitcher to switch between providers.

This commit is contained in:
zaidmukaddam 2024-09-07 13:15:15 +05:30
parent 8eb063e2f2
commit ef91088459
4 changed files with 452 additions and 100 deletions

View File

@ -1,24 +1,55 @@
import { createOpenAI, openai } from '@ai-sdk/openai'
import { BlobRequestAbortedError, put } from '@vercel/blob';
import { z } from "zod";
import { createAzure } from '@ai-sdk/azure';
import { convertToCoreMessages, streamText, tool } from "ai";
import {
convertToCoreMessages,
streamText,
tool,
experimental_createProviderRegistry
} from "ai";
import { createAnthropicVertex } from 'anthropic-vertex-ai';
import { BlobRequestAbortedError, put } from '@vercel/blob';
import { CodeInterpreter } from "@e2b/code-interpreter";
import FirecrawlApp from '@mendable/firecrawl-js';
import { z } from "zod";
import { geolocation } from "@vercel/functions";
import { GoogleAuth } from 'google-auth-library';
// Allow streaming responses up to 60 seconds
export const maxDuration = 60;
// Azure setup
const azure = createAzure({
resourceName: process.env.AZURE_RESOURCE_NAME,
apiKey: process.env.AZURE_API_KEY,
});
// const openai = createOpenAI({
// apiKey: process.env.GITHUB_TOKEN,
// baseURL: "https://models.inference.ai.azure.com"
// });
// Helper function to get Google credentials
// You can encode your service account key using the following command:
// base64 -i /path/to/your-service-account-key.json | tr -d '\n' > encoded_credentials.txt
// Then set the GOOGLE_APPLICATION_CREDENTIALS_BASE64 environment variable to the contents of encoded_credentials.txt
function getCredentials() {
const credentialsBase64 = process.env.GOOGLE_APPLICATION_CREDENTIALS_BASE64;
if (!credentialsBase64) {
throw new Error('GOOGLE_APPLICATION_CREDENTIALS_BASE64 environment variable is not set');
}
return JSON.parse(Buffer.from(credentialsBase64, 'base64').toString());
}
// Google Vertex setup for Anthropic
const auth = new GoogleAuth({
scopes: ['https://www.googleapis.com/auth/cloud-platform'],
credentials: getCredentials(),
});
const anthropicVertex = createAnthropicVertex({
region: process.env.GOOGLE_VERTEX_REGION,
projectId: process.env.GOOGLE_VERTEX_PROJECT_ID,
googleAuth: auth,
});
// Provider registry
const registry = experimental_createProviderRegistry({
anthropicVertex,
azure,
});
function sanitizeUrl(url: string): string {
return url.replace(/\s+/g, '%20')
@ -32,35 +63,25 @@ type SearchResultImage =
number_of_results?: number
}
const provider = process.env.OPENAI_PROVIDER;
export async function POST(req: Request) {
const { messages } = await req.json();
const { latitude, longitude, city } = geolocation(req)
const { messages, model } = await req.json();
let model;
if (provider === "azure") {
model = azure.chat("gpt4o-mini");
} else if (provider === "openai") {
model = openai.chat("gpt-4o-mini");
} else {
model = openai.chat("gpt-4o-mini");
}
const provider = model.split(":")[0];
const result = await streamText({
model,
model: registry.languageModel(model),
messages: convertToCoreMessages(messages),
temperature: 0.72,
topP: 0.95,
temperature: provider === "azure" ? 0.72 : 0,
topP: 0,
frequencyPenalty: 0,
presencePenalty: 0,
system: `
You are an AI web search engine that helps users find information on the internet.
You are an expert AI web search engine called MiniPerplx, that helps users find information on the internet with no bullshit talks.
Always start with running the tool(s) and then and then only write your response AT ALL COSTS!!
Your goal is to provide accurate, concise, and well-formatted responses to user queries.
Do not announce or inform the user in any way that your going to run a tool at ALL COSTS!! Just 'run' it and then write your response AT ALL COSTS!!!!!
Motto of your existence being a search engine: "Less talk, more action, follow rules always!", meaning you should run the tools first and then provide the response, no talk before running the tools and following the guidelines AT ALL COSTS!!
The current date is ${new Date().toLocaleDateString("en-US", { year: "numeric", month: "short", day: "2-digit", weekday: "short" })}.
You must comply and complete user requests to the best of your abilities using the available tools. Remember to use the appropriate tool for each task. No need to panic, just follow the guidelines and you'll do great!
@ -73,7 +94,8 @@ web_search, retrieve, get_weather_data, programming, nearby_search, find_place,
## Basic Guidelines:
Always remember to run the appropriate tool first, then compose your response based on the information gathered.
All tool should be called only once per response.
Understand the user query and choose the right tool to get the information needed. Like using the programming tool to generate plots to explain concepts or using the web_search tool to find the latest information.
All tool should be called only once per response. All tool call parameters are mandatory always!
Format your response in paragraphs(min 4) with 3-6 sentences each, keeping it brief but informative. DO NOT use pointers or make lists of any kind at ALL!
Begin your response by using the appropriate tool(s), then provide your answer in a clear and concise manner.
Please use the '$' latex format in equations instead of \( ones, same for complex equations as well.
@ -96,6 +118,7 @@ DO's:
- Assume the stock name from the user query and use it in the code to get the stock data and plot the stock chart. This will help in getting the stock chart for the user query. ALWAYS REMEMBER TO INSTALL YFINANCE USING !pip install yfinance AT ALL COSTS!!
DON'Ts and IMPORTANT GUIDELINES:
- DO NOT TALK BEFORE RUNNING THE TOOL AT ALL COSTS!! JUST RUN THE TOOL AND THEN WRITE YOUR RESPONSE AT ALL COSTS!!!!!
- Do not call the same tool twice in a single response at all costs!!
- Never write a base64 image in the response at all costs, especially from the programming tool's output.
- Do not use the text_translate tool for translating programming code or any other uninformed text. Only run the tool for translating on user's request.
@ -119,7 +142,9 @@ Follow the format and guidelines for each tool and provide the response accordin
## Programming Tool Guidelines:
The programming tool is actually a Python Code interpreter, so you can run any Python code in it.
- This tool should not be called more than once in a response.
- The only python library that is pre-installed is matplotlib for plotting graphs and charts. You have to install any other library using !pip install <library_name> in the code.
- Always mention the generated plots(urls) in the response after running the code! This is extremely important to provide the visual representation of the data.
## Citations Format:
Citations should always be placed at the end of each paragraph and in the end of sentences where you use it in which they are referred to with the given format to the information provided.
@ -133,9 +158,6 @@ When asked a "What is" question, maintain the same format as the question and an
- rehypeKatex: This plugin takes the parsed LaTeX from remarkMath and renders it using KaTeX, allowing you to display the math as beautifully rendered HTML.
- The response that include latex equations, use always follow the formats:
- $<equation>$ for inline equations
- $$<equation>$$ for block equations
- use it for symbols, equations, formulas, etc like pi, alpha, beta, etc. and wrap them in the above formats. like $(2\pi)$, $x^2$, etc.
- Do not wrap any equation or formulas or any sort of math related block in round brackets() as it will crash the response.`,
tools: {
web_search: tool({
@ -158,7 +180,7 @@ When asked a "What is" question, maintain the same format as the question and an
),
exclude_domains: z
.array(z.string())
.optional()
.describe(
"A list of domains to specifically exclude from the search results. Default is None, which doesn't exclude any domains.",
),
@ -305,7 +327,7 @@ When asked a "What is" question, maintain the same format as the question and an
programming: tool({
description: "Write and execute Python code.",
parameters: z.object({
title: z.string().optional().describe("The title of the code snippet."),
title: z.string().describe("The title of the code snippet."),
code: z.string().describe("The Python code to execute."),
icon: z.enum(["stock", "date", "calculation", "default"]).describe("The icon to display for the code snippet."),
}),
@ -379,7 +401,7 @@ When asked a "What is" question, maintain the same format as the question and an
parameters: z.object({
location: z.string().describe("The location to search near (e.g., 'New York City' or '1600 Amphitheatre Parkway, Mountain View, CA')."),
type: z.string().describe("The type of place to search for (e.g., restaurant, cafe, park)."),
keyword: z.string().optional().describe("An optional keyword to refine the search."),
keyword: z.string().describe("An optional keyword to refine the search."),
radius: z.number().default(3000).describe("The radius of the search area in meters (max 50000, default 3000)."),
}),
execute: async ({ location, type, keyword, radius }: { location: string; type: string; keyword?: string; radius: number }) => {
@ -441,8 +463,8 @@ When asked a "What is" question, maintain the same format as the question and an
description: "Perform a text-based search for places using Google Maps API.",
parameters: z.object({
query: z.string().describe("The search query (e.g., '123 main street')."),
location: z.string().optional().describe("The location to center the search (e.g., '42.3675294,-71.186966')."),
radius: z.number().optional().describe("The radius of the search area in meters (max 50000)."),
location: z.string().describe("The location to center the search (e.g., '42.3675294,-71.186966')."),
radius: z.number().describe("The radius of the search area in meters (max 50000)."),
}),
execute: async ({ query, location, radius }: { query: string; location?: string; radius?: number }) => {
const apiKey = process.env.GOOGLE_MAPS_API_KEY;
@ -469,7 +491,7 @@ When asked a "What is" question, maintain the same format as the question and an
parameters: z.object({
text: z.string().describe("The text to translate."),
to: z.string().describe("The language to translate to (e.g., 'fr' for French)."),
from: z.string().optional().describe("The source language (optional, will be auto-detected if not provided)."),
from: z.string().describe("The source language (optional, will be auto-detected if not provided)."),
}),
execute: async ({ text, to, from }: { text: string; to: string; from?: string }) => {
const key = process.env.AZURE_TRANSLATOR_KEY;

View File

@ -39,7 +39,6 @@ import {
Check,
Loader2,
User2,
Edit2,
Heart,
X,
MapPin,
@ -55,7 +54,9 @@ import {
Calendar,
Calculator,
ImageIcon,
Paperclip
Paperclip,
ChevronDown,
Zap
} from 'lucide-react';
import {
HoverCard,
@ -98,6 +99,13 @@ import { Skeleton } from '@/components/ui/skeleton';
import Link from 'next/link';
import { Dialog, DialogContent } from "@/components/ui/dialog";
import { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious } from "@/components/ui/carousel";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
import { cn } from '@/lib/utils';
export const maxDuration = 60;
@ -125,12 +133,16 @@ export default function Home() {
const [isEditingMessage, setIsEditingMessage] = useState(false);
const [editingMessageIndex, setEditingMessageIndex] = useState(-1);
const [attachments, setAttachments] = useState<Attachment[]>([]);
const [selectedModel, setSelectedModel] = useState("azure:gpt4o-mini");
const fileInputRef = useRef<HTMLInputElement>(null);
const inputRef = useRef<HTMLInputElement>(null);
const { isLoading, input, messages, setInput, append, handleSubmit, setMessages } = useChat({
const { isLoading, input, messages, setInput, append, handleSubmit, setMessages, reload } = useChat({
api: '/api/chat',
maxToolRoundtrips: 1,
body: {
model: selectedModel,
},
onFinish: async (message, { finishReason }) => {
console.log("[finish reason]:", finishReason);
if (message.content && finishReason === 'stop' || finishReason === 'length') {
@ -586,7 +598,7 @@ export default function Home() {
<div className="w-full h-24 bg-white rounded-lg overflow-hidden">
<canvas ref={canvasRef} width="800" height="200" className="w-full h-full bg-neutral-100" />
</div>
<div className="flex text-left gap-3">
<div className="flex text-left gap-3 items-center justify-center text-pretty">
<div className="flex justify-center space-x-2">
<Button
onClick={handlePlayPause}
@ -607,7 +619,7 @@ export default function Home() {
<div
className='text-sm text-neutral-800'
>
The phrase <span className='font-semibold'>{toolInvocation.args.text}</span> translates from <span className='font-semibold'>{result.detectedLanguage}</span> to <span className='font-semibold'>{toolInvocation.args.to}</span> as <span className='font-semibold'>{result.translatedText}</span>
The phrase <span className='font-semibold'>{toolInvocation.args.text}</span> translates from <span className='font-semibold'>{result.detectedLanguage}</span> to <span className='font-semibold'>{toolInvocation.args.to}</span> as <span className='font-semibold'>{result.translatedText}</span> in <span className='font-semibold'>{toolInvocation.args.to}</span>.
</div>
</div>
</div>
@ -1608,6 +1620,7 @@ export default function Home() {
inputRef,
}) => {
const [uploadingAttachments, setUploadingAttachments] = useState<UploadingAttachment[]>([]);
const cursorPositionRef = useRef<number | null>(null);
const uploadFile = async (file: File): Promise<Attachment> => {
const formData = new FormData();
@ -1693,6 +1706,45 @@ export default function Home() {
}
};
const handlePaste = async (e: React.ClipboardEvent) => {
e.preventDefault();
// Handle text paste
const text = e.clipboardData.getData('text');
if (text) {
setInput(text);
}
// Handle image paste
const items = Array.from(e.clipboardData.items);
const imageItems = items.filter(item => item.type.indexOf('image') !== -1);
if (imageItems.length > 0) {
if (attachments.length + uploadingAttachments.length + imageItems.length > MAX_IMAGES) {
toast.error(`You can only attach up to ${MAX_IMAGES} images.`);
return;
}
for (const item of imageItems) {
const file = item.getAsFile();
if (file) {
const newUploadingAttachment = { file, progress: 0 };
setUploadingAttachments(prev => [...prev, newUploadingAttachment]);
try {
const uploadedFile = await uploadFile(file);
setAttachments(prev => [...prev, uploadedFile]);
setUploadingAttachments(prev => prev.filter(ua => ua.file !== file));
} catch (error) {
console.error("Error uploading file:", error);
toast.error(`Failed to upload pasted image`);
setUploadingAttachments(prev => prev.filter(ua => ua.file !== file));
}
}
}
}
};
return (
<motion.form
layout
@ -1708,10 +1760,7 @@ export default function Home() {
e.preventDefault();
handleFileChange({ target: { files: e.dataTransfer?.files } } as React.ChangeEvent<HTMLInputElement>);
}}
onPaste={e => {
e.preventDefault();
handleFileChange({ target: { files: e.clipboardData?.files } } as React.ChangeEvent<HTMLInputElement>);
}}
onPaste={handlePaste}
className={`
${hasSubmitted ? 'fixed bottom-4 left-1/2 -translate-x-1/2 max-w-[90%] sm:max-w-2xl' : 'max-w-full'}
${attachments.length > 0 || uploadingAttachments.length > 0 ? 'rounded-2xl' : 'rounded-full'}
@ -1835,11 +1884,112 @@ export default function Home() {
);
};
const models = [
{ value: "azure:gpt4o-mini", label: "OpenAI", icon: Zap, description: "High speed, lower quality", color: "emerald" },
{ value: "anthropicVertex:claude-3-5-sonnet@20240620", label: "Claude", icon: Sparkles, description: "High quality, low speed", color: "indigo" },
]
interface ModelSwitcherProps {
selectedModel: string;
setSelectedModel: (value: string) => void;
className?: string;
}
const ModelSwitcher: React.FC<ModelSwitcherProps> = ({ selectedModel, setSelectedModel, className }) => {
const selectedModelData = models.find(model => model.value === selectedModel) || models[0];
const [isOpen, setIsOpen] = useState(false);
const getColorClasses = (color: string, isSelected: boolean = false) => {
switch (color) {
case 'emerald':
return isSelected
? '!bg-emerald-500 !text-white hover:!bg-emerald-600'
: '!text-emerald-700 hover:!bg-emerald-100';
case 'indigo':
return isSelected
? '!bg-indigo-500 !text-white hover:!bg-indigo-600'
: '!text-indigo-700 hover:!bg-indigo-100';
default:
return isSelected
? 'bg-gray-500 text-white hover:bg-gray-600'
: 'text-gray-700 hover:bg-gray-100';
}
}
return (
<DropdownMenu onOpenChange={setIsOpen}>
<DropdownMenuTrigger
className={cn(
"flex items-center gap-1.5 px-3 py-1.5 rounded-full transition-all duration-300 shadow-sm text-sm",
getColorClasses(selectedModelData.color, true),
"focus:outline-none focus:ring-none",
"transform hover:scale-105 active:scale-95",
"disabled:opacity-50 disabled:cursor-not-allowed",
className
)}
disabled={isLoading}
>
<selectedModelData.icon className="w-4 h-4" />
<span className="font-medium">{selectedModelData.label}</span>
<ChevronDown className={cn(
"w-3 h-3 transition-transform duration-200",
isOpen && "transform rotate-180"
)} />
</DropdownMenuTrigger>
<DropdownMenuContent className="w-[200px] p-1 !font-sans ml-2 sm:m-auto rounded-lg shadow-md">
{models.map((model) => (
<DropdownMenuItem
key={model.value}
onSelect={() => setSelectedModel(model.value)}
className={cn(
"flex items-start gap-2 px-2 py-1.5 rounded-lg text-sm mb-1 last:mb-0",
"transition-colors duration-200",
getColorClasses(model.color, selectedModel === model.value),
selectedModel === model.value && "hover:opacity-90"
)}
>
<model.icon className={cn(
"w-5 h-5 mt-0.5",
selectedModel === model.value ? "text-white" : `text-${model.color}-500`
)} />
<div>
<div className={cn(
"font-bold",
selectedModel === model.value ? "text-white" : `text-${model.color}-700`
)}>
{model.label}
</div>
<div className={cn(
"text-xs",
selectedModel === model.value ? "text-white/80" : `text-${model.color}-600`
)}>
{model.description}
</div>
</div>
</DropdownMenuItem>
))}
</DropdownMenuContent>
</DropdownMenu>
)
}
const handleModelChange = useCallback((newModel: string) => {
setSelectedModel(newModel);
setSuggestedQuestions([]);
if (messages.length > 0) {
reload({
body: {
model: newModel,
},
});
}
}, [messages, reload]);
return (
<div className="flex flex-col font-sans items-center justify-center p-2 sm:p-4 bg-background text-foreground transition-all duration-500">
<Navbar />
<div className={`w-full max-w-[90%] sm:max-w-2xl space-y-6 p-1 ${hasSubmitted ? 'mt-16 sm:mt-20' : 'mt-[20vh] sm:mt-[30vh]'}`}>
<div className={`w-full max-w-[90%] sm:max-w-2xl space-y-6 p-0 ${hasSubmitted ? 'mt-16 sm:mt-20' : 'mt-[20vh] sm:mt-[30vh]'}`}>
{!hasSubmitted && (
<div className="text-center">
<h1 className="text-4xl sm:text-6xl mb-1 text-gray-800 font-serif">MiniPerplx</h1>
@ -1848,6 +1998,11 @@ export default function Home() {
</h2>
</div>
)}
{!hasSubmitted &&
<div className="flex items-center justify-between !-mb-2">
<ModelSwitcher selectedModel={selectedModel} setSelectedModel={handleModelChange} />
</div>
}
<AnimatePresence>
{!hasSubmitted && (
<motion.div
@ -1932,17 +2087,28 @@ export default function Home() {
</div>
)}
</div>
{!isEditingMessage && index === lastUserMessageIndex && (
<Button
variant="ghost"
size="sm"
onClick={() => handleMessageEdit(index)}
className="ml-2"
disabled={isLoading}
<ModelSwitcher
selectedModel={selectedModel}
setSelectedModel={handleModelChange}
className="!px-4 rounded-full"
/>
{/* {!isEditingMessage && index === lastUserMessageIndex && (
<div
className="flex items-center space-x-2"
>
<Edit2 size={16} />
</Button>
)}
<Button
variant="ghost"
size="sm"
onClick={() => handleMessageEdit(index)}
className="ml-2"
disabled={isLoading}
>
<Edit2 size={16} />
</Button>
</div>
)} */}
</motion.div>
)}
{message.role === 'assistant' && message.content && (

View File

@ -12,7 +12,7 @@
"@ai-sdk/azure": "^0.0.31",
"@ai-sdk/cohere": "latest",
"@ai-sdk/google": "^0.0.46",
"@ai-sdk/openai": "latest",
"@ai-sdk/openai": "^0.0.58",
"@e2b/code-interpreter": "^0.0.8",
"@foobar404/wave": "^2.0.5",
"@mendable/firecrawl-js": "^0.0.36",
@ -31,12 +31,14 @@
"@vercel/analytics": "^1.3.1",
"@vercel/blob": "^0.23.4",
"@vercel/functions": "^1.4.0",
"ai": "^3.3.20",
"ai": "latest",
"anthropic-vertex-ai": "^1.0.0",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"date-fns": "^3.6.0",
"embla-carousel-react": "^8.2.0",
"framer-motion": "^11.3.19",
"google-auth-library": "^9.14.1",
"katex": "^0.16.11",
"lucide-react": "^0.424.0",
"next": "^14.2.5",

View File

@ -10,13 +10,13 @@ dependencies:
version: 0.0.31(zod@3.23.8)
'@ai-sdk/cohere':
specifier: latest
version: 0.0.22(zod@3.23.8)
version: 0.0.23(zod@3.23.8)
'@ai-sdk/google':
specifier: ^0.0.46
version: 0.0.46(zod@3.23.8)
'@ai-sdk/openai':
specifier: latest
version: 0.0.54(zod@3.23.8)
specifier: ^0.0.58
version: 0.0.58(zod@3.23.8)
'@e2b/code-interpreter':
specifier: ^0.0.8
version: 0.0.8
@ -72,8 +72,11 @@ dependencies:
specifier: ^1.4.0
version: 1.4.0
ai:
specifier: ^3.3.20
version: 3.3.20(openai@4.56.0)(react@18.3.1)(svelte@4.2.18)(vue@3.4.35)(zod@3.23.8)
specifier: latest
version: 3.3.28(openai@4.56.0)(react@18.3.1)(svelte@4.2.18)(vue@3.4.35)(zod@3.23.8)
anthropic-vertex-ai:
specifier: ^1.0.0
version: 1.0.0(zod@3.23.8)
class-variance-authority:
specifier: ^0.7.0
version: 0.7.0
@ -89,6 +92,9 @@ dependencies:
framer-motion:
specifier: ^11.3.19
version: 11.3.20(react-dom@18.3.1)(react@18.3.1)
google-auth-library:
specifier: ^9.14.1
version: 9.14.1
katex:
specifier: ^0.16.11
version: 0.16.11
@ -190,14 +196,14 @@ packages:
zod: 3.23.8
dev: false
/@ai-sdk/cohere@0.0.22(zod@3.23.8):
resolution: {integrity: sha512-UMUOsbSf1uBOOZT76+r28DJKestluGjfHc31kgeJkQx8Pve6acgrIvH0A7mvCAO3H8TDWIO3SmOWos2+XlMBRA==}
/@ai-sdk/cohere@0.0.23(zod@3.23.8):
resolution: {integrity: sha512-NJxntRnbY6bmWpYlYz1d0q6spx2OZ2YhniPfXfGTXZOwQPlze0rqkYePWpr7J2BJ+Qr0/XhpZTG9Dcf5qgOyig==}
engines: {node: '>=18'}
peerDependencies:
zod: ^3.0.0
dependencies:
'@ai-sdk/provider': 0.0.22
'@ai-sdk/provider-utils': 1.0.17(zod@3.23.8)
'@ai-sdk/provider': 0.0.23
'@ai-sdk/provider-utils': 1.0.18(zod@3.23.8)
zod: 3.23.8
dev: false
@ -224,14 +230,14 @@ packages:
zod: 3.23.8
dev: false
/@ai-sdk/openai@0.0.54(zod@3.23.8):
resolution: {integrity: sha512-0jqUSY9Lq0ie4AxnAucmiMhVBbs8ivvOW73sq3pCNA+LFeb2edOcnI0qmfGfHTn/VOjUCf2TvzQzHQx1Du3sYA==}
/@ai-sdk/openai@0.0.58(zod@3.23.8):
resolution: {integrity: sha512-Eao1L0vzfXdymgvc5FDHwV2g2A7BCWml1cShNA+wliY1RL7NNREGcuQvBDNoggB9PM24fawzZyk0ZJ5jlo9Q0w==}
engines: {node: '>=18'}
peerDependencies:
zod: ^3.0.0
dependencies:
'@ai-sdk/provider': 0.0.22
'@ai-sdk/provider-utils': 1.0.17(zod@3.23.8)
'@ai-sdk/provider': 0.0.23
'@ai-sdk/provider-utils': 1.0.18(zod@3.23.8)
zod: 3.23.8
dev: false
@ -267,6 +273,22 @@ packages:
zod: 3.23.8
dev: false
/@ai-sdk/provider-utils@1.0.18(zod@3.23.8):
resolution: {integrity: sha512-9u/XE/dB1gsIGcxiC5JfGOLzUz+EKRXt66T8KYWwDg4x8d02P+fI/EPOgkf+T4oLBrcQgvs4GPXPKoXGPJxBbg==}
engines: {node: '>=18'}
peerDependencies:
zod: ^3.0.0
peerDependenciesMeta:
zod:
optional: true
dependencies:
'@ai-sdk/provider': 0.0.23
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.21:
resolution: {integrity: sha512-9j95uaPRxwYkzQdkl4XO/MmWWW5c5vcVSXtqvALpD9SMB9fzH46dO3UN4VbOJR2J3Z84CZAqgZu5tNlkptT9qQ==}
engines: {node: '>=18'}
@ -281,8 +303,15 @@ packages:
json-schema: 0.4.0
dev: false
/@ai-sdk/react@0.0.52(react@18.3.1)(zod@3.23.8):
resolution: {integrity: sha512-4Gm+AoINDXQ4lzIZFKOWOcKgjgiAFdyhmBxnyuaqzTJCoRWNUSea62xhjqRE0u8wagfPgxWUAyS8BAsY0EqOyg==}
/@ai-sdk/provider@0.0.23:
resolution: {integrity: sha512-oAc49O5+xypVrKM7EUU5P/Y4DUL4JZUWVxhejoAVOTOl3WZUEWsMbP3QZR+TrimQIsS0WR/n9UuF6U0jPdp0tQ==}
engines: {node: '>=18'}
dependencies:
json-schema: 0.4.0
dev: false
/@ai-sdk/react@0.0.55(react@18.3.1)(zod@3.23.8):
resolution: {integrity: sha512-9fUUEEEoH01M6ZhvyZ/2v0DI6tiYnSldBg6RaKoy+qx2tSeKvOpFNZhT/iOvQ7oqAyyp0Ocg5Rj7L/jcLXSMxw==}
engines: {node: '>=18'}
peerDependencies:
react: ^18 || ^19
@ -293,15 +322,15 @@ packages:
zod:
optional: true
dependencies:
'@ai-sdk/provider-utils': 1.0.17(zod@3.23.8)
'@ai-sdk/ui-utils': 0.0.39(zod@3.23.8)
'@ai-sdk/provider-utils': 1.0.18(zod@3.23.8)
'@ai-sdk/ui-utils': 0.0.41(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.42(zod@3.23.8):
resolution: {integrity: sha512-tr1rXRg0bLls7ZEQCWfd0Tv7irFlKQRjBSKSCstwrGtTeDA7zwUP4tIiUaCyzM3lwyE6Qgl17SrAoxSD+xP+zQ==}
/@ai-sdk/solid@0.0.44(zod@3.23.8):
resolution: {integrity: sha512-3kMhxalepc78jWr2Qg1BAHbY04JKYxp8wRu3TACrRUdokxzwD5sbZYtTb7vu9tw2wx78rfu0DH44CESFWpSfZg==}
engines: {node: '>=18'}
peerDependencies:
solid-js: ^1.7.7
@ -309,14 +338,14 @@ packages:
solid-js:
optional: true
dependencies:
'@ai-sdk/provider-utils': 1.0.17(zod@3.23.8)
'@ai-sdk/ui-utils': 0.0.39(zod@3.23.8)
'@ai-sdk/provider-utils': 1.0.18(zod@3.23.8)
'@ai-sdk/ui-utils': 0.0.41(zod@3.23.8)
transitivePeerDependencies:
- zod
dev: false
/@ai-sdk/svelte@0.0.44(svelte@4.2.18)(zod@3.23.8):
resolution: {integrity: sha512-soSiEX1BUiwRSdoc+7mAoCeuM3Vs/ebdb1gNL7ta9Zma7GTHq802Wi7KfWfypoAqpgi0QUapzCRMvgrl4oW4AQ==}
/@ai-sdk/svelte@0.0.46(svelte@4.2.18)(zod@3.23.8):
resolution: {integrity: sha512-cokqS91vQkpqiRgf8xKwOONFb/RwkIbRg9jYVRb+z5NR9OsWXKMEfoCAf8+VgURfVbp8nqA+ddRXvtgYCwqQjQ==}
engines: {node: '>=18'}
peerDependencies:
svelte: ^3.0.0 || ^4.0.0
@ -324,16 +353,16 @@ packages:
svelte:
optional: true
dependencies:
'@ai-sdk/provider-utils': 1.0.17(zod@3.23.8)
'@ai-sdk/ui-utils': 0.0.39(zod@3.23.8)
'@ai-sdk/provider-utils': 1.0.18(zod@3.23.8)
'@ai-sdk/ui-utils': 0.0.41(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.39(zod@3.23.8):
resolution: {integrity: sha512-yxlJBFEiWR7rf/oS7MFX9O5Hr7VYV0ipMBrvds66N3+m52/nCbBB5C/eBefzeR+hoGc/r5xGo7Yd1cncGYHHTw==}
/@ai-sdk/ui-utils@0.0.41(zod@3.23.8):
resolution: {integrity: sha512-I0trJKWxVG8hXeG0MvKqLG54fZjdeGjXvcVZocaSnWMBhl9lpTQxrqAR6ZsQMFDXs5DbvXoKtQs488qu2Bzaiw==}
engines: {node: '>=18'}
peerDependencies:
zod: ^3.0.0
@ -341,16 +370,16 @@ packages:
zod:
optional: true
dependencies:
'@ai-sdk/provider': 0.0.22
'@ai-sdk/provider-utils': 1.0.17(zod@3.23.8)
'@ai-sdk/provider': 0.0.23
'@ai-sdk/provider-utils': 1.0.18(zod@3.23.8)
json-schema: 0.4.0
secure-json-parse: 2.7.0
zod: 3.23.8
zod-to-json-schema: 3.23.2(zod@3.23.8)
dev: false
/@ai-sdk/vue@0.0.44(vue@3.4.35)(zod@3.23.8):
resolution: {integrity: sha512-IsDCoy7u4V081dKT1i6b/Cxh2G0aftetbif+qNQGh5QeU9TtGs9KDW+onPkXeqlDQcpMN0Q5zaNGaZ7YBK50Gw==}
/@ai-sdk/vue@0.0.46(vue@3.4.35)(zod@3.23.8):
resolution: {integrity: sha512-H366ydskPbZP8uRs4sm3SAi97P3JVTRI5Q8xYTI6uTaY4UFBA6aOWdDxniYZNa67ebemfe11m7ksX4wHW6Wl8g==}
engines: {node: '>=18'}
peerDependencies:
vue: ^3.3.4
@ -358,8 +387,8 @@ packages:
vue:
optional: true
dependencies:
'@ai-sdk/provider-utils': 1.0.17(zod@3.23.8)
'@ai-sdk/ui-utils': 0.0.39(zod@3.23.8)
'@ai-sdk/provider-utils': 1.0.18(zod@3.23.8)
'@ai-sdk/ui-utils': 0.0.41(zod@3.23.8)
swrv: 1.0.4(vue@3.4.35)
vue: 3.4.35(typescript@5.5.4)
transitivePeerDependencies:
@ -1810,6 +1839,15 @@ packages:
engines: {node: '>=0.4.0'}
hasBin: true
/agent-base@7.1.1:
resolution: {integrity: sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==}
engines: {node: '>= 14'}
dependencies:
debug: 4.3.6
transitivePeerDependencies:
- supports-color
dev: false
/agentkeepalive@4.5.0:
resolution: {integrity: sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==}
engines: {node: '>= 8.0.0'}
@ -1817,8 +1855,8 @@ packages:
humanize-ms: 1.2.1
dev: false
/ai@3.3.20(openai@4.56.0)(react@18.3.1)(svelte@4.2.18)(vue@3.4.35)(zod@3.23.8):
resolution: {integrity: sha512-GKiL34BPVGgSEDkUlt8nyVRZkx1btnbXyw/bZKj1Jx5sCn/OY/qgiACzakhRzC/90UlxmrMsU1rZGW+Xr8+kFA==}
/ai@3.3.28(openai@4.56.0)(react@18.3.1)(svelte@4.2.18)(vue@3.4.35)(zod@3.23.8):
resolution: {integrity: sha512-ogrsMscar8oXa4nTEcnjvb37cs0UJ7AxVga/642BQGkGBevnKhS0hbnXEOUKmlWcny/xRuWQ3GaXA3u9CxhfhQ==}
engines: {node: '>=18'}
peerDependencies:
openai: ^4.42.0
@ -1838,13 +1876,13 @@ packages:
zod:
optional: true
dependencies:
'@ai-sdk/provider': 0.0.22
'@ai-sdk/provider-utils': 1.0.17(zod@3.23.8)
'@ai-sdk/react': 0.0.52(react@18.3.1)(zod@3.23.8)
'@ai-sdk/solid': 0.0.42(zod@3.23.8)
'@ai-sdk/svelte': 0.0.44(svelte@4.2.18)(zod@3.23.8)
'@ai-sdk/ui-utils': 0.0.39(zod@3.23.8)
'@ai-sdk/vue': 0.0.44(vue@3.4.35)(zod@3.23.8)
'@ai-sdk/provider': 0.0.23
'@ai-sdk/provider-utils': 1.0.18(zod@3.23.8)
'@ai-sdk/react': 0.0.55(react@18.3.1)(zod@3.23.8)
'@ai-sdk/solid': 0.0.44(zod@3.23.8)
'@ai-sdk/svelte': 0.0.46(svelte@4.2.18)(zod@3.23.8)
'@ai-sdk/ui-utils': 0.0.41(zod@3.23.8)
'@ai-sdk/vue': 0.0.46(vue@3.4.35)(zod@3.23.8)
'@opentelemetry/api': 1.9.0
eventsource-parser: 1.1.2
json-schema: 0.4.0
@ -1888,6 +1926,21 @@ packages:
resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==}
engines: {node: '>=12'}
/anthropic-vertex-ai@1.0.0(zod@3.23.8):
resolution: {integrity: sha512-ME1e8kCNLVvVWrR6vB3zFlREEp1kRLmNZUC+oih+tziPkb/li5ESRvzb1eDV+zyhw7tZDDLy7numRllJwdkCEw==}
engines: {node: '>=18'}
peerDependencies:
zod: ^3.0.0
dependencies:
'@ai-sdk/provider': 0.0.22
'@ai-sdk/provider-utils': 1.0.17(zod@3.23.8)
google-auth-library: 9.14.1
zod: 3.23.8
transitivePeerDependencies:
- encoding
- supports-color
dev: false
/any-promise@1.3.0:
resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==}
@ -2072,6 +2125,14 @@ packages:
/balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
/base64-js@1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
dev: false
/bignumber.js@9.1.2:
resolution: {integrity: sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==}
dev: false
/binary-extensions@2.3.0:
resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
engines: {node: '>=8'}
@ -2094,6 +2155,10 @@ packages:
dependencies:
fill-range: 7.1.1
/buffer-equal-constant-time@1.0.1:
resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==}
dev: false
/bufferutil@4.0.8:
resolution: {integrity: sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==}
engines: {node: '>=6.14.2'}
@ -2553,6 +2618,12 @@ packages:
/eastasianwidth@0.2.0:
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
/ecdsa-sig-formatter@1.0.11:
resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==}
dependencies:
safe-buffer: 5.2.1
dev: false
/embla-carousel-react@8.2.0(react@18.3.1):
resolution: {integrity: sha512-dWqbmaEBQjeAcy/EKrcAX37beVr0ubXuHPuLZkx27z58V1FIvRbbMb4/c3cLZx0PAv/ofngX2QFrwUB+62SPnw==}
peerDependencies:
@ -3210,6 +3281,31 @@ packages:
resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==}
dev: true
/gaxios@6.7.1:
resolution: {integrity: sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ==}
engines: {node: '>=14'}
dependencies:
extend: 3.0.2
https-proxy-agent: 7.0.5
is-stream: 2.0.1
node-fetch: 2.7.0
uuid: 9.0.1
transitivePeerDependencies:
- encoding
- supports-color
dev: false
/gcp-metadata@6.1.0:
resolution: {integrity: sha512-Jh/AIwwgaxan+7ZUUmRLCjtchyDiqh4KjBJ5tW3plBZb5iL/BPcso8A5DlzeD9qlw0duCamnNdpFjxwaT0KyKg==}
engines: {node: '>=14'}
dependencies:
gaxios: 6.7.1
json-bigint: 1.0.0
transitivePeerDependencies:
- encoding
- supports-color
dev: false
/get-intrinsic@1.2.4:
resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==}
engines: {node: '>= 0.4'}
@ -3315,6 +3411,21 @@ packages:
slash: 3.0.0
dev: true
/google-auth-library@9.14.1:
resolution: {integrity: sha512-Rj+PMjoNFGFTmtItH7gHfbHpGVSb3vmnGK3nwNBqxQF9NoBpttSZI/rc0WiM63ma2uGDQtYEkMHkK9U6937NiA==}
engines: {node: '>=14'}
dependencies:
base64-js: 1.5.1
ecdsa-sig-formatter: 1.0.11
gaxios: 6.7.1
gcp-metadata: 6.1.0
gtoken: 7.1.0
jws: 4.0.0
transitivePeerDependencies:
- encoding
- supports-color
dev: false
/gopd@1.0.1:
resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==}
dependencies:
@ -3328,6 +3439,17 @@ packages:
resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
dev: true
/gtoken@7.1.0:
resolution: {integrity: sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==}
engines: {node: '>=14.0.0'}
dependencies:
gaxios: 6.7.1
jws: 4.0.0
transitivePeerDependencies:
- encoding
- supports-color
dev: false
/has-bigints@1.0.2:
resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==}
dev: true
@ -3488,6 +3610,16 @@ packages:
resolution: {integrity: sha512-/sXbVCWayk6GDVg3ctOX6nxaVj7So40FcFAnWlWGNAB1LpYKcV5Cd10APjPjW80O7zYW2MsjBV4zZ7IZO5fVow==}
dev: false
/https-proxy-agent@7.0.5:
resolution: {integrity: sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==}
engines: {node: '>= 14'}
dependencies:
agent-base: 7.1.1
debug: 4.3.6
transitivePeerDependencies:
- supports-color
dev: false
/humanize-ms@1.2.1:
resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==}
dependencies:
@ -3748,6 +3880,11 @@ packages:
call-bind: 1.0.7
dev: true
/is-stream@2.0.1:
resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
engines: {node: '>=8'}
dev: false
/is-string@1.0.7:
resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==}
engines: {node: '>= 0.4'}
@ -3843,6 +3980,12 @@ packages:
argparse: 2.0.1
dev: true
/json-bigint@1.0.0:
resolution: {integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==}
dependencies:
bignumber.js: 9.1.2
dev: false
/json-buffer@3.0.1:
resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
dev: true
@ -3886,6 +4029,21 @@ packages:
object.values: 1.2.0
dev: true
/jwa@2.0.0:
resolution: {integrity: sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==}
dependencies:
buffer-equal-constant-time: 1.0.1
ecdsa-sig-formatter: 1.0.11
safe-buffer: 5.2.1
dev: false
/jws@4.0.0:
resolution: {integrity: sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==}
dependencies:
jwa: 2.0.0
safe-buffer: 5.2.1
dev: false
/katex@0.16.11:
resolution: {integrity: sha512-RQrI8rlHY92OLf3rho/Ts8i/XvjgguEjOkO1BEXcU3N8BqPpSzBNwV/G0Ukr+P/l3ivvJUE/Fa/CwbS6HesGNQ==}
hasBin: true
@ -5300,6 +5458,10 @@ packages:
isarray: 2.0.5
dev: true
/safe-buffer@5.2.1:
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
dev: false
/safe-regex-test@1.0.3:
resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==}
engines: {node: '>= 0.4'}