Aller au contenu
Console
Try one

    SDK Kotlin

    Installez le SDK Kotlin de Thalovant pour les services JVM et les applications Android qui se connectent à un hub.

    Utilisez le SDK Kotlin quand votre client ou votre agent s’exécute sur la JVM ou sur Android.

    Les coordonnées Maven Central sont com.thalovant:thalovant-sdk. Il faut la JVM 17 ou plus récente, ou une chaîne d’outils Android qui produit du bytecode Java 17. Le SDK utilise OkHttp, kotlinx-serialization et kotlinx-coroutines.

    Code source et versions : thalovant-kotlin-sdk sur GitHub.

    Ajoutez la dépendance à votre build Gradle. La version courante figure dans Versions prises en charge.

    dependencies {
    implementation("com.thalovant:thalovant-sdk:0.9.0")
    }

    Ce flux vous connecte, crée une identité de client et envoie une requête par WSS.

    import com.thalovant.sdk.CreateClientIdentityOptions
    import com.thalovant.sdk.ThalovantClient
    import com.thalovant.sdk.ThalovantControlPlane
    import kotlinx.coroutines.runBlocking
    fun main() = runBlocking {
    val api = ThalovantControlPlane()
    api.login("[email protected]", "password")
    val result = api.createClientIdentity(
    "hub-id",
    CreateClientIdentityOptions(name = "kotlin-demo-client"),
    )
    val client = ThalovantClient(result.identity)
    try {
    val reply = client.ask("Tell me a short clean joke.")
    println(reply.text)
    } finally {
    client.close()
    }
    }

    ThalovantControlPlane() utilise https://api.thalovant.com par défaut.

    Se connecter avec l’authentification multifacteur

    Section intitulée « Se connecter avec l’authentification multifacteur »

    Les comptes où l’authentification multifacteur (AMF) est activée doivent fournir un code TOTP ou un code de récupération à usage unique avec la connexion. Sans l’un d’eux, l’API refuse la connexion avec le code HTTP 401 et le code mfa_required.

    api.login("[email protected]", "password", otpCode = "123456")
    // Or use a one-time recovery code instead:
    api.login("[email protected]", "password", recoveryCode = "abcd-efgh-ijkl")

    Les valeurs otpCode et recoveryCode ne sont envoyées que si elles sont fournies.

    La connexion par appareil demande à votre navigateur d’approuver la connexion : les services et les applications ne manipulent donc jamais votre mot de passe. Le SDK affiche un code court et l’adresse https://dash.thalovant.com/activate, ouvre cette page quand il le peut, puis attend que vous approuviez la demande dans le tableau de bord avec votre connexion habituelle, y compris la connexion Google ou l’AMF. Une fois la demande approuvée, le SDK détient un jeton d’API révocable et limité à des portées précises.

    La connexion par appareil exige le SDK 0.1.1 ou plus récent. Approuver la demande exige un forfait payant pour l’espace de travail; un forfait gratuit reçoit le code HTTP 402.

    import com.thalovant.sdk.DeviceLoginOptions
    api.loginWithBrowser(
    DeviceLoginOptions(scopes = listOf("hubs:read"), clientName = "kotlin-demo"),
    )

    Gérez le jeton obtenu sur la page API Tokens du tableau de bord.

    Passez un jeton d’API enregistré quand le processus doit démarrer déjà authentifié, par exemple pour des tâches de CI et des services. Créez-en un sur la page API Tokens ou avec loginWithBrowser; la page affiche les portées, l’expiration et la dernière utilisation, et permet de révoquer le jeton en tout temps.

    val api = ThalovantControlPlane(accessToken = System.getenv("THALOVANT_API_TOKEN"))

    Le SDK se connecte par WSS. Chaque connexion est chiffrée et authentifiée avant l’envoi de quoi que ce soit; la JVM 17 et Bouncy Castle fournissent la cryptographie. HTTPS et MQTT ne sont toujours pas pris en charge.

    Quand il ouvre un WebSocket, le SDK remplace toute valeur de requête authorization existante par l’identité courante. Les autres paramètres de requête et les fragments d’URL sont conservés. Les échecs de connexion omettent les messages d’erreur réseau et les causes qui contiennent des identifiants. Mettez le SDK à jour si un point de terminaison enregistré avec d’anciennes valeurs d’autorisation n’arrive pas à se connecter.

    Par défaut, le SDK garde ses clés dans ~/.config/thalovant-kotlin/noise. Conservez ce répertoire d’une reconnexion et d’un redémarrage à l’autre. Sur Android, fournissez un répertoire privé à l’application :

    import com.thalovant.sdk.HiveMindNoiseStore
    import java.nio.file.Path
    val client = ThalovantClient(
    identity,
    noiseStore = HiveMindNoiseStore(Path.of(appPrivateDirectory, "noise")),
    )

    Le magasin de fichiers exige des permissions POSIX privées là où elles existent et un système de fichiers qui prend en charge les liens physiques, pour que des processus simultanés ne puissent pas voir une clé incomplète. Utilisez des identités distinctes pour des clients simultanés. Un hub dont l’identité a changé ne peut plus se connecter tant que vous n’avez pas confirmé le changement auprès du propriétaire du hub et mis à jour délibérément l’identité enregistrée.

    Utilisez de nouveaux identifiants de requête (request ID) pour Ask et de nouveaux identifiants d’interrogation (query ID) pour Query; les identifiants générés sont la valeur par défaut. Un collecteur concurrent qui porte le même identifiant est refusé sur le même client. Les espaces de noms sont indépendants. Ne réutilisez pas un identifiant pour une opération logique ultérieure, même après une annulation : une réponse en retard peut encore le porter. Réutilisez un identifiant de session pour le contexte de conversation.

    Pour un HTTP 429, examinez ThalovantApiException.statusCode et analysez son body JSON. Le détail imbriqué du serveur contient token_rate_limited pour la limite par minute ou token_quota_exceeded pour un quota quotidien ou mensuel. Respectez son retry_after_seconds avant de réessayer; les réponses de quota indiquent aussi quel quota est épuisé. Le SDK ne fait aucune nouvelle tentative automatique. Gardez la même clé d’idempotence explicite quand vous réessayez une même création logique de hub. Consultez Limites des jetons d’API.

    Cette version se connecte au hub par WSS seulement. Demander https ou mqtt lève ThalovantUnsupportedProtocolException. La sélection du point de terminaison respecte toujours l’ordre de préférence commun wss, https, mqtt : les identités créées pour des hubs multiprotocoles continuent donc de fonctionner.

    Utilisez le SDK Python, Node.js, Go ou Rust quand le client a besoin dès maintenant du plan de données HTTPS ou MQTT.

    Examinez ce qu’une identité prend en charge :

    import com.thalovant.sdk.HubProtocol
    println(identity.enabledProtocols())
    println(identity.endpointFor(HubProtocol.WSS))
    println(identity.mqtt?.endpoint)

    Les fichiers d’identité bruts téléchargés depuis Thalovant fonctionnent directement. Sous Linux et macOS, le SDK refuse les fichiers d’identité que d’autres utilisateurs peuvent lire ou modifier : protégez-les avec chmod 600 et gardez-les hors de Git.

    val client = ThalovantClient.fromIdentityFile("_identity.json")

    Vous pouvez aussi analyser un contenu d’identité que vous avez déjà en mémoire :

    import com.thalovant.sdk.ThalovantIdentity
    val identity = ThalovantIdentity.fromJson(identityJson)

    Les commandes du plan de contrôle qui modifient des données retournent des opérations durables. Interrogez-les avec la fonction typée :

    val operation = api.getOperation("operation-id")
    println(operation.status)

    Consultez Opérations pour le cycle de vie et les conseils sur les nouvelles tentatives.

    import com.thalovant.sdk.ThalovantEvents
    val subscription = client.on(ThalovantEvents.SPEAK) { event ->
    println(event.text)
    }
    // Later, when the listener is no longer needed:
    subscription.close()

    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 le SDK 0.1.8, les appels sont client.intents(languages, options), qui retourne l’inventaire regroupé par compétence, client.listIntents(lang, options), qui retourne les lignes d’enregistrement, et client.describeIntent(skillId, intentName, lang, options), qui retourne les définitions derrière une intention. Les trois sont des fonctions suspend, comme ask.

    import com.thalovant.sdk.ThalovantClient
    import com.thalovant.sdk.ThalovantPolicyDeniedException
    import kotlinx.coroutines.runBlocking
    fun main() = runBlocking {
    val client = ThalovantClient.fromIdentityFile("_identity.json")
    try {
    val inventory = client.intents(listOf("en-us", "fr-fr"))
    println("${inventory.source} ${inventory.languages}")
    for (skill in inventory.skills) {
    for (intent in skill.intents) {
    println("${intent.id} ${intent.engine} ${intent.examples("fr-fr")}")
    }
    }
    } catch (denied: ThalovantPolicyDeniedException) {
    System.err.println("refused ${denied.deniedType}; allowed ${denied.allowed}")
    throw denied
    } finally {
    client.close()
    }
    }

    intents interroge ovos.intent.list une fois par langue, puis complète les phrases que la liste ne contenait pas, par fenêtres d’au plus DESCRIBE_BATCH requêtes, pour qu’un hub qui compte beaucoup d’intentions ne reçoive jamais toute la rafale d’un coup. IntentInventoryOptions porte l’échéance et les options : describe = false s’arrête aux noms, aux moteurs et à l’état d’activation. examples(lang, limit) préfère les phrases complètes à celles qui contiennent un {slot}, puis les formulations plus complètes jusqu’à huit mots; phrasesFor(lang) les retourne toutes, et asJson() écrit le même document que les autres SDK. Les étiquettes de langue se comparent sans tenir compte de la casse ni de _ et - : fr-fr et fr_FR forment donc une seule requête.

    Un hub qui refuse une requête lève immédiatement ThalovantPolicyDeniedException avec deniedType, code, reason et allowed. Avec la valeur par défaut IntentInventoryOptions(fallback = true), un ovos.intent.list refusé retourne plutôt les noms seulement : inventory.source vaut HubIntentSource.ENGINE_MANIFESTS, inventory.denied nomme la requête refusée et inventory.hasPhrases est faux. Un hub qui accepte la liste et y répond avec ok: false lève ThalovantRuntimeException avec le texte d’erreur du hub, parce qu’une liste en échec n’est pas un hub vide. describeIntent retourne une liste vide pour la même réponse, qui est une vraie réponse : le hub ne connaît pas cet enregistrement.

    L’inventaire par défaut se replie aussi sur les noms quand ovos.intent.list reste silencieux. Désactivez le repli pour propager le délai d’attente de cette liste. Le marqueur denied nomme la requête qui a déclenché le repli; il n’établit pas un refus de politique. listFallbacks() expose les gestionnaires de repli enregistrés, et l’inventaire comprend fallbacksKnown et mayAnswer(lang).

    La sonde facultative des gestionnaires de repli prend au plus 1,5 seconde, connexion, envoi et attente de la réponse compris. Une sonde refusée, silencieuse ou explicitement en échec, ou une enveloppe de réponse malformée, laisse la découverte inconnue. Les tableaux acceptés conservent les gestionnaires utilisables et ignorent les lignes invalides. Une liste de gestionnaires connue comme vide et une découverte inconnue sont deux états différents : la disponibilité d’une langue n’est fausse que si aucune intention activée n’a de phrases pour cette langue et qu’une sonde réussie ne signale aucun gestionnaire de repli. La présence d’un gestionnaire de repli ne garantit pas qu’il peut répondre dans toutes les langues.

    Importez com.thalovant.sdk.* pour rendre accessibles les fonctions d’extension du runtime. Une conversation garde un seul identifiant de session et un contexte partagé, tandis que chaque requête reçoit un nouvel identifiant de requête :

    import com.thalovant.sdk.*
    val conversation = client.conversation(sessionId = "checkout", lang = "en-us")
    val reply = conversation.query("Tell me a short clean joke.", timeoutMs = 12000)
    println(reply.text)

    query recueille les réponses query/cascade qui portent l’identifiant d’interrogation correspondant, jusqu’à hive.query.complete. Un échec d’intention non bloquant permet encore de la parole par la suite; un refus de politique et l’expiration de l’interrogation mettent fin à la collecte et conservent toute parole partielle dans une réponse en échec. Son délai d’attente couvre la connexion, l’envoi et la collecte. Les requêtes ne sont jamais rejouées automatiquement.

    Utilisez waitForEvent pour un seul événement correspondant et listen pour un Flow Kotlin. Le flux démarre quand il est collecté et garde en mémoire tampon au plus 64 événements; un débordement signale une erreur. L’expiration du délai, le nombre d’événements, l’annulation de la coroutine et la perte du transport libèrent les abonnements. sendAction et sendCode conservent les métadonnées des entrées structurées. connectionInfo, connectWithInfo, healthcheck et doctor décrivent l’état local de la connexion authentifiée, sans affirmer que chaque compétence distante est en bon état.

    connect(timeoutMs) inclut la mise en file d’attente et l’authentification dans un seul budget; sa valeur par défaut est de 6 000 ms. L’expiration du délai ou l’annulation d’un appelant en file d’attente n’annule pas la tentative de connexion d’un autre appelant.

    Le client du plan de contrôle ne suit jamais les redirections automatiquement, y compris quand un client OkHttp est fourni. Les requêtes qui portent des identifiants ou un corps JSON exigent HTTPS, sauf pour les points de terminaison de développement HTTP explicites localhost, 127.0.0.1 et [::1]. L’état des témoins (cookies) et de l’authentificateur exige aussi un transport sécurisé. Les lectures anonymes sans identifiants ni corps peuvent utiliser HTTP. Les URL qui contiennent des informations d’utilisateur (userinfo) sont refusées avant toute entrée-sortie; configurez directement l’URL finale de l’API.

    La connexion par appareil n’ouvre que des URL de vérification HTTP(S) sans userinfo ni caractères de contrôle. Les intercepteurs et les authentificateurs personnalisés restent du code applicatif de confiance. Les messages d’erreur ordinaires de l’API omettent les corps bruts et les valeurs detail primitives; le body d’erreur explicite reste disponible pour un examen contrôlé.

    ask

    Envoyez une requête et recevez une réponse normalisée, avec un délai d’attente que vous contrôlez.

    sendUtterance

    Envoyez une entrée de type parole ou clavardage sans attendre la réponse.

    emit

    Envoyez un événement nommé avec des données structurées et un contexte.

    getOperation

    Interrogez une commande durable du plan de contrôle avec un statut typé.

    Pour des recettes qui couvrent tous les langages, consultez Fonctions des SDK.

    Depuis le SDK 0.1.3, le plan de contrôle peut créer des hubs, des groupes de runtime et des installations de compétences. Parcourir le catalogue avec listMarketplaceSkills() exige hubs:read et fonctionne avec tous les forfaits. createHub, createRuntimeGroup, installRuntimeGroupSkill, releaseHub et releaseRuntimeGroup exigent hubs:write et un forfait payant.

    val group = api.createRuntimeGroup(RuntimeGroupCreatePayload(name = "kiosks"))
    val hub = api.createHub(
    HubCreatePayload(
    name = "joke-garden",
    spec = buildJsonObject { },
    runtimeGroupId = group["id"]!!.jsonPrimitive.content,
    ),
    )
    val current = api.getHub(hub["id"]!!.jsonPrimitive.content)
    api.updateHub(
    current["id"]!!.jsonPrimitive.content,
    HubUpdatePayload(active = false),
    etag = current["etag"]!!.jsonPrimitive.content,
    )

    updateHub et deleteHub prennent l’etag actuel du hub comme argument obligatoire. Consultez Provisionner des hubs pour le flux complet, les champs immuables et le tableau des erreurs.

    SymptômeVérification
    Missing Thalovant API access tokenAppelez api.login(...) ou api.loginWithBrowser(...) avant les actions privées de l’API, ou passez accessToken à ThalovantControlPlane.
    HTTP 401 avec le code mfa_requiredPassez otpCode ou recoveryCode à api.login(...).
    L’accès à l’API exige un forfait payantPassez l’espace de travail à un forfait supérieur avant de provisionner des ressources privées par l’API.
    ThalovantUnsupportedProtocolExceptionLe hub n’expose pas WSS, ou le code a demandé https ou mqtt, que cette version ne prend pas en charge pour se connecter.
    Une requête expirePassez un timeoutMs plus grand à ask(...).

    Le SDK peut lister, installer, mettre à jour et retirer les compétences du groupe de runtime d’un hub, et en consulter l’historique. Chaque hub qui partage ce groupe de runtime est touché. L’UUID d’un hub sélectionne le groupe; il ne crée pas d’installation isolée pour ce hub. Un jeton restreint doit couvrir tous les hubs servis par le groupe.

    Les lectures exigent hubs:inspect (hubs:read l’inclut). Les écritures exigent hubs:write, un forfait payant admissible et la propriété. Utilisez latest ou une version publiée précise pour l’installation et les mises à jour. Une écriture acceptée retourne un operation_id; l’acceptation ne signifie pas que le runtime a fini d’installer la compétence.

    ActionMéthode
    ListerlistHubSkills
    HistoriquelistHubSkillHistory
    InstallerinstallHubSkill
    Mettre à jourupdateHubSkill
    RetirerremoveHubSkill

    L’historique retourne l’enveloppe JSON de l’API avec des entrées event et operation de la plus récente à la plus ancienne, en préservant les champs acteur/version qui peuvent être nuls. La limite va de 1 à 200.

    Utilisez HubSkillWaitOptions pour choisir d’attendre la fin de l’opération (120 secondes, avec une interrogation toutes les deux secondes par défaut). Pour les appels sensibles à l’annulation, soumettez d’abord sans attendre, conservez la réponse acceptée, puis appelez waitForHubSkillOperation. Annuler l’attente n’annule pas l’opération acceptée par le serveur. En cas d’échec de l’interrogation, l’erreur conserve l’identifiant de l’opération; examinez cette opération au lieu de répéter l’écriture. L’échéance d’attente empêche de nouvelles interrogations, mais n’annule pas une requête déjà en cours.

    Si une attente automatique échoue, HubSkillOperationException.accepted conserve la réponse complète, y compris l’état d’installation ou de retrait. Passez-la à waitForHubSkillOperation pour reprendre. timedOut indique que le budget d’interrogation a expiré; l’annulation de la coroutine se propage normalement.

    Fonctions de requête et mises à jour sûres de la configuration

    Section intitulée « Fonctions de requête et mises à jour sûres de la configuration »

    Disponible depuis la 0.5.0.

    Les indications de requête transmettent une langue reconnue, un pipeline d’intentions ordonné et l’emplacement de l’appelant sans modifier le contexte de l’appelant. Les indications vides sont omises. La fonction d’emplacement exige une ville et omet les coordonnées invalides ou nulles (zéro/zéro). Le hub valide les indications de langue en fonction des langues configurées.

    Les réponses exposent la langue déclarée, les événements de parole et d’audio ordonnés et le nombre de médias abandonnés. Les extraits audio intégrés des compétences sont limités à 4 Mio chacun et à 16 Mio par réponse, vérifiés avant la conservation et le décodage. L’audio ne prolonge pas la fenêtre de stabilisation de la réponse. Le décodage accepte des octets hexadécimaux séparés par des espaces blancs ASCII; il ne récupère jamais une URL ou un chemin de fichier fourni par une compétence. La lecture relève de l’application. Toute fonction play ou Play ci-dessous appartient à votre application.

    val location = buildLocation(city = "Montréal", country = "CA")
    val reply = client.askWithHints("Quel temps fait-il ?", sttLang = "fr-ca", location = location)
    for (event in reply.mediaEvents) if (event.isAudio) play(event.audioBytes())
    val examples = intent.examplesWithOptions("en-us", speakable = true)
    api.updateRuntimeGroupConfig(groupId, delta)
    // Explicit full replacement:
    api.replaceRuntimeGroupConfig(groupId, fullConfig)

    La fusion protégée exige les portées hubs:read et hubs:write et un forfait payant. La fusion sûre exige une API dont le GET de configuration retourne une revision valide et dont le PUT de configuration vérifie expected_revision. Le SDK relit et réapplique le delta d’origine seulement après un HTTP 412, avec au plus trois tentatives. Les tableaux et les valeurs scalaires remplacent; les objets fusionnent récursivement. Les personas ne sont remplacés que s’ils sont fournis explicitement. Les échecs de connexion, les redirections, les autres statuts et les résultats d’écriture ambigus ne font jamais l’objet d’une nouvelle tentative. Aucun repli PATCH non sûr n’est utilisé. Les remplacements inconditionnels doivent tout de même être coordonnés avec les autres rédacteurs.

    Utilisez l’opération de remplacement explicite montrée ci-dessus quand un remplacement complet est voulu, y compris avec une API plus ancienne. Le code existant qui compte sur le remplacement doit l’activer explicitement lors de la mise à jour. Les motifs d’intention bruts restent la valeur par défaut; les exemples prononçables retirent les parties facultatives, choisissent des variantes et substituent les emplacements (slots) fournis par l’appelant tout en conservant la priorité des phrases complètes.

    Les limites audio utilisent des bornes supérieures basées sur la longueur encodée avant le décodage : les espaces blancs de mise en forme consomment donc aussi le budget. Comme avec bytes.fromhex de Python, des espaces blancs ASCII seuls se décodent en zéro octet. Les extraits malformés bornés restent disponibles comme métadonnées d’événement et échouent au décodage; ils ne sont jamais récupérés ni lus automatiquement. Des événements audio distincts peuvent répéter volontairement un contenu sonore identique. Seule la livraison répétée du même objet d’événement est supprimée, là où l’identité des objets est disponible, sans la compter comme un extrait abandonné. Le classement des exemples rendus utilise la présence d’emplacements dans le motif d’origine, même quand des valeurs d’exemple sont fournies.

    Listes d’intentions adaptées aux paramètres régionaux

    Section intitulée « Listes d’intentions adaptées aux paramètres régionaux »

    Disponible depuis la 0.6.3.

    Les listes de phrases utilisent les données intégrées de thalovant-languages 0.2.1 et correspondent à Python 0.6.8 avec son extra de liste. Le choix de la langue suit les distances régionales d’OVOS : une requête pour fr-CA peut donc utiliser des paramètres régionaux fr-FR enregistrés.

    val examples = intent.examplesWithListing("fr-CA", sentence = true)
    val text = asSentence("what time is it", "en-US")
    val sample = speakableWithLanguage("play {song}", lang = "en-US")

    Le rendu en phrase implique le rendu prononçable. Les valeurs d’emplacement explicites remplacent les exemples régionaux. Les phrases complètes passent avant les préfixes et les motifs à emplacements; les exemples rendus vides ou en double ne comptent pas dans la limite. Les exemples bruts sans limite gardent l’ordre d’enregistrement. Les paramètres régionaux inconnus conservent le texte brut et les noms d’emplacements.

    Les méthodes d’exemples existantes restent disponibles. Utilisez ListingRules pour fournir un instantané complet de données personnalisées ou pour choisir un rendu brut sans données régionales. Aucune requête réseau n’est nécessaire pour charger les règles intégrées. Consultez le README du dépôt pour la construction de règles personnalisées et la gestion des erreurs d’expressions régulières.

    Les données de liste décrivent maintenant 270 langues, y compris les variantes régionales. En espagnol, qué hora es devient Qué hora es?, et en français, coupe le son devient Coupe le son.. Les langues sans règles, comme tlh, restent brutes.

    HubSession possède une connexion de hub réutilisable. Fournissez une fabrique qui retourne un client connecté et qui nettoie une tentative de connexion échouée ou annulée. Les abonnements aux événements survivent au remplacement du client. Go et Rust exposent un flux d’événements persistant; les autres SDK gérés exposent des descripteurs d’abonnement. Fermez la session quand son propriétaire s’arrête; la fermeture attend les opérations acceptées et est définitive.

    Les tentatives de connexion en arrière-plan attendent 10, 20, 40, 80, puis 120 secondes entre elles. Les appels au premier plan peuvent tenter immédiatement. Votre application gère la planification des sondes : utilisez le délai de sonde indiqué (60 secondes quand la connexion est retenue, 5 secondes quand elle est coupée). Le SDK ne rejoue jamais un Ask ou un Emit accepté après la perte d’une réponse, parce qu’un Ask peut déclencher une action. Le délai d’attente d’une requête s’applique à l’opération sous-jacente; l’attente de la session et votre fabrique de connexion ont des budgets distincts.

    val session = HubSession(connect = ::connectClient, warm = false)
    try {
    val reply = session.ask("What is the weather?")
    } finally {
    session.close()
    }

    Inventory, Skill et Intent offrent une vue présentable distincte de l’inventaire d’intentions natif du runtime. Les paramètres régionaux inconnus du catalogue restent inconnus; des phrases observées pour une langue ne prouvent pas que le catalogue la prend en charge. Les exemples choisissent les paramètres régionaux pris en charge les plus proches. Une limite non positive retourne l’ensemble brut des phrases (Rust utilise zéro pour sa limite non signée). Le JSON du cache inclut l’ordre explicite des langues des intentions, pour que la sérialisation ne puisse pas changer la langue par défaut des exemples.

    InventoryCache est facultatif, utilise par défaut une durée de vie (TTL) d’une heure et signale une absence dans le cache pour les données invalides, expirées ou illisibles. Les écritures utilisent des fichiers temporaires privés et uniques et un remplacement atomique. Sous POSIX, les fichiers de cache sont lisibles et modifiables par leur propriétaire seulement; Windows utilise les ACL du répertoire de l’utilisateur. Les clés de cache séparent le mode, le chemin de l’identité et le nom d’hôte complet et normalisé du hub. N’utilisez jamais les caches d’inventaire pour stocker des identifiants.

    OriginPreference donne à une adresse privilégiée son propre budget de connexion court et la met en pause après un échec. Dans les SDK autres que Python, la fabrique doit implémenter la liaison à l’adresse sur son propre transport, conserver l’hôte public pour TLS/SNI et terminer le nettoyage des tentatives échouées avant de retourner. Les restrictions du transport et de la plateforme s’appliquent toujours. Cette fonction ne modifie pas le DNS global et ne désactive pas la validation TLS.

    Une réponse expose reply.pipelineIds, reply.skillIds et reply.claimed.

    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.