Intégrer Mastra à votre projet SvelteKit
Dans ce guide, vous allez créer avec Mastra un Agent d’IA capable d’appeler des Tools, puis le connecter à SvelteKit en important et en appelant l’Agent directement depuis vos routes.
Vous utiliserez AI SDK UI pour créer une expérience de chat élégante et interactive.
Avant de commencerLien direct vers Avant de commencer
- Vous aurez besoin d’une clé API provenant d’un Provider de modèles pris en charge. Si vous n’avez pas de préférence, utilisez OpenAI.
- Installez Node.js
v22.13.0ou une version ultérieure
Créer une application SvelteKit (facultatif)Lien direct vers Créer une application SvelteKit (facultatif)
Si vous disposez déjà d’une application SvelteKit utilisant Tailwind, passez à l’étape suivante.
Exécutez la commande suivante pour créer une application SvelteKit :
- npm
- pnpm
- Yarn
- Bun
npx sv create mastra-svelte --template minimal --types ts --add tailwindcss="plugins:forms" --install npm
pnpm dlx sv create mastra-svelte --template minimal --types ts --add tailwindcss="plugins:forms" --install npm
yarn dlx sv create mastra-svelte --template minimal --types ts --add tailwindcss="plugins:forms" --install npm
bun x sv create mastra-svelte --template minimal --types ts --add tailwindcss="plugins:forms" --install npm
Cette commande crée un projet nommé mastra-svelte, mais vous pouvez choisir le nom de votre choix. Tailwind est ajouté pour la mise en forme utilisée plus loin.
Initialiser MastraLien direct vers Initialiser Mastra
Accédez à votre projet SvelteKit :
cd mastra-svelte
Exécutez mastra init. Lorsque vous y êtes invité, choisissez un Provider (par exemple OpenAI) et saisissez votre clé :
- npm
- pnpm
- Yarn
- Bun
npx mastra@latest init
pnpm dlx mastra@latest init
yarn dlx mastra@latest init
bun x mastra@latest init
Cette commande crée un dossier src/mastra contenant un exemple d’Agent météo et les fichiers suivants :
index.ts— configuration de Mastra, y compris la mémoiretools/weather-tool.ts— Tool qui récupère la météo d’un lieu donnéagents/weather-agent.ts— Agent météo doté d’une instruction qui utilise le Tool
Dans les étapes suivantes, vous appellerez weather-agent.ts depuis vos routes SvelteKit.
Installer AI SDK UILien direct vers Installer AI SDK UI
Installez AI SDK UI ainsi que l’adaptateur Mastra :
- npm
- pnpm
- Yarn
- Bun
npm install @mastra/ai-sdk@latest @ai-sdk/svelte ai
pnpm add @mastra/ai-sdk@latest @ai-sdk/svelte ai
yarn add @mastra/ai-sdk@latest @ai-sdk/svelte ai
bun add @mastra/ai-sdk@latest @ai-sdk/svelte ai
Créer une route de chatLien direct vers Créer une route de chat
Créez src/routes/api/chat/+server.ts :
import type { RequestHandler } from './$types'
import { handleChatStream } from '@mastra/ai-sdk'
import { toAISdkV5Messages } from '@mastra/ai-sdk/ui'
import { createUIMessageStreamResponse } from 'ai'
import { mastra } from '../../../mastra'
const THREAD_ID = 'example-user-id'
const RESOURCE_ID = 'weather-chat'
export const POST: RequestHandler = async ({ request }) => {
const params = await request.json()
const stream = await handleChatStream({
mastra,
agentId: 'weather-agent',
params: {
...params,
memory: {
...params.memory,
thread: THREAD_ID,
resource: RESOURCE_ID,
},
},
})
return createUIMessageStreamResponse({ stream })
}
export const GET: RequestHandler = async () => {
const memory = await mastra.getAgentById('weather-agent').getMemory()
let response = null
try {
response = await memory?.recall({
threadId: THREAD_ID,
resourceId: RESOURCE_ID,
})
} catch {
console.log('No previous messages found.')
}
const uiMessages = toAISdkV5Messages(response?.messages || [])
return Response.json(uiMessages)
}
La route POST accepte une instruction et renvoie la réponse de l’Agent en streaming au format AI SDK, tandis que la route GET récupère l’historique des messages depuis la mémoire afin de réhydrater l’interface lors du rechargement du client.
Pour que le gestionnaire GET soit appelé, créez un fichier src/routes/+page.ts. Sa fonction load() s’exécute avec +page.svelte.
import type { UIDataTypes, UIMessage, UITools } from 'ai'
import type { PageLoad } from './$types'
export const load: PageLoad = async ({ fetch }) => {
const response = await fetch('/api/chat')
const initialMessages = (await response.json()) as UIMessage<unknown, UIDataTypes, UITools>[]
return { initialMessages }
}
Ajouter l’interface de chatLien direct vers Ajouter l’interface de chat
Remplacez le contenu de src/routes/+page.svelte par ce qui suit.
<script lang="ts">
import { Chat } from '@ai-sdk/svelte';
import { DefaultChatTransport, type ToolUIPart } from 'ai';
let input = $state('');
const { data } = $props();
let messages = $derived(data.initialMessages)
const chat = new Chat({
transport: new DefaultChatTransport({
api: '/api/chat'
}),
get messages() {
return messages;
}
});
function handleSubmit(event: SubmitEvent) {
event.preventDefault();
chat.sendMessage({ text: input });
input = '';
}
const STATE_TO_LABEL_MAP: Record<ToolUIPart["state"], string> = {
"input-streaming": "Pending",
"input-available": "Running",
// @ts-expect-error - Only available in AI SDK v6
"approval-requested": "Awaiting Approval",
"approval-responded": "Responded",
"output-available": "Completed",
"output-error": "Error",
"output-denied": "Denied",
};
</script>
<main class="max-w-3xl mx-auto p-6 size-full h-screen">
<div class="flex flex-col h-full">
<div class="flex-1 min-h-0 overflow-y-auto" data-name="conversation">
<div data-name="conversation-content" class="flex flex-col gap-8">
{#each chat.messages as message, messageIndex (messageIndex)}
<div>
{#each message.parts as part, partIndex (partIndex)}
{#if part.type === 'text'}
<div data-name="message" class={[message.role === 'user' && 'ml-auto justify-end', 'group flex w-full max-w-[95%] flex-col gap-2', message.role === 'user' ? 'is-user' : 'is-assistant']}>
<div data-name="message-content" class={["is-user:dark flex w-fit max-w-full min-w-0 flex-col gap-2 overflow-hidden text-sm",
"group-[.is-user]:ml-auto group-[.is-user]:rounded-lg group-[.is-user]:bg-blue-100 group-[.is-user]:px-4 group-[.is-user]:py-3 group-[.is-user]:text-foreground",
"group-[.is-assistant]:text-foreground"]}>
<div data-name="message-response" class="size-full [&>*:first-child]:mt-0 [&>*:last-child]:mb-0">
{part.text}
</div>
</div>
</div>
{:else if part.type.startsWith('tool-')}
<div data-name="tool" class="not-prose mb-6 w-full rounded-lg border border-gray-300 shadow">
<details data-name="tool-header" class="w-full p-3 hover:cursor-pointer">
<summary class="font-medium text-sm">{(part as ToolUIPart).type.split("-").slice(1).join("-")} - {STATE_TO_LABEL_MAP[(part as ToolUIPart).state ?? 'output-available']}</summary>
<div data-name="tool-content" class="">
<div data-name="tool-input" class="space-y-2 overflow-hidden py-4">
<div class="font-medium text-muted-foreground text-xs uppercase tracking-wide">Parameters</div>
<pre class="w-full overflow-x-auto rounded-md border border-gray-300 bg-gray-50 p-3 text-sm"><code>{JSON.stringify((part as ToolUIPart).input, null, 2)}</code></pre>
</div>
<div data-name="tool-output" class="space-y-2 overflow-hidden py-4">
<div class="font-medium text-muted-foreground text-xs uppercase tracking-wide">{(part as ToolUIPart).errorText ? 'Error' : 'Result'}</div>
<pre class="w-full overflow-x-auto rounded-md border border-gray-300 bg-gray-50 p-3 text-sm"><code>{JSON.stringify((part as ToolUIPart).output, null, 2)}</code></pre>
{#if (part as ToolUIPart).errorText}
<div data-name="tool-error" class="text-red-600">
{(part as ToolUIPart).errorText}
</div>
{/if}
</div>
</div>
</details>
</div>
{/if}
{/each}
</div>
{/each}
</div>
</div>
<form class="w-full grid grid-cols-[1fr_auto] gap-6 shrink-0 pt-4" onsubmit={handleSubmit} data-name="prompt-input">
<input name="chat-input" class="rounded-lg border border-gray-300 shadow h-10" placeholder="City name" bind:value={input} />
<button class="bg-blue-600 text-white shadow-lg border border-blue-400 px-4 whitespace-nowrap rounded-lg text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]" type="submit">Send</button>
</form>
</div>
</main>
Cette page connecte Chat au point de terminaison api/chat, lui envoie les instructions et reçoit la réponse en streaming par fragments.
Elle affiche le texte de la réponse à l’aide de composants personnalisés pour les messages et les Tools.
Tester votre AgentLien direct vers Tester votre Agent
- Exécutez votre application SvelteKit avec
npm run dev - Ouvrez le chat à l’adresse http://localhost:5173
- Posez une question sur la météo. Si votre clé API est correctement configurée, vous obtiendrez une réponse
Étapes suivantesLien direct vers Étapes suivantes
Félicitations, vous avez créé votre Agent Mastra avec SvelteKit ! 🎉
Vous pouvez maintenant enrichir le projet avec vos propres Tools et votre propre logique :
- En savoir plus sur les Agents
- Donnez à votre Agent ses propres Tools
- Ajoutez une mémoire semblable à celle des humains à votre Agent
Lorsque vous êtes prêt, découvrez plus en détail l’intégration de Mastra avec AI SDK UI et SvelteKit, ainsi que le déploiement de votre Agent sur n’importe quelle plateforme :
- Intégrez Mastra à AI SDK UI
- Déployez votre Agent sur la plateforme de votre choix
- Essayez la bibliothèque Svelte AI Elements non officielle