Décision agentique gouvernée
Une décision agentique Touba est un choix effectué dans un périmètre déclaré. Le runtime ne demande pas à l’hôte de décider à sa place, mais il ne donne pas non plus à l’agent une liberté non bornée.
user objective
-> Touba agent
-> controlled model input
-> capabilities authorized by AIR
-> configured decision provider
-> structured selection
-> runtime verification
-> execution or refusal
-> trace
Ce que le runtime fait
Quand l’exécution atteint un agent, le runtime :
- lit les capacités déclarées dans
uses; - construit une entrée modèle structurée ;
- sépare instruction développeur, données utilisateur, contenus externes et interface de ressources ;
- indique qu’un catalogue de capacités est disponible ;
- envoie le catalogue complet seulement si le provider le demande ;
- peut accepter une réponse directe si aucune capacité n’est nécessaire ;
- reçoit une cible
target_refet, si nécessaire, des arguments ; - vérifie que la cible appartient bien à
uses; - vérifie
callable_bysi la cible est un autre agent ; - vérifie que les arguments correspondent à la signature de la cible ;
- exécute la capacité, retourne la réponse directe ou refuse avant tout handler ;
- remet le résultat intermédiaire au modèle comme observation pour la décision suivante ;
- trace la décision.
Cette boucle réduit la charge côté développeur : l’hôte n’a plus à reconstruire manuellement le catalogue, extraire un choix, vérifier le périmètre puis réinjecter la décision dans Touba.
Deux représentations provider, une seule autorité runtime
Le SDK peut représenter le choix du modèle de deux façons :
| Interface | Représentation fournisseur |
|---|---|
structured | objet de décision produit depuis un schéma ; comportement par défaut |
native | appel de fonction natif pendant la phase catalogue ; choix explicite de l’hôte |
Cette différence ne modifie ni la syntaxe .tb, ni l’AIR, ni le protocole
touba-agent-decision-v1. En interface native, le SDK ne donne pas d’exécuteur
au modèle : il normalise sa proposition, puis le runtime applique les mêmes
contrôles et réalise seul l’exécution.
Le tutoriel Utiliser les appels natifs sous autorité Touba montre la configuration et le cycle complet.
Catalogue à la demande
Le runtime ne transmet pas forcément tous les contrats à chaque décision.
Premier échange :
{
"protocol": "touba-agent-decision-v1",
"mode": "summary",
"model_input": {
"protocol": "touba-agent-model-input-v1",
"mode": "orientation",
"developer_instruction": {
"source": "air_agent_responsibility",
"text": "Find and summarize public datasets."
},
"content_boundary": {
"developer_instruction_authority": "instruction",
"user_input_authority": "domain_data_only",
"external_content_authority": "untrusted_content"
},
"user_input": {
"category": "domain_data",
"keys": ["request"]
},
"resources_hint": {
"capabilities_available": true,
"capability_count": 2,
"catalog_available_on_request": true
}
},
"agent_ref": "agent:examples.research/Researcher",
"capability_count": 2,
"capability_refs": [
"skill:examples.research/SearchDatasetOnly",
"skill:examples.research/BuildDatasetBrief"
],
"input_keys": ["request"]
}
Pour une entrée simple comme une salutation, le provider peut répondre sans demander le catalogue :
{
"action": "answer_directly",
"source": "ai_sdk_structured_output",
"reason": "No Touba resource is required.",
"result": "Hello."
}
Si le provider a besoin du détail, il répond :
{
"action": "request_capabilities",
"source": "ai_sdk_structured_output",
"reason": "I need to compare the available contracts."
}
Le runtime envoie alors le catalogue autorisé : kind, signatures, champs de
types locaux, type de sortie, grants requis, handles de secrets, accès mémoire
et sous-capacités. Une capacité peut être une function, un tool, une
skill, un agent ou une strategy si elle est déclarée dans uses. Chaque
capacité exposée au provider doit avoir une description source explicite ;
sinon le runtime refuse avant l’appel modèle. Cette règle donne au provider un
signal sémantique stable sans affaiblir le contrôle runtime.
Pour un agent exposé à un autre agent, le catalogue peut inclure sa
responsabilité, ses sous-capacités résumées et ses règles callable_by. Cela
permet de traiter la délégation multi-agents comme une capacité gouvernée, pas
comme un appel libre.
Boucle séquentielle
Un agent peut consommer plusieurs ressources pendant une même exécution. Après chaque ressource autorisée, le runtime renvoie une observation au modèle :
{
"agent_state": {
"step_index": 1,
"observation_count": 1,
"observations": [
{
"target_ref": "skill:examples.research/SearchDatasetOnly",
"result": {
"datasets_count": 3
}
}
]
}
}
L’observation sert à décider de la suite : répondre, demander le catalogue, appeler une autre capacité autorisée ou demander un review humain. Les traces indiquent qu’un résultat est disponible, mais elles n’écrivent pas l’observation brute.
Sélection avec arguments
Le provider peut choisir une capacité et renseigner ses entrées :
{
"action": "select_capability",
"target_ref": "skill:examples.research/BuildDatasetBrief",
"source": "openai_structured_output",
"reason": "The request requires search followed by summarization.",
"arguments": {
"request": {
"query": "firefighter",
"rows": 1,
"dry_run": true,
"llm_model": "gpt-4.1-nano",
"goal": "Find a public dataset and produce a short summary in English."
}
}
}
Le runtime vérifie que BuildDatasetBrief est bien dans uses. Il vérifie aussi
que request est un input déclaré par la capacité. Une entrée inconnue ou
manquante provoque un refus avant exécution.
Review humain demandé par l’agent
Le modèle peut demander un review humain en mode catalogue :
{
"action": "request_human_review",
"target_ref": "human_review",
"source": "openai_structured_output",
"reason": "The result should be confirmed before continuing.",
"review_prompt": "Validate the selected dataset before synthesis."
}
Ce mécanisme est différent de human.approve. human.approve est une barrière
imposée par le programme. request_human_review est une possibilité que l’agent
peut demander ; le runtime suspend si aucune décision humaine n’est disponible,
puis reprend seulement avec une décision explicite.
Provider JavaScript
@touba/sdk fournit un adaptateur pour l’AI SDK :
import { createAiSdkDecisionProvider } from "@touba/sdk";
import { model } from "./model-provider.mjs";
export const decideAgentCapability = createAiSdkDecisionProvider({
model,
});
export const provider_metadata = {
provider_kind: "sdk_ai",
provider_name: "researcher-provider",
provider_version: "1.0.0",
model_family: "openai",
prompt_template_id: "researcher-v1",
decision_schema_version: "touba-agent-decision-v1",
};
Le choix du fournisseur reste côté projet. Touba conserve son propre protocole et le runtime revalide la décision. Le scénario Données Québec utilise le helper OpenAI du SDK pour démontrer un chemin d’exécution réel avec un fournisseur configuré explicitement.
Le runtime trace un digest de requête rédigée, les metadata provider non
secrètes, les appels provider tentés, les retries bornés et les refus de budget
max_provider_calls. Ces traces n’exposent pas les valeurs brutes envoyées au
modèle.
Décision et concurrence
Chaque agent enchaîne ses décisions séquentiellement. Une capacité choisie peut
être une stratégie ou une skill contenant un groupe parallel ; une stratégie
peut aussi distribuer des entrées sur un agent typé. Les branches isolent leurs
observations et partagent les budgets du run, sans élargir uses ni
callable_by. Une même capacité reste réutilisable tant qu'elle est autorisée.
Les interfaces SDK structured et native changent la représentation présentée
au modèle, pas cette autorité runtime. Le guide SDK
explique leur configuration et le tutoriel multi-agent
montre la composition et la reprise.
Les transferts libres de session, l'ordonnancement distribué et les plafonds monétaires stricts ne font pas partie de ce mécanisme.