Aller au contenu principal

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 commencer
Lien 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.0 ou 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 :

npx 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 Mastra
Lien 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é :

npx 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émoire
  • tools/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 UI
Lien direct vers Installer AI SDK UI

Installez AI SDK UI ainsi que l’adaptateur Mastra :

npm install @mastra/ai-sdk@latest @ai-sdk/svelte ai

Créer une route de chat
Lien direct vers Créer une route de chat

Créez src/routes/api/chat/+server.ts :

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.

src/routes/+page.ts
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 chat
Lien direct vers Ajouter l’interface de chat

Remplacez le contenu de src/routes/+page.svelte par ce qui suit.

src/routes/+page.svelte
<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 Agent
Lien direct vers Tester votre Agent

  1. Exécutez votre application SvelteKit avec npm run dev
  2. Ouvrez le chat à l’adresse http://localhost:5173
  3. Posez une question sur la météo. Si votre clé API est correctement configurée, vous obtiendrez une réponse

Étapes suivantes
Lien 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 :