Parler à un hub
Connectez-vous, posez une question, listez ce que le hub comprend et envoyez des énoncés, des actions et des codes.
Fait partie de Fonctions des SDK. Chaque appel ci-dessous est montré dans chaque langage qui l’offre.
Réutiliser une connexion et présenter ses compétences
Section intitulée « Réutiliser une connexion et présenter ses compétences »Les sept SDK gérés offrent HubSession et HubSessionPolicy pour une connexion
réutilisable, des abonnements conservés et des délais de reconnexion et de sondage configurables.
Fournissez une fabrique de clients connectés et fermez la session quand son propriétaire se termine.
Un Ask ou un Emit à l’issue incertaine n’est pas rejoué automatiquement : c’est l’application qui décide
s’il est sûr de réessayer une action. Un nettoyage qui échoue bloque tout remplacement jusqu’à ce
que cette connexion ait été retirée.
Utilisez Inventory, Skill et Intent pour une vue présentable des compétences
découverts et des exemples adaptés aux paramètres régionaux. InventoryCache ajoute un stockage privé,
facultatif et borné, avec une durée de vie (TTL) d’une heure par défaut; une prise en charge
de langue inconnue dans le catalogue reste inconnue. L’ordre explicite des langues est conservé
à la sérialisation JSON. Cette vue est distincte de la réponse native de l’inventaire des intentions.
Consultez les exemples de session gérée et de cache pour Python, Node, Go, Rust, Kotlin, .NET et Swift. MCP renvoie la vue de présentation dans le bail d’identité de chaque outil. Le C embarqué laisse les sessions et le stockage à l’appelant.
Créer un client du runtime
Section intitulée « Créer un client du runtime »Utilisez un client du runtime une fois que vous avez les éléments d’identité.
Gardez les clés enregistrées par le SDK dans un stockage privé et persistant. Utilisez une identité par processus client qui s’exécute en même temps. Une reconnexion s’authentifie de nouveau avec la même identité et les mêmes clés enregistrées; un échec de connexion n’est jamais une raison de les supprimer. Chaque page de SDK nomme son option de stockage.
from thalovant import ThalovantClient
client = ThalovantClient(identity, protocol="wss")client.connect()print(client.healthcheck())client.close()const client = new ThalovantClient(identity, { protocol: "wss" });await client.connect();console.log(await client.healthcheck());await client.close();client, err := thalovant.NewClientWithOptions(identity, thalovant.ClientOptions{ Protocol: thalovant.ProtocolWSS,})if err != nil { log.Fatal(err)}
if err := client.Connect(ctx); err != nil { log.Fatal(err)}fmt.Println(client.Healthcheck())client.Close(ctx)use thalovant::{Client, HubProtocol};
let client = Client::with_protocol(identity.clone(), HubProtocol::Wss)?;client.connect().await?;println!("{:?}", client.healthcheck().await);client.close().await?;Utilisez un gestionnaire de contexte, try/finally ou defer pour que les connexions se ferment de façon fiable. En Rust, fermez le client avant de propager une erreur de requête : ? quitte immédiatement la fonction en cours et n’attend pas le nettoyage de la connexion. Les appelants concurrents se joignent à la disponibilité authentifiée, chacun dans son propre délai. Un appelant en file d’attente qui est annulé ne doit pas fermer la connexion active.
Noms des fonctions d’aide du runtime
Section intitulée « Noms des fonctions d’aide du runtime »Ces fonctions d’aide couvrent les mêmes parcours dans les transports pris en charge par chaque SDK de haut niveau. Les fonctions d’extension Kotlin exigent import com.thalovant.sdk.*.
| Parcours | Python | Node.js | Go | Rust | Kotlin / Swift | .NET |
|---|---|---|---|---|---|---|
| Requête routée et réponses en cascade | query | query | Query | query | query | QueryAsync |
| Réutiliser une session de conversation | conversation | conversation | Conversation | conversation | conversation | Conversation |
| Attendre un événement corrélé | wait_for_event | waitForEvent | WaitForEvent | wait_for_event | waitForEvent | WaitForEventAsync |
| Observer un flux d’événements | listen | on | Listen | listen | listen | ListenAsync |
| Se connecter et inspecter la disponibilité | connect_with_info | connectWithInfo | ConnectWithInfo | connect_with_info | connectWithInfo | ConnectWithInfoAsync |
| Poser une question avec des indications de langue, de pipeline et d’emplacement | ask | ask | AskWithOptions | ask_with_hints | askWithHints | AskWithHintsAsync |
| Construire l’emplacement d’une requête | build_location | buildLocation | BuildLocation | build_location | buildLocation | ThalovantContext.BuildLocation |
| Rendre un modèle d’intention prononçable | speakable | speakable | Speakable | speakable | speakable | ThalovantContext.Speakable |
| Décoder un événement audio intégré | audio_bytes | audioBytes | AudioBytes | audio_bytes | audioBytes | AudioBytes |
| Lire les ID des pipelines qui ont répondu | reply.pipeline_ids | reply.pipelineIds | reply.PipelineIDs() | reply.pipeline_ids() | reply.pipelineIds | reply.PipelineIds |
| Lire les ID des compétences qui ont répondu | reply.skill_ids | reply.skillIds | reply.SkillIDs() | reply.skill_ids() | reply.skillIds | reply.SkillIds |
| Inspecter la revendication indicative de la réponse | reply.claimed | reply.claimed | reply.Claimed() | reply.claimed() | reply.claimed | reply.Claimed |
Pour l’écoute, Kotlin utilise un Flow, Swift un AsyncThrowingStream et .NET un IAsyncEnumerable. Leurs tampons contiennent au plus 64 événements et signalent explicitement tout débordement. Annulez ou terminez le flux pour retirer son abonnement. En Swift, l’abonnement commence à l’appel de listen; en .NET, il commence à l’énumération. Consultez le guide de chaque langage pour les unités de délai et les paramètres d’annulation.
Ask accepte une parole différée dans une limite donnée; Query suit son ID de requête à travers les réponses en cascade et attend la fin. Une intention manquée de façon non bloquante peut se rattraper quand la parole arrive. Un refus de politique ferme et un délai de requête explicite restent des échecs, et la parole partielle est conservée. Les fonctions d’aide de conversation réutilisent la session tout en créant un nouvel ID de requête et un contexte fusionné à chaque requête. Une reconnexion ne rejoue jamais automatiquement une requête de l’application.
Les ID de réponse sont des chaînes non vides, dans l’ordre de première apparition. Une réponse réussie venue seulement d’un repli conserve son texte et son statut de réussite, mais indique claimed=false; une réponse réussie sans marques d’étape conserve l’ancien comportement de revendication. Les réponses en échec ou non traitées ne sont jamais revendiquées. Les métadonnées de revendication ne vérifient pas l’identité du pair. Consultez revendications de réponse pour la correspondance et le comportement face aux marques mal formées.
Le C embarqué offre thalovant_ask_event_pipeline_id(), thalovant_ask_event_skill_id() et thalovant_reply_claimed(), avec des tampons fournis par l’appelant et une agrégation des ID. Les résumés du runtime de MCP exposent pipelineIds, skillIds et claimed au moyen du SDK Node.
Poser une question à un hub
Section intitulée « Poser une question à un hub »Utilisez ask pour un échange requête-réponse unique.
reply = client.ask("What can this hub do?")
print(reply.text)for item in reply.display_items(): print(item)const reply = await client.ask("What can this hub do?");
console.log(reply.text);for (const item of reply.displayItems()) { console.log(item);}reply, err := client.Ask(ctx, "What can this hub do?", thalovant.RequestOptions{})if err != nil { log.Fatal(err)}
fmt.Println(reply.Text)for _, item := range reply.DisplayItems(600) { fmt.Println(item)}let reply = client .ask("What can this hub do?", RequestOptions::default()) .await?;
println!("{}", reply.text);for item in reply.display_items(Some(600)) { println!("{item:?}");}Forme de la sortie attendue :
{ "text": "This hub can answer quick joke and trivia requests.", "display_items": []}Lister ce qu’on peut demander à un hub
Section intitulée « Lister ce qu’on peut demander à un hub »Utilisez intents quand un client doit montrer aux gens ce que le hub comprend, ou confirmer qu’une compétence s’est enregistrée. Le hub répond dans la session du client lui-même, avec chaque intention, par langue, et les phrases qui y mènent. Aucun jeton du plan de contrôle n’est en jeu. La connexion doit avoir le droit de publier ovos.intent.list, ainsi que ovos.intent.describe quand le SDK doit demander les phrases séparément, ce qu’un hub qui les renvoie avec la liste ne l’oblige jamais à faire. Consultez Que peut-on demander à mon hub?.
from thalovant import ThalovantPolicyDeniedError
try: inventory = client.intents(["en-us", "fr-fr"])except ThalovantPolicyDeniedError as denied: print("refused:", denied.denied_type, "allowed:", denied.allowed) raise
for intent in inventory.intents: print(intent.id, intent.examples("en-us"))Forme de la sortie attendue :
{ "languages": ["en-us", "fr-fr"], "source": "intent-manifest", "denied": [], "skills": [ { "skill_id": "thalovant-skill-weather.thalovant", "languages": ["en-us", "fr-fr"], "intents": [ { "id": "thalovant-skill-weather.thalovant:current.weather", "skill_id": "thalovant-skill-weather.thalovant", "name": "current.weather", "engine": "padatious", "enabled": true, "phrases": { "en-us": ["what is the weather", "what is the weather in {location}"], "fr-fr": ["quel temps fait-il", "quelle est la météo à {location}"] } } ] } ]}Une requête refusée lève aussitôt l’erreur de politique du SDK, qui nomme le type de message, au lieu d’attendre l’expiration du délai. Quand ovos.intent.list est refusé et que le repli est activé, ce qui est le cas par défaut, le résultat ne contient que les noms, avec source réglé à engine-manifests. Un hub qui accepte une requête et y répond avec ok: false est un cas différent. Une liste en échec lève l’erreur de runtime du SDK avec le texte d’erreur du hub, parce qu’une liste en échec n’est pas un hub vide. Une description en échec, elle, laisse cette seule intention sans phrases et ne lève rien. Chaque SDK publié offre cette recette sous sa propre graphie; chaque page de SDK donne un exemple fonctionnel, et la page des SDK indique la version dans laquelle chacun l’a livrée.
Les SDK de haut niveau actuels utilisent le repli par défaut sur les manifestes des moteurs quand ovos.intent.list expire. Dans ce cas, denied nomme la requête restée sans réponse, ce qui ne prouve pas un refus de politique. Désactivez le repli pour propager l’expiration de la liste; les moteurs de repli silencieux produisent quand même une expiration. Consultez la découverte des intentions.
Émettre un événement brut
Section intitulée « Émettre un événement brut »Utilisez des événements bruts quand vous avez déjà un nom d’événement et une charge utile structurée.
client.emit( "thalovant.client.status", {"state": "ready"}, {"source": "checkout-kiosk"},)await client.emit( "thalovant.client.status", { state: "ready" }, { source: "checkout-kiosk" },);err := client.Emit(ctx, "thalovant.client.status", map[string]any{ "state": "ready",}, map[string]any{ "source": "checkout-kiosk",})if err != nil { log.Fatal(err)}use serde_json::json;
let mut data = serde_json::Map::new();data.insert("state".into(), json!("ready"));
let mut context = serde_json::Map::new();context.insert("source".into(), json!("checkout-kiosk"));
client .emit("thalovant.client.status", data, context) .await?;Envoyer un énoncé
Section intitulée « Envoyer un énoncé »Utilisez un énoncé quand l’entrée doit se comporter comme de la parole ou du texte de clavardage venant d’un client.
client.send_utterance( "What is the status?", lang="en-us", session_id="status-session",)await client.sendUtterance("What is the status?", { lang: "en-us", sessionId: "status-session",});err := client.SendUtterance(ctx, "What is the status?", thalovant.RequestOptions{ Lang: "en-us", SessionID: "status-session",})if err != nil { log.Fatal(err)}client .send_utterance( "What is the status?", RequestOptions { lang: Some("en-us".into()), session_id: Some("status-session".into()), ..Default::default() }, ) .await?;Envoyer une action
Section intitulée « Envoyer une action »Utilisez des actions pour les boutons, les choix de menu, les confirmations et les commandes d’outils.
client.send_action( "/approve invoice-42", title="Approve invoice", session_id="approval-session",)await client.sendAction( "/approve invoice-42", { title: "Approve invoice", sessionId: "approval-session" },);err := client.SendAction(ctx, "/approve invoice-42", thalovant.ActionOptions{ Title: "Approve invoice", SessionID: "approval-session",})if err != nil { log.Fatal(err)}client .send_action( "/approve invoice-42", ActionOptions { title: Some("Approve invoice".into()), session_id: Some("approval-session".into()), ..Default::default() }, ) .await?;Envoyer un code
Section intitulée « Envoyer un code »Utilisez une entrée de code pour les valeurs de code QR, les lectures de codes-barres, les numéros de série, les codes courts ou les valeurs exactes saisies au clavier.
client.send_code( "INV-2026-001", kind="invoice", session_id="scan-session",)await client.sendCode("INV-2026-001", { kind: "invoice", sessionId: "scan-session",});err := client.SendCode(ctx, "INV-2026-001", thalovant.CodeOptions{ Kind: "invoice", SessionID: "scan-session",})if err != nil { log.Fatal(err)}client .send_code( "INV-2026-001", CodeOptions { kind: Some("invoice".into()), session_id: Some("scan-session".into()), ..Default::default() }, ) .await?;Tenir une conversation
Section intitulée « Tenir une conversation »Utilisez une conversation quand des tours liés doivent partager la même session.
with client.conversation(lang="en-us") as convo: print(convo.ask("Remember that my favorite color is blue.").text) print(convo.ask("What color did I mention?").text)const convo = client.conversation({ lang: "en-us" });
const first = await convo.ask("Remember that my favorite color is blue.");const second = await convo.ask("What color did I mention?");console.log(first.text, second.text);convo := client.Conversation(thalovant.ConversationOptions{Lang: "en-us"})
first, err := convo.Ask(ctx, "Remember that my favorite color is blue.", thalovant.RequestOptions{})if err != nil { log.Fatal(err)}second, err := convo.Ask(ctx, "What color did I mention?", thalovant.RequestOptions{})if err != nil { log.Fatal(err)}fmt.Println(first.Text, second.Text)let convo = client.conversation(ConversationOptions { lang: Some("en-us".into()), ..Default::default()});
let first = convo .ask("Remember that my favorite color is blue.", RequestOptions::default()) .await?;let second = convo .ask("What color did I mention?", RequestOptions::default()) .await?;println!("{} {}", first.text, second.text);Rendre des exemples d’intentions adaptés à la langue
Section intitulée « Rendre des exemples d’intentions adaptés à la langue »Avec les versions actuelles prises en charge des SDK,
Python utilise sentence=True avec l’extra facultatif de listes. Node accepte
{ sentence: true } dans intent.examples(lang, limit, options).
Go utilise IntentExampleOptions{Sentence: true} avec ExamplesWithOptions;
Rust utilise IntentExampleOptions avec examples_with_listing.
Kotlin, Swift et .NET offrent examplesWithListing / ExamplesWithListing.
MCP offre sentence sur thalovant_intent_inventory.
Ces moteurs de rendu utilisent les échantillons de variables propres à la langue avant les valeurs imposées par l’appelant, préfèrent les phrases complètes et comptent les résultats uniques non vides dans les limites de rendu. Les exemples bruts sans limite conservent l’ordre d’enregistrement. Les SDK gérés intègrent les mêmes données que celles de l’extra de listes de Python. Consultez le guide de chaque SDK pour la signature de son appel et ses options de règles personnalisées.