feat: added edit option, shifted completely to anthropic models, and added more context in Readme

This commit is contained in:
zaidmukaddam 2024-08-15 18:38:22 +05:30
parent 916588acf4
commit e471371545
6 changed files with 148 additions and 118 deletions

View File

@ -1,3 +1,5 @@
OPENAI_API_KEY=sk-****
ANTHROPIC_API_KEY=sk-ant-api****
TAVILY_API_KEY=tvly-****
GROQ_API_KEY=gsk_****
OPENWEATHER_API_KEY=***
E2B_API_KEY=e2b_****

View File

@ -4,9 +4,29 @@
A minimalistic AI-powered search engine that helps you find information on the internet.
## Features
- **AI-powered search**: Get answers to your questions using Anthropic's Models.
- **Web search**: Search the web using Tavily's API.
- **URL Specific search**: Get information from a specific URL.
- **Weather**: Get the current weather for any location using OpenWeather's API.
- **Programming**: Run code snippets in multiple languages using E2B's API.
## Built with
- [Next.js](https://nextjs.org/)
- [Tailwind CSS](https://tailwindcss.com/)
- [Vercel AI SDK](https://sdk.vercel.ai/docs)
- [Shadcn/UI](https://ui.shadcn.com/)
- [Anthropic](https://www.anthropic.com/)
- [Tavily](https://tavily.com/)
- [OpenWeather](https://openweathermap.org/)
- [E2B](https://e2b.dev/)
### Deploy your own
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fzaidmukaddam%2Fminiperplx&env=OPENAI_API_KEY,ANTHROPIC_API_KEY,TAVILY_API_KEY,OPENWEATHER_API_KEY,E2B_API_KEY&envDescription=API%20keys%20needed%20for%20application)
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fzaidmukaddam%2Fminiperplx&env=ANTHROPIC_API_KEY,GROQ_API_KEY,TAVILY_API_KEY,OPENWEATHER_API_KEY,E2B_API_KEY&envDescription=API%20keys%20needed%20for%20application)
### Local development
To run the example locally you need to:

View File

@ -1,4 +1,3 @@
import { openai } from "@ai-sdk/openai";
import { anthropic } from '@ai-sdk/anthropic'
import { convertToCoreMessages, streamText, tool } from "ai";
import { CodeInterpreter } from '@e2b/code-interpreter'
@ -12,36 +11,34 @@ export async function POST(req: Request) {
const { messages, model } = await req.json();
const { latitude, longitude, city } = geolocation(req)
let ansmodel;
if (model === "claude-3-5-sonnet-20240620") {
ansmodel = anthropic("claude-3-5-sonnet-20240620")
} else {
ansmodel = openai(model)
}
const ansmodel = anthropic(model);
const result = await streamText({
model: ansmodel,
messages: convertToCoreMessages(messages),
temperature: 0,
maxTokens: 500,
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!!!!!." +
"You are an AI web search engine that helps users find information on the internet.\n" +
"Always start with running the tool(s) and then and then only write your response AT ALL COSTS!!\n" +
"Never write a response without running the tool(s) first!\n" +
"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!!!!!." +
"Tool Usage Instructions:\n" +
"The user is located in " + city + " at latitude " + latitude + " and longitude " + longitude + "." +
"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." +
"You use the 'web_search' tool to search for information on the internet before saying anyting to the user." +
"Incomplete details or any other said words before the search tool result in a bad response." +
"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." +
"The detail should be 3-5 paragraphs in 10-12 sentences, some time pointers, each with citations in the [Text](link) format always!" +
"Citations can be inline of the text like this: Hey there! [Google](https://google.com) is a search engine." +
"The detail should be 3-5 paragraphs in 10-12 sentences and put citations using the markdown link format like this always: [source text](link to the site) in the end of each paragraph!" +
"Citations will the render in the client side, so please make sure you format them correctly!" +
"Never use pointers, unless asked to." +
"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. DO NOT put citation to OpenWeatherMaps API EVER!" +
"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 environment is like a jupyter notebook so don't write print statements at all costs!, just write variables in the end.\n\n" +
"The current date is: " +
new Date()
.toLocaleDateString("en-US", {
@ -53,8 +50,12 @@ export async function POST(req: Request) {
.replace(/(\w+), (\w+) (\d+), (\d+)/, "$4-$2-$3 ($1)") +
"." +
"Rules for the response:\n" +
"Use a story telling format in your response, like a news article ALWAYS! This is for all tools except programming!" +
"Never start with 'based on the search results,...' EVER! Always start with the information you found like an article!" +
"Never use the heading format in your response!." +
"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.'",
"Do not use print statements in the code execution tool, just the variables." +
"Don't say things like 'Okay I am going to perform some action.' OR 'Certainly! To count the number of 'r's in the word 'strawberry', we can use a simple Python code. Let's use the programming tool to execute this task.' The user's DO NOT LIKE TO WAIT! REMEMBER THE THING ABOUT PRINT STATEMENTS! NEVER WRITE 'EM!" +
"IMPORTANT!!!: Refrain from saying things like that mention that your going to perform a certain action, example: 'Certainly! I'll search for information about <something> using the web search tool.'",
tools: {
web_search: tool({
description: 'Search the web for information with the given query, max results and search depth.',

View File

@ -36,6 +36,7 @@ import {
Check,
Loader2,
User2,
Edit2,
} from 'lucide-react';
import {
HoverCard,
@ -103,11 +104,12 @@ export default function Home() {
const [showExamples, setShowExamples] = useState(false)
const [showConfirmModal, setShowConfirmModal] = useState(false);
const [newSelectedModel, setNewSelectedModel] = useState('');
const [isEditingQuery, setIsEditingQuery] = useState(false);
const { isLoading, input, messages, setInput, append, reload, handleSubmit, setMessages } = useChat({
api: '/api/chat',
body: {
model: selectedModel === 'Speed' ? 'gpt-4o-mini' : selectedModel === 'Quality (GPT)' ? 'gpt-4o' : 'claude-3-5-sonnet-20240620',
model: selectedModel === 'Speed' ? 'claude-3-haiku-20240307' : 'claude-3-5-sonnet-20240620',
},
maxToolRoundtrips: 2,
onFinish: async (message, { finishReason }) => {
@ -165,19 +167,18 @@ export default function Home() {
onClick={handleCopy}
className="h-8 px-2 text-xs"
>
{isCopied ? "copied" : "copy"}
{isCopied ? (
<Check className="h-3 w-3 mr-1" />
<Check className="h-3 w-3 ml-2" />
) : (
<Copy className="h-3 w-3 mr-1" />
<Copy className="h-3 w-3 ml-2" />
)}
{isCopied ? "Copied" : "Copy"}
</Button>
);
};
const models = [
{ name: 'Speed', description: 'High speed, but lower quality.', details: '(OpenAI/GPT-4o-mini)', icon: FastForward },
{ name: 'Quality (GPT)', description: 'Speed and quality, balanced.', details: '(OpenAI/GPT | Optimized)', icon: Sparkles },
{ name: 'Speed', description: 'High speed, but lower quality.', details: '(Anthropic/Claude-3-Haiku)', icon: FastForward },
{ name: 'Quality (Claude)', description: 'High quality generation.', details: '(Anthropic/Claude-3.5-Sonnet)', icon: Sparkles },
];
@ -190,7 +191,7 @@ export default function Home() {
setSelectedModel(value);
reload({
body: {
model: value === 'Speed' ? 'gpt-4o-mini' : value === 'Quality (GPT)' ? 'gpt-4o' : 'claude-3-5-sonnet-20240620',
model: value === 'Speed' ? 'claude-3-haiku-20240307' : 'claude-3-5-sonnet-20240620',
},
});
}
@ -205,7 +206,7 @@ export default function Home() {
setSuggestedQuestions([]);
reload({
body: {
model: newSelectedModel === 'Speed' ? 'gpt-4o-mini' : newSelectedModel === 'Quality (GPT)' ? 'gpt-4o' : 'claude-3-5-sonnet-20240620',
model: newSelectedModel === 'Speed' ? 'claude-3-haiku-20240307' : 'claude-3-5-sonnet-20240620',
},
});
} else {
@ -742,11 +743,31 @@ export default function Home() {
});
}, [append, setMessages]);
const handleQueryEdit = useCallback(() => {
setIsEditingQuery(true);
setInput(lastSubmittedQuery);
}, [lastSubmittedQuery, setInput]);
const handleQuerySubmit = useCallback((e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
if (input.trim()) {
setLastSubmittedQuery(input.trim());
setIsEditingQuery(false);
setMessages([]);
setHasSubmitted(true);
setIsAnimating(true);
setSuggestedQuestions([]);
handleSubmit(e);
} else {
toast.error("Please enter a search query.");
}
}, [input, setMessages, handleSubmit]);
const exampleQueries = [
"Weather in Doha",
"Latest on Paris Olympics",
"Count the number of r's in strawberry",
"OpenAI GPT-4o mini"
"Explain Claude 3.5 Sonnet"
];
return (
@ -779,7 +800,7 @@ export default function Home() {
className={`flex items-center font-semibold ${models.find((model) => model.name === selectedModel)?.name.includes('Quality') ? 'text-purple-500' : 'text-green-500'} focus:outline-none focus:ring-0 `}
>
{selectedModel === 'Speed' && <FastForward className="w-5 h-5 mr-2" />}
{(selectedModel === 'Quality (GPT)' || selectedModel === 'Quality (Claude)') && <Sparkles className="w-5 h-5 mr-2" />}
{(selectedModel === 'Quality (Claude)') && <Sparkles className="w-5 h-5 mr-2" />}
{selectedModel}
<ChevronDown className={`w-5 h-5 ml-2 transform transition-transform ${isModelSelectorOpen ? 'rotate-180' : ''}`} />
</button>
@ -886,6 +907,18 @@ export default function Home() {
transition={{ duration: 0.5, delay: 0.2 }}
className="flex-grow min-w-0"
>
{isEditingQuery ? (
<form onSubmit={handleQuerySubmit} className="flex items-center space-x-2">
<Input
value={input}
onChange={(e) => setInput(e.target.value)}
className="flex-grow"
/>
<Button type="submit" size="sm">
<ArrowRight size={16} />
</Button>
</form>
) : (
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
@ -898,17 +931,29 @@ export default function Home() {
</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"
className="flex-shrink-0 flex flex-row items-center gap-2"
>
{!isEditingQuery && (
<Button
variant="ghost"
size="sm"
onClick={handleQueryEdit}
className="ml-2"
disabled={isLoading}
>
<Edit2 size={16} />
</Button>
)}
<ModelSelector
selectedModel={selectedModel}
onModelSelect={handleModelChange}
isDisabled={isLoading}
isDisabled={isLoading || isEditingQuery}
/>
</motion.div>
</div>

View File

@ -10,7 +10,6 @@
},
"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",

View File

@ -8,9 +8,6 @@ dependencies:
'@ai-sdk/anthropic':
specifier: ^0.0.37
version: 0.0.37(zod@3.23.8)
'@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
@ -49,7 +46,7 @@ dependencies:
version: 1.4.0
ai:
specifier: latest
version: 3.3.6(react@18.3.1)(svelte@4.2.18)(vue@3.4.35)(zod@3.23.8)
version: 3.3.7(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
@ -141,19 +138,8 @@ packages:
zod: 3.23.8
dev: false
/@ai-sdk/openai@0.0.40(zod@3.23.8):
resolution: {integrity: sha512-9Iq1UaBHA5ZzNv6j3govuKGXrbrjuWvZIgWNJv4xzXlDMHu9P9hnqlBr/Aiay54WwCuTVNhTzAUTfFgnTs2kbQ==}
engines: {node: '>=18'}
peerDependencies:
zod: ^3.0.0
dependencies:
'@ai-sdk/provider': 0.0.14
'@ai-sdk/provider-utils': 1.0.5(zod@3.23.8)
zod: 3.23.8
dev: false
/@ai-sdk/provider-utils@1.0.10(zod@3.23.8):
resolution: {integrity: sha512-xciXF2PorLQMNdhYe+n9CafVkXZANHURsME85RXjtAoZSs631l2t8Blqwz2C/pHUb9bxLdMRRuIEB4PnHLnHvQ==}
/@ai-sdk/provider-utils@1.0.11(zod@3.23.8):
resolution: {integrity: sha512-u3BmXKg4MeA5s5eN9bWP4ybGJuOTRC2H0YacMCag5fcZ14S6kfukGE8MzRsGU2wTv6A16zLY0XqVvwcqe13mUA==}
engines: {node: '>=18'}
peerDependencies:
zod: ^3.0.0
@ -161,23 +147,7 @@ packages:
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'}
peerDependencies:
zod: ^3.0.0
peerDependenciesMeta:
zod:
optional: true
dependencies:
'@ai-sdk/provider': 0.0.14
'@ai-sdk/provider': 0.0.19
eventsource-parser: 1.1.2
nanoid: 3.3.6
secure-json-parse: 2.7.0
@ -200,13 +170,6 @@ packages:
zod: 3.23.8
dev: false
/@ai-sdk/provider@0.0.14:
resolution: {integrity: sha512-gaQ5Y033nro9iX1YUjEDFDRhmMcEiCk56LJdIUbX5ozEiCNCfpiBpEqrjSp/Gp5RzBS2W0BVxfG7UGW6Ezcrzg==}
engines: {node: '>=18'}
dependencies:
json-schema: 0.4.0
dev: false
/@ai-sdk/provider@0.0.15:
resolution: {integrity: sha512-phX/YdwKd8q8/uZ7MsUytcHuN5KvT+wgM+y78eu6E+VyFE3GRwelctBFnaaA96uRL6xnKNmb0e7e+2fDOYuBoA==}
engines: {node: '>=18'}
@ -214,15 +177,15 @@ packages:
json-schema: 0.4.0
dev: false
/@ai-sdk/provider@0.0.18:
resolution: {integrity: sha512-LF4aUAKDTKIHa2e7ozwRJDMhUC9cs7t224sUilG1HfyFWyyh+01oPZwMob/hj111SozZkvXIukN0BIa+sXS0mw==}
/@ai-sdk/provider@0.0.19:
resolution: {integrity: sha512-WXyyJ0Fqg0OHzUQ/spem4jRFPq+NkYB8YNTVbSQrE+Rpxtm7DqK1x9MrHtIEhoikCMg9wBOCbm7HuMnfsIR5GA==}
engines: {node: '>=18'}
dependencies:
json-schema: 0.4.0
dev: false
/@ai-sdk/react@0.0.42(react@18.3.1)(zod@3.23.8):
resolution: {integrity: sha512-oiwXKLc5n7SwaTZWldMrpyJEWTgLh35NXuxQIGDGVHTIryxxMk9lgOQ+vQ8uri3WGMzGQQGRfwh8MTijJ8cN2A==}
/@ai-sdk/react@0.0.43(react@18.3.1)(zod@3.23.8):
resolution: {integrity: sha512-maWuV9529tIVVST9iXgnxBWUoM5Z8DW0lyrMYnsaLJAZ4kostt+PbqJjhy6eAQPzmXGcu4+OdgT1v1ZNCZR4+Q==}
engines: {node: '>=18'}
peerDependencies:
react: ^18 || ^19
@ -233,15 +196,15 @@ packages:
zod:
optional: true
dependencies:
'@ai-sdk/provider-utils': 1.0.10(zod@3.23.8)
'@ai-sdk/ui-utils': 0.0.30(zod@3.23.8)
'@ai-sdk/provider-utils': 1.0.11(zod@3.23.8)
'@ai-sdk/ui-utils': 0.0.31(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.33(zod@3.23.8):
resolution: {integrity: sha512-6AV4g6IrQ7bPcfQgwOjNMT50W2lljk/sgzJ3qx+Bt/lobvhA7khyW1RVYTnxx3OBdf4/qB1D2BAAbUrrm/na8A==}
/@ai-sdk/solid@0.0.34(zod@3.23.8):
resolution: {integrity: sha512-puVv9rrskWXrtaikDbpoMkGeTboa4ZY6wTmC66Xw9rhZ0zK5yN15lLJBf/LeBIV6J1V9F9bBxjRX7UQXjE3sZg==}
engines: {node: '>=18'}
peerDependencies:
solid-js: ^1.7.7
@ -249,14 +212,14 @@ packages:
solid-js:
optional: true
dependencies:
'@ai-sdk/provider-utils': 1.0.10(zod@3.23.8)
'@ai-sdk/ui-utils': 0.0.30(zod@3.23.8)
'@ai-sdk/provider-utils': 1.0.11(zod@3.23.8)
'@ai-sdk/ui-utils': 0.0.31(zod@3.23.8)
transitivePeerDependencies:
- zod
dev: false
/@ai-sdk/svelte@0.0.35(svelte@4.2.18)(zod@3.23.8):
resolution: {integrity: sha512-vbDmvcu2MRZvvxoOtCUH8ydKSaugaQkhiBtZRp/U1YvSIuzR7xUkYSf0EQ173kWBWsaoPO9PFava0WxF7k1q4g==}
/@ai-sdk/svelte@0.0.36(svelte@4.2.18)(zod@3.23.8):
resolution: {integrity: sha512-5pSaKt+UZK9+9AsbIYLs4REtAc/0HOLX4DK3nRtMcDqDLoWDoSJDKK/EjDMYVhYB1gqQmT0AeiSLo2WH0nf00w==}
engines: {node: '>=18'}
peerDependencies:
svelte: ^3.0.0 || ^4.0.0
@ -264,16 +227,16 @@ packages:
svelte:
optional: true
dependencies:
'@ai-sdk/provider-utils': 1.0.10(zod@3.23.8)
'@ai-sdk/ui-utils': 0.0.30(zod@3.23.8)
'@ai-sdk/provider-utils': 1.0.11(zod@3.23.8)
'@ai-sdk/ui-utils': 0.0.31(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.30(zod@3.23.8):
resolution: {integrity: sha512-ifmYSQtSVdeY1XlOFirAdbgWVnSg5hYPhG8bEiNI9TvR1HFdMN/zZhxscjLyKXXAelf/ACYvUjwNQmCnWSurZQ==}
/@ai-sdk/ui-utils@0.0.31(zod@3.23.8):
resolution: {integrity: sha512-PA1mI+WC69Bc8JCTDOXwhLv9OAfocex/d+MRtQjfuWE6jTBjkBMa6davw+JjN7Vcp6zP0JLQG6gd7n6MnkFepQ==}
engines: {node: '>=18'}
peerDependencies:
zod: ^3.0.0
@ -281,16 +244,16 @@ packages:
zod:
optional: true
dependencies:
'@ai-sdk/provider': 0.0.18
'@ai-sdk/provider-utils': 1.0.10(zod@3.23.8)
'@ai-sdk/provider': 0.0.19
'@ai-sdk/provider-utils': 1.0.11(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.34(vue@3.4.35)(zod@3.23.8):
resolution: {integrity: sha512-Nbht63i4NJrau5Yrf6dH6paH2mj/5CSmHopjA0IRHdOTvh3lKe382oZP2hLnN/xa575r25as67l7P/j/iq8ULQ==}
/@ai-sdk/vue@0.0.35(vue@3.4.35)(zod@3.23.8):
resolution: {integrity: sha512-7cPShsxiyxzoSB5orjCqwnFWvjpM/YX2W+a2K6lyV2Z2JAgHc+4PHhVnrKwc0c9Q7vwfpvW+3MoKM6U2xZaS+w==}
engines: {node: '>=18'}
peerDependencies:
vue: ^3.3.4
@ -298,8 +261,8 @@ packages:
vue:
optional: true
dependencies:
'@ai-sdk/provider-utils': 1.0.10(zod@3.23.8)
'@ai-sdk/ui-utils': 0.0.30(zod@3.23.8)
'@ai-sdk/provider-utils': 1.0.11(zod@3.23.8)
'@ai-sdk/ui-utils': 0.0.31(zod@3.23.8)
swrv: 1.0.4(vue@3.4.35)
vue: 3.4.35(typescript@5.5.4)
transitivePeerDependencies:
@ -1584,8 +1547,8 @@ packages:
engines: {node: '>=0.4.0'}
hasBin: true
/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==}
/ai@3.3.7(react@18.3.1)(svelte@4.2.18)(vue@3.4.35)(zod@3.23.8):
resolution: {integrity: sha512-xMfQdOL2s0aiGozdUO0ahOAfcwkGBUye3q4wC64PPNpmE3Qeing1Tv4JSsHk0zymhCMHBDiI1Tky8BNGdu+V6A==}
engines: {node: '>=18'}
peerDependencies:
openai: ^4.42.0
@ -1605,13 +1568,13 @@ packages:
zod:
optional: true
dependencies:
'@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)
'@ai-sdk/provider': 0.0.19
'@ai-sdk/provider-utils': 1.0.11(zod@3.23.8)
'@ai-sdk/react': 0.0.43(react@18.3.1)(zod@3.23.8)
'@ai-sdk/solid': 0.0.34(zod@3.23.8)
'@ai-sdk/svelte': 0.0.36(svelte@4.2.18)(zod@3.23.8)
'@ai-sdk/ui-utils': 0.0.31(zod@3.23.8)
'@ai-sdk/vue': 0.0.35(vue@3.4.35)(zod@3.23.8)
'@opentelemetry/api': 1.9.0
eventsource-parser: 1.1.2
json-schema: 0.4.0