Passer au contenu principal
L’interrogation des résultats est efficace, mais pour une expérience plus réactive et en temps réel, vous pouvez streamer les événements directement depuis un outil en cours d’exécution. Ce guide couvre les deux principaux types de streaming disponibles dans l’API :
  1. Streaming d’Exécution d’Outil : Pour surveiller les tâches d’outils de longue durée.
  2. Streaming de Session d’Agent : Pour recevoir des réponses de chat en temps réel des agents.

Streaming d’Exécution d’Outil

Ce guide montre comment se connecter au flux d’événements d’un outil en utilisant les Server-Sent Events (SSE). Il suppose que vous avez déjà lancé une exécution d’outil comme indiqué dans le guide Exécuter Votre Premier Outil.
1

Exécuter un Outil et Obtenir l'URL de Streaming

Tout d’abord, exécutez un outil comme vous le feriez normalement. La réponse initiale 202 Accepted contiendra une stream_url. C’est l’endpoint que nous utiliserons pour recevoir les événements en direct.
Réponse
{
  "execution_id": "exec_123456789",
  "status": "pending",
  "tool_id": "d1e2f3a4-b5c6-7890-1234-567890abcdef",
  "details_url": "https://app.ubik-agent.com/api/v1/tool-executions/exec_123456789",
  "stream_url": "https://app.ubik-agent.com/api/v1/tool-executions/exec_123456789/stream"
}
Copiez la stream_url pour l’étape suivante.
2

Se Connecter au Flux d'Événements

Maintenant, vous pouvez vous connecter à la stream_url en utilisant n’importe quel client compatible SSE. La connexion restera ouverte, et le serveur enverra les événements au fur et à mesure qu’ils se produisent.
# Utilisez l'option -N pour désactiver la mise en mémoire tampon
curl -X GET "https://app.ubik-agent.com/api/v1/tool-executions/exec_123456789/stream" \
     -H "X-API-KEY: VOTRE_CLE_API" \
     -N
Dans l’exemple JavaScript EventSource, nous passons la clé API comme paramètre de requête. Notre serveur est configuré pour accepter la clé API soit via l’en-tête X-API-KEY, soit via un paramètre de requête nommé api_key pour les connexions SSE, car EventSource ne prend pas en charge les en-têtes personnalisés.
3

Comprendre les Événements

Au fur et à mesure que l’outil s’exécute, vous recevrez une série d’objets JSON. Chaque objet contient un event_type et une charge utile data. Voici les types d’événements détaillés et leurs structures :

tool_update

Utilisé pour les mises à jour générales de progression ou les changements de données structurées.
{
  "phase": "processing",        // Optionnel : Phase d'exécution actuelle
  "message": "Traitement...",   // Optionnel : Statut lisible par l'humain
  "output_key": "result",       // Optionnel : Clé pour les données structurées
  "data": { ... }               // Optionnel : Données structurées arbitraires
}

tool_partial_update

Utilisé pour le contenu en streaming (par exemple, génération de texte, téléchargements partiels d’images).
{
  "content": "texte partiel...", // Le fragment de contenu
  "output_key": "response",      // Le champ de sortie en cours de streaming
  "data": { ... }                // Optionnel : Métadonnées supplémentaires
}

tool_input_required

Envoyé lorsqu’un outil interactif met en pause l’exécution pour attendre une entrée de l’utilisateur.
{
  "prompt": "Veuillez confirmer...", // Question pour l'utilisateur
  "input_types": ["text"],           // Types d'entrée autorisés
  "timeout": 300,                    // Délai d'attente en secondes
  "state": { ... }                   // État interne (opaque)
}

tool_end

L’événement final d’une exécution réussie. Les données contiennent les sorties directes de l’outil.
Pour des raisons de compatibilité ou selon la méthode d’exécution, cet événement peut parfois apparaître sous le nom final_result. Il doit être traité de la même manière que tool_end.
{
  "execution_id": "exec_123...", // ID de l'exécution
  "response": "Texte complet...", // Exemple de sortie (dépend de l'outil)
  "images": [...]                 // Exemple de sortie
}

error

Indique qu’une erreur est survenue pendant l’exécution.
{
  "message": "Description de l'erreur",
  "code": "CODE_ERREUR"
}

Gestion des Événements Larges (Chunking)

Pour les événements qui dépassent la limite de taille (par exemple, de grandes images encodées en base64 ou de longs textes), l’API utilise un mécanisme de “chunking”. Ces événements sont divisés en plusieurs parties avec le suffixe _delta_sse ajouté au nom de l’événement d’origine.Par exemple, si un événement tool_update est trop volumineux, vous recevrez une série d’événements tool_update_delta_sse.Structure d’un événement chunké :
{
  "chunk_id": "uuid-unique-pour-ce-groupe",
  "chunk_index": 0,           // Index du morceau (commence à 0)
  "total_chunks": 5,          // Nombre total de morceaux
  "original_event_type": "tool_update",
  "chunk_data": "...",        // Fragment de la donnée JSON originale (string)
  "is_last_chunk": false      // true pour le dernier morceau
}
Logique de réassemblage (Côté Client) :
  1. Détectez si le nom de l’événement se termine par _delta_sse.
  2. Stockez les chunk_data dans un buffer, ordonnés par chunk_index.
  3. Lorsque is_last_chunk est true, concaténez tous les fragments de chunk_data.
  4. Analysez la chaîne concaténée comme du JSON.
  5. Traitez l’objet résultant comme s’il s’agissait de l’événement original_event_type.
Exemple JavaScript de gestion du chunking :
const eventBuffers = {}; // Stocker les morceaux par chunk_id

eventSource.addEventListener('message', (event) => {
    // Note: EventSource peut ne pas exposer le type d'événement directement dans 'message'
    // Il est préférable d'utiliser un gestionnaire générique ou d'écouter tous les types possibles
});

// Fonction utilitaire pour gérer tous les événements entrants
function handleIncomingEvent(eventType, eventData) {
    if (eventType.endsWith('_delta_sse')) {
        const { chunk_id, chunk_index, chunk_data, is_last_chunk, original_event_type } = eventData;
        
        if (!eventBuffers[chunk_id]) {
            eventBuffers[chunk_id] = [];
        }
        eventBuffers[chunk_id][chunk_index] = chunk_data;

        if (is_last_chunk) {
            const fullDataString = eventBuffers[chunk_id].join('');
            delete eventBuffers[chunk_id]; // Nettoyage
            
            try {
                const fullData = JSON.parse(fullDataString);
                // Traiter récursivement l'événement reconstitué
                handleIncomingEvent(original_event_type, fullData);
            } catch (e) {
                console.error("Erreur de parsing du chunk réassemblé", e);
            }
        }
        return; // Attendre les autres morceaux
    }

    // Traitement normal des événements
    console.log(`Événement reçu: ${eventType}`, eventData);
    if (eventType === 'tool_end') {
        console.log("Résultat final:", eventData);
    }
}

Exemple de Flux d’Événements

event: tool_update
data: {"phase": "retrieval", "message": "Récupération des documents pertinents..."}

event: tool_update
data: {"phase": "generation", "message": "Génération de la réponse..."}

event: tool_partial_update
data: {"content": "Les résultats financiers montrent..."}

event: tool_partial_update
data: {"content": " une augmentation significative du chiffre d'affaires."}

event: tool_end
data: {"execution_id": "...", "status": "completed", "outputs": {"response": "Les résultats financiers montrent une augmentation significative du chiffre d'affaires."}}

Intégrer les Événements d’Outils dans l’Interface de Chat

Lorsque vous construisez une interface de chat personnalisée, vous devez souvent combiner l’historique permanent de la conversation (texte) avec les mises à jour transitoires en temps réel (événements). Cela garantit que votre interface utilisateur est à la fois réactive pendant l’exécution et précise lors du rechargement de l’historique.

La Stratégie à Double Flux

  1. Flux de Texte (response_chunk) : Contient la “source de vérité” de la conversation. Il inclut des délimiteurs qui marquent où un outil a été appelé et quel a été le résultat final.
  2. Flux d’Événements (tool_update, tool_partial_update) : Contient les mises à jour de statut en temps réel, les journaux et les indicateurs de progression qui doivent être affichés pendant l’exécution de l’outil.

Logique d’Implémentation

Pour construire une interface utilisateur riche comme celle d’Ubik, suivez ce modèle :
  1. Détecter le Début : Lorsque vous analysez <<TOOL_STEP_START/nom_outil:id_exec>> dans le flux de texte, créez un Conteneur d’Outil dans votre interface. Marquez-le comme “Chargement” ou “En cours”.
  2. Mises à jour en Direct : Écoutez les événements SSE. Si vous recevez un tool_update ou tool_partial_updatetool_execution_id correspond à id_exec, mettez à jour le contenu de votre Conteneur d’Outil (par exemple, affichez “Recherche sur le web…”, mettez à jour une barre de progression ou diffusez des journaux).
  3. Détecter la Fin : Lorsque vous analysez <<TOOL_STEP_RESULT_START>><<TOOL_STEP_RESULT_END>> dans le flux de texte, vous avez la sortie finale et permanente. Vous pouvez maintenant remplacer l’état “Chargement” dans votre Conteneur d’Outil par le résultat statique final.
Cette approche garantit que même si l’utilisateur actualise la page (perdant les événements transitoires), le flux de texte contient toujours l’historique complet de l’exécution (entrées et résultats) nécessaire pour afficher l’état terminé de l’outil.

Flux d’Événements Spécifiques aux Outils

Chaque outil peut émettre des structures de données différentes dans ses événements tool_update et tool_partial_update en fonction de sa fonction (par exemple, un outil de recherche web peut diffuser des mises à jour “Recherche d’URL…”, tandis qu’un outil d’exécution de code diffuse des journaux de console). Pour construire une interface utilisateur robuste, vous devrez analyser le flux d’événements spécifique pour les outils que vous avez l’intention de prendre en charge.
Note : Des guides détaillés documentant les structures d’événements spécifiques pour chaque outil natif seront disponibles à l’avenir. Pour l’instant, nous vous recommandons d’inspecter les événements renvoyés par les outils pendant le développement.
Pour une liste des outils disponibles et de leurs capacités, veuillez consulter le guide Outils Natifs.

Streaming de Session d’Agent

Les Sessions d’Agent fournissent un ensemble différent d’événements adaptés aux interfaces conversationnelles. Lorsque vous envoyez un message avec "stream": true, le serveur diffuse le processus de réflexion de l’agent et les morceaux de réponse.

Événements de Session d’Agent

Contrairement aux exécutions d’outils, les événements de session d’agent sont souvent utilisés pour afficher une interface de chat en temps réel. Pour une liste complète des types d’événements et leur structure, veuillez consulter le Guide des Événements de Session d’Agent.

Endpoint de Stream Dédié

Bien que POST /agent-sessions/{id}/messages prenne en charge le streaming direct, UBIK fournit également un endpoint dédié pour s’abonner aux événements de session. Ceci est utile pour :
  1. Reconnexion : Reprendre un flux si la connexion est interrompue (les événements passés sont rejoués).
  2. Compatibilité Navigateur : Utiliser EventSource qui nécessite une requête GET et une authentification basée sur l’URL.
Endpoint : GET /agent-sessions/{session_id}/stream

Authentification avec JWT

Comme l’API EventSource standard des navigateurs ne peut pas envoyer d’en-têtes personnalisés (comme X-API-KEY), cet endpoint accepte un paramètre de requête token. Vous devez générer un JWT à courte durée de vie en utilisant /auth/token et le passer ici. Pour plus de détails sur la génération de jetons, voir le Guide Authentification & Sécurité.
// 1. Obtenir un jeton à courte durée de vie depuis votre backend
const token = "eyJhbGciOiJIUz..."; 

// 2. Se connecter en utilisant le paramètre token
const streamUrl = `https://app.ubik-agent.com/api/v1/agent-sessions/${sessionId}/stream?token=${token}`;
const eventSource = new EventSource(streamUrl);