Construire
Créer un agent
Recevez des messages, appelez votre propre modèle, répondez au bon endroit et gérez les tâches longues.
Tout agent Pacerelle suit la même boucle : recevoir un message, faire le travail, répondre. Le SDK s'occupe de la connexion et du chiffrement ; vous n'écrivez que la fonction de traitement.
client.onMessage(async (message, agent) => {
const answer = await doTheWork(message.text);
await agent.reply(message, { text: answer });
});Si vous n'avez pas encore connecté d'agent, commencez par le démarrage rapide.
L'objet message
Votre fonction reçoit le message déchiffré et un client pour répondre.
| JavaScript | Python | Description |
|---|---|---|
id | id | Identifiant unique du message. Sert à répondre et comme clé d'idempotence. |
conversationId | conversation_id | La conversation du message. |
from | from_id | L'expéditeur — la personne (ou l'agent) à qui répondre. |
text | text | Le texte du message. |
attachments | attachments | Fichiers joints. Voir Fichiers et médias. |
widgetResponse | widget_response | Présent quand le message répond à un widget. |
replyToMessageId | reply_to_message_id | Renseigné quand l'expéditeur répond à un message précis. |
Répondre au bon endroit
Répondez toujours avec la conversation et l'expéditeur du message reçu, et indiquez son identifiant comme message auquel vous répondez. Le SDK envoie alors la réponse vers l'appareil exact qui a posé la question, même si un autre message est arrivé entre-temps.
// reply() renseigne la conversation, le destinataire et le message d'origine.
await agent.reply(message, { text: "C'est fait." });
// Équivalent, entièrement explicite :
await agent.sendMessage({
conversationId: message.conversationId,
to: message.from,
replyToMessageId: message.id,
text: "C'est fait.",
});Vous pouvez envoyer plusieurs messages pour une même demande — un accusé rapide, puis le résultat.
Brancher un modèle
Pacerelle est indifférent au modèle utilisé. Cet exemple utilise le SDK OpenAI, qui fonctionne aussi avec tout point d'accès compatible OpenAI — y compris un serveur Ollama local. Il garde un court historique par conversation pour que le modèle garde le contexte.
import OpenAI from "openai";
import {
createNodeAgentGatewayClient,
createNodeSignalSnapshotStore,
} from "@pacerelle/sdk/node";
// Lit OPENAI_API_KEY. Pour Ollama : new OpenAI({ baseURL: "http://localhost:11434/v1", apiKey: "ollama" })
const openai = new OpenAI();
const histories = new Map(); // conversationId → messages récents
const agentId = process.env.PACERELLE_AGENT_ID;
const state = createNodeSignalSnapshotStore(agentId);
const client = createNodeAgentGatewayClient({
agentId,
token: process.env.PACERELLE_AGENT_TOKEN,
e2ee: true,
signalSnapshot: state.signalSnapshot,
onSignalSnapshot: state.onSignalSnapshot,
});
client.onMessage(async (message, agent) => {
if (message.widgetResponse || !message.text) return;
const history = histories.get(message.conversationId) ?? [];
history.push({ role: "user", content: message.text });
// Affiche « en train d'écrire… » dans l'application pendant que le modèle réfléchit.
agent.sendTyping({ conversationId: message.conversationId, to: message.from });
const completion = await openai.chat.completions.create({
model: process.env.OPENAI_MODEL,
messages: [
{ role: "system", content: "Tu es un assistant utile qui tourne sur mon ordinateur." },
...history.slice(-20),
],
});
const answer = completion.choices[0].message.content ?? "";
history.push({ role: "assistant", content: answer });
histories.set(message.conversationId, history);
await agent.reply(message, { text: answer });
});
await client.connect();Ajoutez les réglages du modèle à côté de la configuration Pacerelle :
PACERELLE_AGENT_ID=agent_...
PACERELLE_AGENT_TOKEN=...
OPENAI_API_KEY=sk-...
OPENAI_MODEL=nom-de-votre-modeleRemplacez l'appel OpenAI par Anthropic, Google, Mistral, LangChain, LlamaIndex, CrewAI ou votre propre code. La partie Pacerelle — recevoir, répondre — reste exactement la même.
Montrer que l'agent travaille
Dès qu'une tâche prend plus de quelques secondes, tenez l'utilisateur informé :
- Indicateur de saisie —
agent.sendTyping({ conversationId, to })en JavaScript. - Accusé rapide — répondez tout de suite
Je m'en occupe…, puis envoyez le résultat. - Barre de progression — un widget de progression mis à jour au fil du travail.
Tâches longues
Les messages sont traités un par un, dans l'ordre. Quand votre fonction se termine sans erreur, le SDK marque le message comme traité et en accuse réception auprès du relais. Si la fonction lève une erreur ou si le processus plante avant, le message peut être livré à nouveau plus tard.
Pour un travail de plusieurs minutes ou heures :
- Enregistrez la tâche de façon durable (fichier, base de données, file) avant la fin de la fonction.
- Rendez la main rapidement, éventuellement avec une première réponse :
C'est lancé, je reviens vers vous. - Une fois la tâche terminée, envoyez le résultat avec
replyToMessageIdégal à l'identifiant du message d'origine.
Utilisez l'id du message comme clé d'idempotence pour qu'un message relivré ne lance jamais deux
fois la même tâche. Voir Mise en production.
Relire les messages précédents
Après un redémarrage, le SDK JavaScript peut récupérer les messages récents reçus par votre agent
dans une conversation pour reconstruire le contexte. Passez before ou beforeId pour remonter
plus loin.
const recent = await client.listConversationMessages({
conversationId: message.conversationId,
limit: 50,
skipUndecodable: true,
});