Aller au contenu
BeeuniBeeuni
Français
Esc
↑↓naviguer↵ouvrir⌘Japerçu
Sur cette page

Hooks React

Exécutez une session Beeuni dans React avec le hook useSession.

@beeuni/sdk/react ajoute des hooks React au SDK. Cette page présente useSession, le hook qui exécute une session de bout en bout, ainsi que les autres hooks confirmés stables pour les applications React.

useSession(projectId, sessionId, options?)

useSession démarre la session, ouvre le transport d’événements sélectionné par le serveur et synchronise les messages, l’état et les demandes en attente. Appelez-le une fois par vue de session.

import { useSession } from '@beeuni/sdk/react';

function Chat({ projectId, sessionId }: { projectId: string; sessionId: string }) {
  const s = useSession(projectId, sessionId);

  if (s.phase !== 'ready') return <Booting stage={s.stage} onRetry={s.retry} />;

  return (
    <>
      {s.messages.map(({ info, parts }) => (
        <Message key={info.id} info={info} parts={parts} />
      ))}
      <Composer busy={s.isBusy} onSend={s.send} onStop={s.cancel} />
    </>
  );
}

Le serveur fait autorité sur la disponibilité. L’environnement d’exécution est prêt lorsque POST /start renvoie stage: 'ready'. useSession n’effectue pas de vérification de santé distincte côté client.

Valeurs renvoyées

Champ Type Contenu
phase 'starting' | 'ready' | 'error' État global. Affichez un écran de démarrage jusqu’à ready.
messages { info, parts }[] La liste des messages. Les parties arrivent en direct.
savedTranscript 'loading' | 'shown' | 'none' Indique si la conversation enregistrée peut s’afficher avant le réveil de l’ordinateur. loading : une copie enregistrée est en cours d’acheminement. shown : les messages sont dans la liste. none : rien ne peut s’afficher avant la réponse de l’environnement d’exécution.
conversationEmpty boolean La copie enregistrée confirme que la conversation est vide, qu’aucun tour ne s’est terminé depuis et que rien n’est ouvert ni en file d’attente. Affichez la zone de saisie, pas un écran de démarrage.
status SessionStatus L’état de la session.
isBusy boolean L’agent génère une réponse.
questions, permissions array Questions de l’agent et demandes d’approbation d’outils en attente. Ici, un permission est une approbation d’outil de l’environnement d’exécution, pas une autorisation IAM.
diffs, todos array Différences de fichiers et tâches à faire en direct.
sendError BeeuniSendError | null Le dernier échec de send : billing, runtime-not-ready ou runtime-error.
rewindMessageId string | null Le message utilisateur sélectionné pendant la préparation d’un retour en arrière réversible.
rewindPending boolean Une demande de retour en arrière ou de restauration est en cours.
rewindError BeeuniSendError | null Le dernier échec de retour en arrière ou de restauration.
models, agents, defaultAgent, commands — Modèles sélectionnables, agents sélectionnables, agent par défaut et commandes slash. Disponibles avant le démarrage de l’environnement d’exécution.
retry () => void Force une nouvelle vérification de /start.

Actions

Action Fonction
send(text, override?) Envoie un prompt. override définit { model?, agent? } pour ce message uniquement.
sendParts(parts, override?) Envoie du texte et des parties de fichiers avec URL de l’environnement d’exécution via le transport sélectionné. Les références privées préparées utilisent les routes de prompts de la plateforme.
rewind(messageId) Ramène cette session canonique à un message utilisateur. Le message sélectionné et la suite du parcours deviennent masqués et récupérables.
restoreRewind() Restaure le parcours supprimé avant qu’un autre prompt ne valide son remplacement.
cancel() Arrête l’exécution en cours et efface les questions et autorisations en attente. Suspend d’abord les prompts en file d’attente de la session, afin qu’un prompt en attente ne démarre pas une nouvelle exécution.
runCommand(command, args) Exécute une commande slash du projet.
answerQuestion(id, answers) Répond à une question de l’agent en attente.
rejectQuestion(id) Rejette une question de l’agent en attente.
answerPermission(id, reply, message?) Répond à une demande d’approbation d’outil. reply vaut 'once', 'always' ou 'reject'.

useSession renvoie aussi removeQuestion et removePermission. Ne les utilisez pas. Ils effacent la demande de l’état local sans jamais avertir l’agent ; l’exécution reste donc bloquée. Utilisez plutôt answerQuestion, rejectQuestion ou answerPermission.

Options

Option Valeur par défaut Fonction
waitMs 15000 Le budget de long polling envoyé à /start.
replayStartStash true Rejoue un prompt enregistré avant la création de la session, une fois la session prête.
enabled true Définissez false pour différer le hook, par exemple jusqu’à la validation d’une vérification de facturation.
chatEngine true Définissez false si votre application monte sa propre interface de chat pour cette session, afin d’éviter de synchroniser les messages deux fois.
initialRuntimeSessionId null Une référence fixe de session de l’environnement d’exécution que votre serveur détient déjà pour cette session. La transcription s’affiche à partir de cette référence pendant l’exécution de /start ; la réponse de /start reste la référence faisant autorité. initialOpenCodeSessionId est son ancien nom, désormais obsolète.
browserPresence false Maintient le bail de présence de cet onglet pendant qu’une personne connectée utilise la page (saisie au cours des 10 dernières minutes). Le bail maintient l’ordinateur de la session éveillé.
presenceAlerts false Cet onglet affiche ses propres notifications. Transmis via le bail de présence : le serveur n’envoie pas de notifications au téléphone ni via Web Push uniquement lorsqu’un onglet émettant des alertes est utilisé. Toute modification est envoyée immédiatement. Passez true uniquement lorsque l’indicateur notification_center du projet est activé ; sinon, le serveur l’ignore. Nécessite browserPresence.
presencePageExit false Met fin au bail de présence lorsque la page se ferme ou entre dans le cache de navigation précédent/suivant, afin qu’un tour se terminant juste après la fermeture de l’onglet déclenche quand même une notification. Si activé, pagehide signale l’absence, et chaque signalement d’absence est envoyé avec keepalive pour survivre à la page. Si désactivé : aucun signalement pagehide et aucun keepalive. Un onglet qui se ferme devient tout de même masqué et signale l’absence, mais le navigateur peut annuler cette requête lors du déchargement de la page ; le bail reste alors actif jusqu’à son expiration après 90 s. Passez l’indicateur notification_center du projet. Toute modification s’applique immédiatement, sans nouveau signalement de présence. Nécessite browserPresence.
repositoryMode — Télémétrie uniquement. Une session créée avant le remplacement d’un dépôt démarre et utilise la configuration actuelle du projet sans cette option. Seul son clone /workspace provient encore de l’ancien dépôt ; un push depuis ce clone nécessite donc d’abord un rebase.

L’envoi est optimiste. send affiche votre message immédiatement, puis les événements du flux complètent la réponse de l’agent.

rewind(messageId) ne crée jamais de session. Il utilise la session canonique de POST /start. L’environnement d’exécution restaure l’état des fichiers et conserve le parcours supprimé de la transcription récupérable. Le prochain prompt accepté valide le parcours de remplacement.

Autres hooks stables

@beeuni/sdk/react exporte également des hooks React Query pour les données qui ne nécessitent pas de session en cours d’exécution. Chacun correspond à une méthode du client et ne nécessite aucun fournisseur.

Hook Données lues
useProjectModels(projectId) Modèles sélectionnables pour le projet.
useProjectModelPickerCatalog(projectId) L’enregistrement brut /model-picker par modèle au format de transport (reasoning_options, temperature, limit) et les estimations de prix client managedPricingRoutes pour chaque route gérée éligible. La route qui traite la requête détermine le montant final facturé en crédits.
useProjectSessions(projectId, { parent, startedBy, q, limit }) Les sessions d’un projet, paginées. parent: 'root' renvoie les sessions de premier niveau avec child_count ; startedBy: 'me' | 'others' | 'automated' filtre selon la personne qui a lancé l’exécution ; q recherche dans toutes les sessions que l’utilisateur peut ouvrir, pas seulement dans les pages chargées. Chaque ensemble de filtres possède sa propre entrée de cache.
useSessionChildren(projectId, parentSessionId, { q, limit, enabled }) Les sessions créées par un même parent (parent=<id>), de la plus récente à la plus ancienne, paginées. Définissez enabled: false jusqu’à l’ouverture du parent.
useVisibleAgents({ projectId }) Les agents visibles du projet.
useProjectConfig(projectId) La configuration du runtime du projet : agent par défaut, commandes.
useProjectSecrets(projectId) Secrets : liste, ajout, suppression et substitutions personnelles.
useAccountSecretResources(accountId) Métadonnées des secrets de fournisseur du compte et autorisations d’utilisation. Les valeurs ne sont jamais renvoyées.
useSessionProviderSecretPools(projectId, sessionId) Pools configurés, y compris les sélections vides ; setPool met à jour un fournisseur et actualise le cache des sessions.
useProjectTriggers(projectId) Déclencheurs : liste, création, mise à jour, suppression, déclenchement.
useProjectTriggerEventTypes(projectId, connector) Les événements d’application sur lesquels un connecteur peut se déclencher. Inactif tant que connector n’est pas défini.
useChangeRequests(projectId, status?) Demandes de modification : liste, ouverture, fusion, fermeture, demande de changements.
useRuntimeSupports(capability) Indique si le runtime de la session ouverte prend en charge une fonctionnalité (session.rewind, session.compact, …), d’après les réponses /beeuni/health lues par le mécanisme d’interrogation de reconnexion au runtime. true jusqu’à la première réponse. Voir Ce que le runtime prend en charge.
useNotificationInbox({ userId, limit?, enabled? }) La page la plus récente de la boîte de réception de l’appelant (limit vaut 20 par défaut), unreadCount, ainsi que markRead(ids), markAllRead(), markSessionRead(sessionId). Interroge toutes les 60 s tant que la page est visible et recharge les données à la prise de focus. Une écriture modifie immédiatement le cache, le restaure en cas d’échec, puis recharge chaque entrée de la boîte de réception. Aucune requête sans userId.
useNotificationPreferences({ userId, enabled? }) Le choix de l’appelant pour les notifications push et par e-mail, par type, email_available et update(patch) (optimiste).
useSessionWatch({ userId, projectId, sessionId, enabled? }) { watching } pour une session, et setWatching(watching) (optimiste) pour la mettre en sourdine ou la suivre.
resetRuntimeQueries(queryClient) Ce n’est pas un hook. Supprime toutes les requêtes de runtime mises en cache (sessions, messages, agents, commandes, diffs). Appelez-le après le remplacement du runtime de la session par un redémarrage ou un rechargement de configuration, afin que la prochaine lecture provienne du nouveau runtime.

Les trois hooks de notification utilisent userId (qk.notifications) comme clé de cache, afin qu’un changement d’utilisateur dans le même onglet n’affiche jamais la boîte de réception de l’utilisateur précédent. Passez l’identifiant de l’utilisateur connecté.

Les notifications sont contrôlées par le feature flag notification_center propre à chaque projet, désactivé par défaut. Conditionnez chaque hook avec enabled: useFeatureFlag(projectId, 'notification_center').enabled, afin qu’un projet où ce flag est désactivé n’envoie aucune requête de notification.

Liens de configuration des connecteurs

Un agent peut générer un lien de connexion en un clic (/connect/<token>). Les données du parcours et la politique du runtime résident dans le SDK ; l’hôte affiche sa propre boîte de dialogue à partir de ces éléments et y injecte ses adaptateurs.

Export Rôle
useConnectorSetup(token, options) Le parcours complet : charger ce que le lien désigne, POST /start, ouvrir la page hébergée du fournisseur via le openPopup injecté, interroger POST /finalize selon le calendrier de 3 s / 5 s / 5 minutes, et communiquer phase (loading, ready, starting, opened, connected, error), les informations de l’application, l’erreur et l’identité sous laquelle le compte a été autorisé. options contient le backendUrl de l’hôte, l’adaptateur storage et openPopup ; onOpened se déclenche après chaque ouverture de fenêtre contextuelle.
useConnectorLinkInfo(token, options) Un cache partagé, adossé au stockage, par jeton de lien, afin que toutes les cartes et la fenêtre modale partagent une seule requête GET vers la route publique soumise à une limite de débit et affichent le logo de l’application dès la première image. Les mêmes options backendUrl/storage.
createConnectorLinkInfoCache(fetchInfo, { storage }) La fabrique de cache elle-même (sans framework, stockage injecté) pour un hôte qui souhaite sa propre instance.
resolveConnectorStart({ start, finalize }) La règle de résultat de /start : URL hébergée → fenêtre contextuelle, déjà connecté → finaliser une seule fois, sinon le message d’erreur.
nextConnectorPollDelay(attempt, elapsedMs) Le calendrier d’interrogation borné (3 s au départ, puis 5 s, arrêt à 5 minutes).

Données des connecteurs

useConnectorQuery(projectId, slug, action, args, { account, enabled, staleTime }) lit la sortie d’une action de connecteur sous forme de requête mise en cache. error est un ConnectorCallError : affichez un bouton de connexion à partir de error.connectUrl, ou un sélecteur de compte à partir de error.availableAccounts. Utilisez-le uniquement pour une action de lecture ; chaque récupération exécute l’action et écrit un événement d’audit. La sortie reste à jour pendant 30 s, la prise de focus ne recharge jamais les données, et seul un 429 ou 503 en amont fait l’objet d’une nouvelle tentative. Voir Connecteurs depuis le code.

Anticiper la lecture d’ouverture

prefetchSessionOpen(queryClient, projectId, sessionId) lance la lecture d’ouverture de session avant le montage de la vue de session. Il émet une requête GET .../snapshot (enregistrement de session, tour, file d’attente et les 40 premiers messages de la transcription) et initialise le cache de l’enregistrement de session à partir de celle-ci. useSession utilise ensuite cette requête au lieu d’en lancer une autre.

Appelez-le lorsqu’une route désigne une session, ou au survol, à la prise de focus ou au toucher d’un lien de session. Il est en lecture seule : il n’appelle jamais /start et ne réveille jamais un ordinateur. Il ne rejette jamais sa promesse. Un nouvel appel pour la même session dans les 30 secondes n’envoie aucune requête.

import { prefetchSessionOpen } from '@beeuni/sdk/react';

<a
  href={`/projects/${projectId}/sessions/${sessionId}`}
  onFocus={() => void prefetchSessionOpen(queryClient, projectId, sessionId)}
/>;

Afficher depuis le cache lors d’un rechargement

Deux magasins conservent ce qu’un utilisateur a déjà vu, afin qu’un rechargement ou un démarrage à froid de l’application l’affiche dès la première image et l’actualise sur place. Tous deux sont propres à chaque utilisateur et bornés, et l’hôte les efface tous deux à la déconnexion.

  • createPersistedQueryCache conserve les résultats React Query utilisés par l’utilisateur pour naviguer : comptes, projets, détail du projet, liste paginée des sessions et enregistrements de session (isPersistableQueryKey). Une entrée restaurée conserve son ancienneté d’origine, et ses données sont donc rechargées au montage. Les limites par défaut sont de 1 000 000 caractères et 7 jours.
  • createSavedCopyStore conserve les dernières copies enregistrées des transcriptions envoyées par le serveur. Enregistrez-le avec setSavedCopyStore, et useSession affiche la copie conservée avant la première image. La copie du serveur est ensuite réconciliée avec elle par identifiant de message, et le SDK la relit 3 secondes après la fin de chaque tour. Les limites par défaut sont de 12 sessions, 1 500 000 caractères et 14 jours. Une copie de plus de 300 000 caractères conserve ses messages les plus récents qui tiennent dans cette limite ; les messages plus anciens sont chargés depuis le serveur lorsque l’utilisateur fait défiler vers le haut.
import {
  browserKeyValueStorage,
  createPersistedQueryCache,
  createSavedCopyStore,
  isPersistableQueryKey,
  setSavedCopyStore,
} from '@beeuni/sdk';

const storage = browserKeyValueStorage(); // null where there is no localStorage
if (storage) {
  const cache = createPersistedQueryCache({ storage, userId, shouldPersist: isPersistableQueryKey });
  cache.restore(queryClient); // synchronous with localStorage: no pending frame
  const stop = cache.persist(queryClient);
  setSavedCopyStore(createSavedCopyStore({ storage, userId }));
}

Sur React Native, passez AsyncStorage comme storage. restore renvoie alors une promesse.

Le magasin de copies enregistrées ne conserve que les captures du serveur : le miroir de la transcription que l’API écrit à la fin d’un tour. La transcription en direct n’est jamais écrite sur l’appareil, afin qu’un tour arrêté ne puisse pas réapparaître comme étant en cours. Une lecture du runtime qui ne renvoie aucun message conserve les messages enregistrés à l’écran : cela signifie que l’ordinateur a perdu son état, pas que la conversation est vide. La première lecture du runtime contenant des messages les réconcilie.

Déconnexion et changement de compte

Le SDK conserve en mémoire l’état des sessions par utilisateur : transcriptions, questions et autorisations en attente, reçus de tours et choix de modèles. Appelez resetIdentityState() à chaque changement d’identité : déconnexion et connexion d’un autre utilisateur. Cela inclut une connexion dans un autre onglet qui change l’utilisateur sans rechargement de page.

Appelez ce gestionnaire lorsque votre flux d’authentification connecte ou déconnecte un utilisateur.

import { resetIdentityState } from '@beeuni/sdk/react';

let previousUserId: string | null = null;

function onIdentityChange(userId: string | null) {
  if (userId !== previousUserId) {
    queryClient.clear();
    resetIdentityState();
  }
  previousUserId = userId;
}

resetIdentityState() supprime également l’entrée localStorage du magasin de modèles. Il ne vide pas les caches propres à l’hôte, comme React Query, ni la source de jetons transmise à createBeeuni. Réinitialisez-les dans le même gestionnaire. Il ne lève jamais d’exception.

Avec les magasins de Afficher depuis le cache lors d’un rechargement, videz-les dans le même gestionnaire : await cache.clear(), puis await savedCopies.clear() et setSavedCopyStore(null). Aucun des deux magasins ne restaure de données pour un autre utilisateur, mais un appareil déconnecté ne doit pas les conserver.

Suite

  • Sessions — le handle de session encapsulé par useSession et les types BeeuniSendError.
  • Référence — l’ensemble de l’interface REST utilisée en lecture par ces hooks.

Historique enregistré pendant le démarrage

useSession(projectId, sessionId) affiche l’historique de discussion enregistré pendant le démarrage de son ordinateur. Le SDK lit la base de données indépendamment de la disponibilité de l’environnement d’exécution. Les messages en direct sont ensuite rapprochés à l’aide de leurs identifiants d’origine. Les hôtes n’ont pas besoin d’une requête d’historique ni d’un magasin de messages distincts.

L’historique enregistré s’affiche exactement comme la transcription en direct : texte, raisonnement et chaque appel d’outil avec son entrée, sa sortie et son erreur. La vue complète d’un sous-agent lit la transcription enregistrée propre à ce sous-agent : transmettez la portée du parent et savedChild: true à useSessionSync(subAgentSessionId, { beeuniSessionScope, savedChild: true }). La fenêtre initiale contient les 40 messages les plus récents, dans la limite de 1 000 000 de caractères. Faire défiler vers le haut charge des fenêtres plus anciennes de l’historique enregistré, même lorsque l’ordinateur est éteint. Les pièces jointes qui nécessitent l’ordinateur deviennent disponibles lorsque l’environnement d’exécution est prêt.

savedTranscript indique à l’hôte quoi afficher pendant le démarrage de l’ordinateur. Il vaut loading tant qu’une copie enregistrée peut encore arriver, shown une fois que les messages sont dans messages, et none lorsque rien ne peut s’afficher avant la réponse de l’environnement d’exécution. Un état inconnu vaut loading, jamais none.

conversationEmpty vaut true lorsqu’il n’y a rien à attendre. La copie enregistrée prouve que la conversation est vide : une lecture complète de l’environnement d’exécution de la session n’a trouvé aucun message. Aucun tour ne s’est terminé depuis, et rien n’est ouvert ni en file d’attente. Des enregistrements manquants ne le font jamais passer à true ; une ancienne session avec un historique n’est donc jamais affichée comme vide. Une session obtient cette preuve à son premier démarrage avec l’historique enregistré activé.

if (s.messages.length === 0) {
  // Nothing saved and nothing to wait for: the user can type now.
  if (s.conversationEmpty) return <Composer />;
  // One round trip for a saved copy; the computer can take minutes.
  return s.savedTranscript === 'none' ? <Booting stage={s.stage} /> : <MessageSkeleton />;
}

Les appels d’outils enregistrés avant le 2026-09-28 ont perdu leurs entrées et sorties. Le serveur fournit chacun d’eux avec l’entrée attestée par le titre ou les métadonnées conservés : la commande et la sortie d’une commande, le chemin d’un appel de fichier, le motif d’une recherche, la description d’un sous-agent, l’URL d’une récupération, une liste de tâches, le nom d’une compétence. Au prochain démarrage de la session, l’historique entier est à nouveau enregistré, à l’identique.

Prompts en attente

useSessionPrompts(projectId, sessionId) soumet les prompts à la boîte de réception persistante de la session. Le serveur exécute automatiquement les prompts en attente, chacun dans son propre tour.

Transmettez placement: 'transcript' pour afficher un message en attente dans la conversation. Il s’exécute avant chaque entrée composer et met fin à la réponse active après la fin de l’appel d’outil en cours. Transmettez placement: 'composer' pour le conserver dans la liste modifiable au-dessus du champ de saisie. Il attend que la réponse active se termine. Chaque emplacement conserve l’ordre de soumission. Transmettez delivery: 'steer' | 'queue' | 'interrupt' pour indiquer comment le prompt parvient à un tour en cours. steer le transmet au tour à son étape suivante ; le tour ne s’arrête pas. queue attend la fin du tour. interrupt met fin au tour après l’outil en cours. Avec seulement delivery, le SDK envoie l’emplacement qu’il implique : interrupt correspond à transcript, les autres à composer. Une ligne de réorientation qui ne peut pas réorienter affiche delivery: 'queue' avec steer_fallback défini sur unsupported, not_prompter ou turn_ended. interrupt(promptId) (« Stop and send ») transforme une ligne en attente en entrée de transcription ; une ligne déjà en cours de transmission renvoie 409.

L’éditeur web envoie avec Entrée sous la forme steer lorsqu’un tour est en cours, et comme un envoi dans la transcription lorsque la session est inactive. Commande+Entrée (Ctrl+Entrée sous Windows/Linux) utilise l’emplacement de l’éditeur. Maj+Entrée insère un saut de ligne.

Les lignes de la liste incluent full_text pour des aperçus complets après rechargement. text reste l’aperçu limité destiné aux anciens clients. Les octets des pièces jointes sont exclus des réponses de liste. La suppression renvoie le prompt complet pour permettre une annulation sans perte.

Transmission en attente et réponses actives

useSessionWorking() conserve state: 'working' tant qu’un prompt attend dans la boîte de réception persistante. Cela maintient Stop disponible. pendingDelivery: true signale un prompt encore en cours de transmission vers l’environnement d’exécution ; l’application web affiche un indicateur d’activité dès que state vaut working, quelle que soit la valeur de cet indicateur. Les tours actifs et l’activité récente de l’environnement d’exécution l’effacent. Une annulation ayant expiré ne confirme pas l’arrêt de l’exécution.

La prise en charge par un worker vérifie uniquement l’admission et laisse le prompt en attente. La transmission commence après une admission réussie. Un tour actif confirmé efface la présentation en attente, même si l’instantané précédent de la boîte de réception répertorie encore ce prompt. L’activité de l’environnement d’exécution préserve l’identifiant de message du tour actif pendant ce transfert.

L’éditeur web nomme Commande/Ctrl+Entrée Queue List et l’action « Stop and send » d’une ligne Quick Queue. Les entrées Quick Queue s’exécutent en premier. Une entrée Quick Queue en attente est une bulle teintée après les tours transmis, sans texte d’état. Les entrées Queue List restent modifiables jusqu’au début de la transmission. Le serveur récupère les événements de fin manqués à partir de preuves exactes de l’environnement d’exécution, y compris après rechargement, sans considérer un environnement d’exécution inaccessible comme un tour terminé.

Chaque pression distincte sur Entrée affiche immédiatement son prompt en attente, même si une demande d’acceptation précédente reste sans réponse. Seul un échec de transmission ajoute du texte : sa cause, Retry et Remove. La boîte de réception du serveur reste responsable de l’ordre d’exécution.

Le hook lit les modifications de la file d’attente depuis le flux de contrôle de la session (GET .../sessions/:id/events?channels=control), avec une connexion par session, quel que soit le nombre de composants qui le montent. Chaque écriture d’une ligne de la boîte de réception arrive sous forme de trame beeuni.control.queue. L’interrogation périodique GET .../prompts ne s’exécute que lorsque ce flux n’est pas connecté.

Pourquoi un tour s’est terminé

La transcription d’un tour interrompu ne contient que MessageAbortedError. Le plan de contrôle conserve ce qu’il sait de la fin de chaque tour : la cause indiquée par la sandbox, par exemple SandboxMemoryGuard, et les tours qui se sont arrêtés sans cause indiquée. Un arrêt demandé par quelqu’un — le bouton Stop, abort(), un prompt envoyé dans une session occupée — est enregistré comme une demande et n’est jamais signalé comme un échec.

useSessionTurnOutcome(projectId, sessionId) renvoie last_ended, recent_failures et l’heure de lecture atMs depuis le cache que useSessionWorking() maintient à jour. Il n’effectue aucune requête. Transmettez le résultat à turnEndNotice, avec ce que la transcription indique sur le tour :

const outcome = useSessionTurnOutcome(projectId, sessionId);
const notice = turnEndNotice(outcome, turn.userMessage.info.id, {
  hasError: Boolean(turnError),
  isAbort: turnErrorIsAbort,
});
// notice: { kind: 'sandbox-memory', usedPct: 97, detail: 'sandbox memory at 97% …' }
//       | { kind: 'cause', name: 'SomeGuard', message: '…' }
//       | { kind: 'unexplained' }
//       | null

L’hôte associe chaque kind à son propre texte et n’analyse jamais le message de la sandbox. null signifie « afficher ce que la transcription affiche » : une véritable erreur reste affichée, une interruption n’affiche rien. Un échec inexpliqué n’est signalé que lorsque la lecture survient quelques secondes après la fin du tour, car la cause arrive souvent une trame après l’interruption. turnEndCause(outcome, messageId) renvoie la cause brute enregistrée, ou null.

Cette page vous a-t-elle été utile ?