# Parler à un hub

> Connectez-vous, posez une question, listez ce que le hub comprend et envoyez des énoncés, des actions et des codes.

Source: https://docs.thalovant.com/fr/developers/sdk-functions/talking-to-a-hub/

---
{/* Last Edit: Claude Opus 5.5 - 2026-09-28 - Motive: Canadian French translation of developers/sdk-functions/talking-to-a-hub.mdx. */}

Fait partie de [Fonctions des SDK](/fr/developers/sdk-functions/). Chaque appel ci-dessous est montré dans chaque langage qui l'offre.

## 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](/fr/developers/sdks/python/#sessions-gérées-et-caches-dinventaire),
[Node](/fr/developers/sdks/node/#sessions-gérées-et-caches-dinventaire),
[Go](/fr/developers/sdks/go/#sessions-gérées-et-caches-dinventaire),
[Rust](/fr/developers/sdks/rust/#sessions-gérées-et-caches-dinventaire),
[Kotlin](/fr/developers/sdks/kotlin/#sessions-gérées-et-caches-dinventaire),
[.NET](/fr/developers/sdks/dotnet/#sessions-gérées-et-caches-dinventaire) et
[Swift](/fr/developers/sdks/swift/#sessions-gérées-et-caches-dinventaire).
MCP renvoie la [vue de présentation](/fr/developers/mcp/#sortie-dinventaire-présentable)
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

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](/fr/developers/sdks/) nomme son option de stockage.

  

```python
from thalovant import ThalovantClient

client = ThalovantClient(identity, protocol="wss")
client.connect()
print(client.healthcheck())
client.close()
```

  
  

```ts

const client = new ThalovantClient(identity, { protocol: "wss" });
await client.connect();
console.log(await client.healthcheck());
await client.close();
```

  
  

```go
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)
```

  
  

```rust
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

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](/fr/developers/sdks/python/#revendications-des-réponses) 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](/fr/developers/mcp/#revendication-des-réponses) exposent `pipelineIds`, `skillIds` et `claimed` au moyen du SDK Node.

## Poser une question à un hub

Utilisez `ask` pour un échange requête-réponse unique.

  

```python
reply = client.ask("What can this hub do?")

print(reply.text)
for item in reply.display_items():
    print(item)
```

  
  

```ts
const reply = await client.ask("What can this hub do?");

console.log(reply.text);
for (const item of reply.displayItems()) {
  console.log(item);
}
```

  
  

```go
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)
}
```

  
  

```rust
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 :

```json
{
  "text": "This hub can answer quick joke and trivia requests.",
  "display_items": []
}
```

## 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?](/fr/concepts/hub-intents/).

  

```python
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 :

```json
{
  "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](/fr/developers/sdks/) donne un exemple fonctionnel, et la [page des SDK](/fr/developers/sdks/) 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](/fr/concepts/hub-intents/).

## É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.

  

```python
client.emit(
    "thalovant.client.status",
    {"state": "ready"},
    {"source": "checkout-kiosk"},
)
```

  
  

```ts
await client.emit(
  "thalovant.client.status",
  { state: "ready" },
  { source: "checkout-kiosk" },
);
```

  
  

```go
err := client.Emit(ctx, "thalovant.client.status", map[string]any{
	"state": "ready",
}, map[string]any{
	"source": "checkout-kiosk",
})
if err != nil {
	log.Fatal(err)
}
```

  
  

```rust
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é

Utilisez un énoncé quand l'entrée doit se comporter comme de la parole ou du texte de clavardage venant d'un client.

  

```python
client.send_utterance(
    "What is the status?",
    lang="en-us",
    session_id="status-session",
)
```

  
  

```ts
await client.sendUtterance("What is the status?", {
  lang: "en-us",
  sessionId: "status-session",
});
```

  
  

```go
err := client.SendUtterance(ctx, "What is the status?", thalovant.RequestOptions{
	Lang:      "en-us",
	SessionID: "status-session",
})
if err != nil {
	log.Fatal(err)
}
```

  
  

```rust
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

Utilisez des actions pour les boutons, les choix de menu, les confirmations et les commandes d'outils.

  

```python
client.send_action(
    "/approve invoice-42",
    title="Approve invoice",
    session_id="approval-session",
)
```

  
  

```ts
await client.sendAction(
  "/approve invoice-42",
  { title: "Approve invoice", sessionId: "approval-session" },
);
```

  
  

```go
err := client.SendAction(ctx, "/approve invoice-42", thalovant.ActionOptions{
	Title:     "Approve invoice",
	SessionID: "approval-session",
})
if err != nil {
	log.Fatal(err)
}
```

  
  

```rust
client
    .send_action(
        "/approve invoice-42",
        ActionOptions {
            title: Some("Approve invoice".into()),
            session_id: Some("approval-session".into()),
            ..Default::default()
        },
    )
    .await?;
```

  

## 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.

  

```python
client.send_code(
    "INV-2026-001",
    kind="invoice",
    session_id="scan-session",
)
```

  
  

```ts
await client.sendCode("INV-2026-001", {
  kind: "invoice",
  sessionId: "scan-session",
});
```

  
  

```go
err := client.SendCode(ctx, "INV-2026-001", thalovant.CodeOptions{
	Kind:      "invoice",
	SessionID: "scan-session",
})
if err != nil {
	log.Fatal(err)
}
```

  
  

```rust
client
    .send_code(
        "INV-2026-001",
        CodeOptions {
            kind: Some("invoice".into()),
            session_id: Some("scan-session".into()),
            ..Default::default()
        },
    )
    .await?;
```

  

## Tenir une conversation

Utilisez une conversation quand des tours liés doivent partager la même session.

  

```python
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)
```

  
  

```ts
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);
```

  
  

```go
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)
```

  
  

```rust
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

Avec les [versions actuelles prises en charge des SDK](/fr/developers/sdks/#versions-prises-en-charge),
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](/fr/developers/sdks/) pour la signature
de son appel et ses options de règles personnalisées.
