Docs · Référence
API publique
Le contrat TypeSafe, à l'identique, plus des extensions préfixées x_. Toutes sont optionnelles : un client TypeSafe qui les ignore fonctionne.
Base URL : https://<domaine> en externe, http://gateway:8080 depuis le réseau Docker. Routes publiques sous /v1/*, administration sous /admin/v1/*, santé sous /health et /health/ready.
Authentification
Chaque appel porte Authorization: Bearer jaas_<prefix>_<secret>. Le préfixe fait 8 caractères [a-z0-9], le secret 32 caractères base62. La gateway vérifie un hash argon2id du secret (poivré côté serveur), l'expiration et la révocation. Chaque réponse porte l'en-tête x-typesafe-request-id.
POST /v1/systemone
Évalue un state contre des questions typées. Coût quota : 1 + nombre de questions.
Requête
{
"state": "string | object | array",
"model": "kev-0.8b",
"questions": {
"department": { "type": "choice", "instructions": "…", "criteria": { "billing": "…", "shipping": null } },
"urgent": { "type": "noul", "instructions": "…", "criteria": { "true": "…", "false": "…" } },
"tone": { "type": "score", "instructions": "…", "criteria": ["calm", "annoyed", "angry"] }
},
"x_template": { "id": "ticket-triage", "version": 3, "variables": { "subject": "…", "body": "…" } },
"x_schema": { "id": "triage", "version": 2 }
}| Champ | Type | Rôle |
|---|---|---|
state | string | object | array | Le contexte à évaluer. Ignoré (peut être omis) si x_template est présent. |
model | string | Accepté et renvoyé tel quel. Le backend est choisi par le schéma. Un model inconnu (jev-latest, kev-latest…) n'est pas une erreur. |
questions | map nom → question | Format TypeSafe : type, instructions, criteria. Ignoré si x_schema est présent, obligatoire sinon. |
x_template | { id, version?, variables } | Slug du template ; version par défaut : dernière publiée. La gateway rend le state à partir des variables. |
x_schema | { id, version? } | Slug du schéma ; version par défaut : dernière publiée. |
Types de question
| type | criteria | Limites |
|---|---|---|
choice | map option → description (ou null) | 1 à 255 options, 20 au plus recommandé |
score | tableau ordonné de niveaux | 2 à 10 niveaux |
noul | { true, false } optionnel | question oui/non |
- Nombre de questions ≤
JEVIS_MAX_QUESTIONS(32 par défaut). State ≤JEVIS_MAX_STATE_CHARS(32 000 caractères par défaut). - Sans
x_schema, l'empreinte structurelle des questions inline doit correspondre à une version publiée d'un schéma autorisé pour l'application. Voir l'empreinte.
Réponse
{
"model": "kev-0.8b",
"answers": {
"department": { "type": "choice", "choice": "billing", "probabilities": { "billing": 0.81, "shipping": 0.19 }, "confidence": 0.81 },
"urgent": { "type": "noul", "noul": 0.93 },
"tone": { "type": "score", "score": 1.2, "legend": { "0": "calm", "1": "annoyed", "2": "angry" },
"probabilities": { "0": 0.1, "1": 0.6, "2": 0.3 }, "confidence": 0.6, "x_abstain": true }
},
"usage": { "input_tokens": 101, "output_tokens": 12 },
"x_decision_id": "019a1b2c-…",
"x_backend": "kev-0.8b-cpu",
"x_schema": { "id": "triage", "version": 2 },
"x_schema_version": 2,
"x_template": { "id": "ticket-triage", "version": 3 },
"x_latency_ms": { "gateway": 212, "backend": 187 }
}| Champ | Rôle |
|---|---|
answers.*.confidence | max(probabilities) après température. Pour noul : max(noul, 1 − noul), implicite. |
answers.*.x_abstain | true quand la confiance est sous abstain_threshold de la version de schéma. La réponse est conservée. |
usage | Relayé du backend s'il le fournit, sinon omis. |
x_decision_id | UUIDv7 de la décision enregistrée. Sert pour l'outcome. |
x_backend | Nom du backend qui a répondu. |
x_schema | { id, version } du schéma utilisé. |
x_schema_version | La version en entier, toujours présente (utilisée par la console et les logs). |
x_template | { id, version } si un template a été rendu. |
x_latency_ms | { gateway, backend } en millisecondes. |
Erreurs
Un format unique, pour l'API publique comme pour l'admin :
{ "error": { "code": "schema_not_granted", "message": "…", "details": {} } }| HTTP | code | Quand |
|---|---|---|
| 401 | invalid_api_key | Clé absente, invalide, expirée ou révoquée. |
| 403 | schema_not_granted | Le schéma résolu n'est pas autorisé pour l'application. |
| 404 | not_found | Décision inconnue ou appartenant à une autre application. |
| 409 | conflict | Outcome déjà enregistré avec une autre valeur. |
| 422 | validation_error | Corps invalide (types, bornes, question inconnue…). |
| 422 | invalid_schema | Schéma ou questions invalides. |
| 422 | template_render_error | Variables manquantes ou mal typées, rendu Jinja en échec. |
| 429 | rate_limited | Rate limit par minute dépassé. En-tête Retry-After. |
| 429 | quota_exceeded | Quota journalier dépassé. En-tête Retry-After. |
| 503 | backend_unavailable | Aucun réplica du backend ne répond. |
POST /v1/decisions/{id}/outcome
La valeur réellement observée, par question.
{ "answers": { "department": "billing", "urgent": true, "tone": 2 }, "source": "agent-ui" }{ "decision_id": "019a1b2c-…", "recorded": ["department", "urgent", "tone"] }- Valeur par question : clé d'option (
choice), booléen (noul), index de niveau entier (score). - Idempotent : même valeur déjà enregistrée → 200 ; valeur différente → 409
conflict. Question inconnue → 422. - L'application appelante doit être propriétaire de la décision, sinon 404.
GET /v1/decisions/{id}
Renvoie la décision avec ses réponses et ses outcomes, pour l'application propriétaire. Le state n'est inclus que si l'application a log_state activé.
GET /v1/models
Compatible TypeSafe et kev. Un modèle par backend activé. Authentification requise.
{ "models": [ { "name": "kev-0.8b", "description": "…", "release_date": "…" } ] }Santé
Sans authentification : GET /health → { "status": "ok" }, et GET /health/ready → { "status": "ok", "database": true, "redis": true } ou 503.
/admin/v1/*) est décrite dans le contrat complet du dépôt : doc/api-contract.md.