Analyse de l'identité
Analysez le JSON d’identité émis par l’API Thalovant, avec les mêmes alias de champs que ceux qu’acceptent les SDK Node et Go.
Créez un client d'appareil C99 pour les hubs Thalovant avec votre propre transport MQTT ou WebSocket.
Utilisez la bibliothèque C embarquée quand votre client est un microcontrôleur ou un petit appareil, comme un ESP32, un appareil Zephyr, un système sans système d’exploitation (bare-metal) ou un ordinateur monocarte sous Linux.
Il s’agit d’une bibliothèque de protocole, pas d’un SDK complet. Elle est indépendante du transport : vous apportez votre propre client MQTT ou WebSocket et votre propre pile TLS, et la bibliothèque fournit tout ce qui est propre au protocole. Elle est écrite en C99 pur, sans aucune dépendance externe, et ses chemins principaux n’allouent jamais de mémoire; chaque fonction écrit dans des tampons fournis par l’appelant.
Code source et versions : thalovant-embedded-c sur GitHub.
La bibliothèque donne à un appareil tout ce qu’il lui faut pour ouvrir une session chiffrée et authentifiée avec un hub; votre application fournit les sockets ou la connexion au courtier et pilote l’échange. Les anciennes fonctions d’enveloppe restent disponibles pour les intégrations existantes, mais elles ne peuvent pas se connecter à un hub actuel.
Analyse de l'identité
Analysez le JSON d’identité émis par l’API Thalovant, avec les mêmes alias de champs que ceux qu’acceptent les SDK Node et Go.
Sujets MQTT
Dérivez les sujets (topics) MQTT propres à chaque client, les points de terminaison de connexion, les ports et les identifiants de client, identiques octet pour octet à ceux du SDK Node.
Chiffrement des données utiles
Chiffrement authentifié de chaque message, vérifié avec des vecteurs de test indépendants.
Tramage sur le réseau
Construisez et analysez les messages du hub, menez l’échange d’authentification et chiffrez chaque message, avec des fonctions pour les requêtes ask et leurs réponses.
| Vous fournissez | La bibliothèque fournit |
|---|---|
| Un client MQTT, WebSocket ou les deux | Les sujets, les points de terminaison, les codecs de trames et d’enveloppes |
| Une pile TLS | L’indicateur TLS ainsi que l’analyse du schéma et du port |
| Un générateur aléatoire cryptographiquement sûr | Vous fournissez une clé de client persistante et une nouvelle clé éphémère pour chaque connexion; la bibliothèque gère les compteurs de messages |
| Une boucle d’événements et des minuteries | Le classificateur de trames et la sémantique de la boucle ask |
| Un stockage protégé pour l’identité, la clé du client et l’identité de hub enregistrée | L’analyseur d’identité et un échange d’authentification qui vérifie l’identité de hub enregistrée |
La bibliothèque n’a pas de client pour le plan de contrôle. Créez l’identité de client au moyen du tableau de bord, de l’API ou d’un autre SDK, puis stockez le JSON d’identité sur l’appareil.
Utilisez un nouvel identifiant de requête Ask et un nouvel identifiant Query pour chaque opération logique, y compris les appels ultérieurs. Gardez les identifiants simultanés uniques dans chaque espace de noms correspondant; les espaces de noms Ask et Query sont indépendants. Cette bibliothèque laisse la gestion des collecteurs à votre transport. Vérifiez chaque résultat négatif d’un constructeur ou d’un codec avant de convertir une longueur ou de publier des octets.
L’analyseur superficiel de clés d’objet valide l’objet direct au complet avant de retourner un champ correspondant, y compris les séparateurs qui suivent ce champ. Les conteneurs imbriqués conservent leurs règles d’analyse superficielle documentées.
Intégrez la bibliothèque à votre dépôt (vendoring) ou récupérez-la par une étiquette de version immuable. L’étiquette actuelle est v0.8.0.
git submodule add https://github.com/thalovant/thalovant-embedded-c.git \ third_party/thalovant-embedded-cgit -C third_party/thalovant-embedded-c checkout v0.8.0FetchContent de CMake, les références de composants ESP-IDF et les manifestes west de Zephyr fonctionnent de la même façon avec l’étiquette v0.8.0. Chaque version comprend une archive des sources et un fichier SHA256SUMS pour vérifier votre téléchargement.
La compilation n’exige qu’un compilateur C99 :
make # build/libthalovant.amake test # host-side, offline test suiteConsultez le guide d’intégration du dépôt pour l’API complète et la séquence de transport :
thalovant_noise_select.thalovant_noise_psk. Il faut 64 Mio de mémoire de travail uint64_t appartenant à l’appelant, que la fonction efface ensuite. Un appareil plus petit doit recevoir le même secret par un provisionnement sécurisé, après une dérivation faite hors de l’appareil; n’affaiblissez jamais la dérivation.thalovant_noise_init, votre clé de client protégée, une nouvelle clé éphémère générée de façon cryptographiquement aléatoire et toute identité de hub enregistrée. Échangez les messages d’authentification avec thalovant_noise_write et thalovant_noise_read.thalovant_noise_encrypt et déchiffrez les réponses avec thalovant_noise_decrypt avant de les classer. Toute erreur d’authentification ou de tramage ferme la session.Votre transport doit garder ensemble tous les fragments d’un même message, plafonner les trames chiffrées à 65 535 octets et découper les grosses données utiles en fragments de 65 000 octets. Réassemblez-les dans un tampon borné appartenant à l’appelant, d’au plus 32 Mio; choisissez une limite plus petite si l’appareil l’exige. Une reconnexion exige une nouvelle clé éphémère, tout en conservant la clé du client et l’identité de hub enregistrée.
Un client connecté peut lister chaque intention à laquelle son hub répond, par langue, avec les phrases qu’une personne prononce pour atteindre chacune, dans sa propre session et sans jeton du plan de contrôle. Consultez Que peut-on demander à mon hub? pour savoir ce que le hub retourne, quels types de messages la connexion doit être autorisée à publier, et à quoi ressemblent un refus ou une liste en échec.
Depuis la version v0.2.0, la bibliothèque prend en charge le côté protocole de cette fonction, dans le même style que thalovant_ask_*. thalovant_intent_list_build_frame et thalovant_intent_describe_build_frame construisent les trames ovos.intent.list et ovos.intent.describe, et thalovant_intent_classify lit une réponse dans un thalovant_intent_event. Votre transport scelle et envoie les trames, lui retransmet les réponses et les met en correspondance grâce à l’identifiant de requête que vous définissez.
struct inventory_query { const char *request_id; bool answered; };
static bool on_row(const thalovant_intent_registration *row, void *user){ printf("%s:%s (%s) %s\n", row->skill_id, row->intent_name, row->lang, row->method); return true; /* false stops the walk */}
struct inventory_query query = { "req-2", false };thalovant_intent_list_request list = { "en-us", "sess-1", identity.site_id, query.request_id, false };if (thalovant_intent_list_build_frame(&list, frame, sizeof(frame)) < 0) { /* THALOVANT_ERR_NOMEM: frame[] too small; nothing was built to send */}/* seal and publish the frame, then classify each reply that arrives */
thalovant_intent_event reply;thalovant_intent_classify(plaintext, plaintext_len, query.request_id, &reply);switch (reply.kind) {case THALOVANT_INTENT_LIST_RESPONSE: if (query.answered) break; /* ignore a duplicate reply */ query.answered = true; thalovant_intent_list_rows(&reply, on_row, NULL); break;case THALOVANT_INTENT_POLICY_DENIED: /* reply.denied_type names the query */ break;default: break; /* THALOVANT_INTENT_IGNORE */}Les fonctions de parcours livrent un élément à la fois au moyen d’une fonction de rappel : un manifeste de n’importe quelle taille se lit donc dans une mémoire bornée. thalovant_intent_list_rows parcourt les enregistrements, thalovant_intent_definitions une réponse de description, et thalovant_intent_samples les phrases derrière une définition. thalovant_intent_same_language normalise les étiquettes de langue comme le font les autres SDK : fr-fr et fr_FR correspondent donc. Le method d’une ligne vaut template ou keyword, que les SDK complets exposent comme les moteurs padatious et adapt.
Un refus arrive sous la forme THALOVANT_INTENT_POLICY_DENIED, avec le type refusé dans reply.denied_type. Une liste que le hub a acceptée puis n’a pas réussi à produire est un cas différent : depuis la v0.3.0, thalovant_intent_list_rows retourne THALOVANT_ERR_HUB_REFUSED avec les mots du hub dans reply.error, parce qu’une liste en échec n’est pas un hub vide. thalovant_intent_definitions retourne zéro définition pour la même réponse à une description, qui est une vraie réponse : le hub ne connaît pas cet enregistrement. La mise en correspondance, les nouvelles tentatives et le modèle de résultat sont à votre charge; consultez Que peut-on demander à mon hub? pour la structure que les SDK complets construisent à partir des mêmes réponses.
Utilisez Python, Node.js, Go ou Rust quand l’appareil peut exécuter un environnement d’exécution complet. Ces SDK gèrent pour vous le transport, la logique de reconnexion et les appels au plan de contrôle. Consultez MQTT pour les détails sur le courtier (broker) et la portée des sujets.
| Symptôme | Vérification |
|---|---|
| L’analyse de l’identité échoue | Vérifiez que le JSON stocké est le contenu d’identité intact provenant de l’API ou du téléchargement dans le tableau de bord. |
| Le courtier refuse la connexion | Vérifiez le point de terminaison dérivé, le port et l’indicateur TLS, et utilisez les identifiants de courtier propres au client qui se trouvent dans l’identité. |
| Les réponses ne sont jamais classées | Vérifiez que le sujet d’abonnement est topics.outbound et que l’identifiant de requête correspond à celui envoyé dans la trame ask. |
| L’authentification ou le déchiffrement échoue | Vérifiez le mot de passe, l’identifiant de nœud du serveur, l’identité de hub enregistrée et l’ordre des trames. Fermez la session en échec; ne réessayez pas avec les anciennes enveloppes et ne supprimez pas automatiquement l’identité de hub enregistrée. |
thalovant_fallback_list_build_payload et thalovant_fallback_list_build_frame construisent la liste des gestionnaires de repli. Les deux utilisent thalovant_intent_list_request pour le contexte de session et de requête, et envoient ovos.skills.fallback.list avec un objet de données vide; les gestionnaires ne dépendent pas de la langue. thalovant_intent_classify reconnaît la réponse comme THALOVANT_FALLBACK_LIST_RESPONSE et expose le tableau data.fallbacks par items_json, items_len et count.
L’application gère la sonde facultative de 1,5 seconde, l’analyse des priorités, le tri et le modèle de résultat. Distinguez une réponse indisponible, en échec ou malformée d’une liste explicitement vide. L’absence de phrases d’intention ne suffit pas à établir qu’un hub ne répondra pas. Consultez la découverte des gestionnaires de repli.
La bibliothèque prend en charge GCC, Clang et les cibles 32 bits. Elle utilise C99, des tampons appartenant à l’appelant et le transport que vous fournissez.
thalovant_ask_build_payload_with_hints et thalovant_ask_build_frame_with_hints
acceptent thalovant_ask_hints : stt_lang, un tableau de chaînes JSON pipeline_json
et un objet JSON location_json. Les espaces autour de la langue et des étapes du pipeline sont retirés;
les étapes vides sont omises. Construisez l’objet d’emplacement avec
thalovant_build_location; une ville est obligatoire, et les coordonnées invalides ou nulles sont
omises. Les constructeurs existants conservent leurs octets d’origine sur le réseau.
La trame complète utilise directement le tampon de sortie de l’appelant. Chaque étape de pipeline
décodée doit tenir dans THALOVANT_ASK_TEXT_MAX, terminateur compris;
le JSON des indications doit tenir dans THALOVANT_WIRE_MAX_TOKENS. Ces limites fixées à la compilation gardent
les tampons de l’analyseur lexical et de la normalisation bornés, sans allocation dynamique.
thalovant_speakable rend un motif d’intention dans un tampon appartenant à l’appelant, avec
des remplacements thalovant_speakable_slot facultatifs. Classez les exemples rendus selon
la présence d’emplacements dans le motif d’origine, conservez le meilleur rang lors de la déduplication
et appliquez ensuite la limite demandée.
thalovant_ask_classify reconnaît THALOVANT_ASK_AUDIO sans le traiter comme un
échec. L’audio ne règle ni ne prolonge jamais une requête ask : conservez son ordre à côté de la parole
dans la fenêtre de réponse existante. thalovant_ask_event_language retourne la
première langue non vide trouvée dans les données de l’événement, le contexte ou la session.
thalovant_ask_audio_decode valide la correspondance et ne décode que l’audio hexadécimal
intégré, dans un stockage appartenant à l’appelant; l’espace de travail contient la chaîne
hexadécimale sans échappement. Elle ne lit jamais de fichier ni d’URL. Vérifiez la longueur ou l’erreur retournée avant
de lire les octets. Les limites des tampons peuvent être inférieures au maximum de 4 Mio par extrait.
Initialisez à zéro thalovant_audio_budget pour chaque réponse et appelez
thalovant_audio_budget_accept avant de conserver de l’audio encodé. Cette fonction plafonne chaque
extrait à 4 Mio et l’ensemble des extraits d’une réponse à 16 Mio (bornes supérieures encodées); les extraits
refusés incrémentent dropped et n’ont pas d’effet sur la collecte de la parole. Dédupliquez
les livraisons du transport avant la collecte. La bibliothèque reste indépendante du transport;
la gestion des compétences et de la configuration par le plan de contrôle relève des clients des SDK gérés.
thalovant_ask_event_pipeline_id() et thalovant_ask_event_skill_id() extraient les marques de type chaîne des trames de réponse reconnues et mises en correspondance, dans des tampons fournis par l’appelant. Conservez les identifiants distincts dans l’ordre de première apparition, dans votre propre stockage. thalovant_reply_claimed() classe la réponse selon son statut traité/échec et les identifiants de pipeline conservés. Un NUL intégré est refusé; des tampons insuffisants retournent THALOVANT_ERR_NOMEM.
Les identifiants de pipeline et de compétence sont des chaînes non vides, dans l’ordre de première apparition, sans doublons. Une réponse réussie dont les identifiants de pipeline contiennent tous le texte fallback (sensible à la casse) est signalée comme non revendiquée. Toute étape autre qu’un repli rend une réponse réussie revendiquée. Les réponses réussies de hubs plus anciens, sans marques d’étape, restent revendiquées. Les réponses en échec ou non traitées ne sont jamais revendiquées. Les marques malformées qui ne sont pas des chaînes sont ignorées.
Utilisez cette information comme indice pour décider de poursuivre ou non une conversation. Le texte de repli et le statut de réussite existant sont conservés. Ces marques ne constituent pas une identité de pair vérifiée et ne doivent pas autoriser d’actions.