Intégrer Mastra à votre projet Electron
Dans ce guide, vous allez créer avec Mastra un Agent d’IA capable d’appeler des Tools, puis le connecter à une application de bureau Electron en l’appelant directement depuis le serveur Mastra.
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 Electron (facultatif)Lien direct vers Créer une application Electron (facultatif)
Si vous disposez déjà d’une application Electron, passez à l’étape suivante.
Initialisez une nouvelle application Electron avec electron-vite :
- npm
- pnpm
- Yarn
- Bun
npm create @quick-start/electron@latest electron-chat -- --template react-ts --skip
pnpm create @quick-start/electron electron-chat --template react-ts --skip
yarn create @quick-start/electron electron-chat --template react-ts --skip
bunx @quick-start/create-electron@latest electron-chat --template react-ts --skip
Cette commande crée une application Electron nommée electron-chat avec React et TypeScript. Accédez au répertoire du projet :
cd electron-chat
Modifier les paramètres CSPLien direct vers Modifier les paramètres CSP
Pour que l’application Electron puisse appeler le serveur Mastra, vous devez adapter les paramètres de la politique de sécurité du contenu (CSP).
Ouvrez src/renderer/index.html et mettez à jour la balise <meta http-equiv="Content-Security-Policy"> afin d’inclure http://localhost:4111 dans la directive connect-src :
<meta
http-equiv="Content-Security-Policy"
content="default-src 'self'; connect-src http://localhost:4111; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:"
/>
Pour les déploiements en production, adaptez cette valeur à l’URL réelle de votre serveur.
Modifier main.cssLien direct vers edit-maincss
Ouvrez src/renderer/src/assets/main.css et remplacez son contenu par :
@import './base.css';
body {
background: var(--ev-c-white);
color: var(--ev-c-black);
}
Initialiser MastraLien direct vers Initialiser Mastra
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 votre interface de chat.
Installer AI SDK UI et AI ElementsLien direct vers Installer AI SDK UI et AI Elements
Installez AI SDK UI ainsi que l’adaptateur Mastra :
- npm
- pnpm
- Yarn
- Bun
npm install @mastra/ai-sdk@latest @ai-sdk/react ai
pnpm add @mastra/ai-sdk@latest @ai-sdk/react ai
yarn add @mastra/ai-sdk@latest @ai-sdk/react ai
bun add @mastra/ai-sdk@latest @ai-sdk/react ai
Créer une route de chatLien direct vers Créer une route de chat
Ouvrez src/mastra/index.ts et ajoutez une chatRoute() à votre configuration. Elle crée une route d’API que votre frontend Electron peut appeler pour recevoir des réponses de chat compatibles avec AI SDK ; vous l’utiliserez ensuite avec useChat().
import { Mastra } from '@mastra/core/mastra'
// Existing imports...
import { chatRoute } from '@mastra/ai-sdk'
export const mastra = new Mastra({
// Existing config...
server: {
cors: {
origin: '*', // Restrict this to your app's origin in production
allowMethods: ['*'],
allowHeaders: ['*'],
},
apiRoutes: [
chatRoute({
path: '/chat/:agentId',
}),
],
},
})
CORS est nécessaire, car le moteur de rendu Electron se charge depuis une origine différente de celle du serveur Mastra. Pour les déploiements en production, limitez l’origine à celle de votre application.
Ajouter l’interface de chatLien direct vers Ajouter l’interface de chat
Ouvrez src/renderer/src/App.tsx et remplacez son contenu par le composant de chat :
import { useState } from 'react'
import { useChat } from '@ai-sdk/react'
import { DefaultChatTransport, type ToolUIPart } from 'ai'
const STATE_TO_LABEL_MAP: Record<string, string> = {
'input-streaming': 'Streaming input...',
'input-available': 'Input ready',
'approval-requested': 'Approval requested',
'approval-responded': 'Approval responded',
'output-available': 'Complete',
'output-error': 'Error',
}
export default function App(): React.JSX.Element {
const [input, setInput] = useState('')
const { messages, sendMessage } = useChat({
transport: new DefaultChatTransport({
api: `http://localhost:4111/chat/weather-agent`,
}),
})
const handleSubmit = (e: React.FormEvent<HTMLFormElement>): void => {
e.preventDefault()
if (!input.trim()) return
sendMessage({ text: input })
setInput('')
}
return (
<main
style={{
maxWidth: '48rem',
marginLeft: 'auto',
marginRight: 'auto',
padding: '1.5rem',
width: '100%',
height: '100vh',
}}
>
<div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
<div style={{ flex: '1 1 0%', minHeight: 0, overflowY: 'auto' }} data-name="conversation">
<div
data-name="conversation-content"
style={{ display: 'flex', flexDirection: 'column', gap: '2rem' }}
>
{messages.map((message, messageIndex) => (
<div key={messageIndex}>
{message.parts.map((part, partIndex) => {
if (part.type === 'text') {
return (
<div
key={partIndex}
data-name="message"
style={{
display: 'flex',
width: '100%',
maxWidth: '95%',
flexDirection: 'column',
gap: '0.5rem',
...(message.role === 'user'
? { marginLeft: 'auto', justifyContent: 'flex-end' }
: {}),
}}
>
<div
data-name="message-content"
style={{
display: 'flex',
width: 'fit-content',
maxWidth: '100%',
minWidth: 0,
flexDirection: 'column',
gap: '0.5rem',
overflow: 'hidden',
fontSize: '0.875rem',
...(message.role === 'user'
? {
marginLeft: 'auto',
borderRadius: '0.5rem',
backgroundColor: '#dbeafe',
paddingLeft: '1rem',
paddingRight: '1rem',
paddingTop: '0.75rem',
paddingBottom: '0.75rem',
}
: {}),
}}
>
<div
data-name="message-response"
style={{ width: '100%', height: '100%' }}
>
{part.text}
</div>
</div>
</div>
)
}
if (part.type.startsWith('tool-')) {
const toolPart = part as unknown as ToolUIPart
return (
<div
key={partIndex}
data-name="tool"
style={{
marginBottom: '1.5rem',
width: '100%',
borderRadius: '0.5rem',
border: '1px solid #d1d5db',
boxShadow: '0 1px 3px 0 rgba(0,0,0,0.1)',
}}
>
<details
data-name="tool-header"
style={{ width: '100%', padding: '0.75rem', cursor: 'pointer' }}
>
<summary style={{ fontWeight: 500, fontSize: '0.875rem' }}>
{toolPart.type.split('-').slice(1).join('-')} -{' '}
{STATE_TO_LABEL_MAP[toolPart.state ?? 'output-available']}
</summary>
<div data-name="tool-content">
<div
data-name="tool-input"
style={{
overflow: 'hidden',
paddingTop: '1rem',
paddingBottom: '1rem',
}}
>
<div
style={{
fontWeight: 500,
color: '#6b7280',
fontSize: '0.75rem',
textTransform: 'uppercase',
letterSpacing: '0.05em',
}}
>
Parameters
</div>
<pre
style={{
width: '100%',
overflowX: 'auto',
borderRadius: '0.375rem',
border: '1px solid #d1d5db',
backgroundColor: '#f9fafb',
padding: '0.75rem',
fontSize: '0.875rem',
}}
>
<code>{JSON.stringify(toolPart.input, null, 2)}</code>
</pre>
</div>
<div
data-name="tool-output"
style={{
overflow: 'hidden',
paddingTop: '1rem',
paddingBottom: '1rem',
}}
>
<div
style={{
fontWeight: 500,
color: '#6b7280',
fontSize: '0.75rem',
textTransform: 'uppercase',
letterSpacing: '0.05em',
}}
>
{toolPart.errorText ? 'Error' : 'Result'}
</div>
<pre
style={{
width: '100%',
overflowX: 'auto',
borderRadius: '0.375rem',
border: '1px solid #d1d5db',
backgroundColor: '#f9fafb',
padding: '0.75rem',
fontSize: '0.875rem',
}}
>
<code>{JSON.stringify(toolPart.output, null, 2)}</code>
</pre>
{toolPart.errorText && (
<div data-name="tool-error" style={{ color: '#dc2626' }}>
{toolPart.errorText}
</div>
)}
</div>
</div>
</details>
</div>
)
}
return null
})}
</div>
))}
</div>
</div>
<form
style={{
width: '100%',
display: 'grid',
gridTemplateColumns: '1fr auto',
gap: '1.5rem',
flexShrink: 0,
paddingTop: '1rem',
}}
onSubmit={handleSubmit}
data-name="prompt-input"
>
<input
name="chat-input"
style={{
borderRadius: '0.5rem',
border: '1px solid #d1d5db',
boxShadow: '0 1px 2px 0 rgba(0,0,0,0.05)',
height: '2.5rem',
padding: '0 0.75rem',
}}
placeholder="City name"
value={input}
onChange={e => setInput(e.target.value)}
/>
<button
style={{
backgroundColor: '#2563eb',
color: 'white',
boxShadow: '0 10px 15px -3px rgba(0,0,0,0.1)',
border: '1px solid #60a5fa',
paddingLeft: '1rem',
paddingRight: '1rem',
whiteSpace: 'nowrap',
borderRadius: '0.5rem',
fontSize: '0.875rem',
fontWeight: 500,
transition: 'all',
flexShrink: 0,
outline: 'none',
}}
type="submit"
>
Send
</button>
</form>
</div>
</main>
)
}
Cela connecte useChat() au point de terminaison /chat/weather-agent, lui envoie les instructions et reçoit la réponse en streaming par fragments.
Tester votre AgentLien direct vers Tester votre Agent
Pour tester votre Agent avec l’interface de chat, exécutez simultanément le serveur Mastra et l’application Electron.
-
Démarrez le serveur de développement Mastra :
- npm
- pnpm
- Yarn
- Bun
npx mastra devpnpm dlx mastra devyarn dlx mastra devbun x mastra dev -
Dans un autre terminal, démarrez l’application Electron :
- npm
- pnpm
- Yarn
- Bun
npm run devpnpm run devyarn devbun run dev -
Une fenêtre Electron s’ouvre avec l’interface de chat
-
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 Electron ! 🎉
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 React, 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