Spec de l'enveloppe wire
Les trois SDK (Python, Node, Go) envoient exactement la même enveloppe
JSON vers POST /api/v1/ai/ingest avec Authorization: Bearer aiv_....
Vous pouvez aussi poster directement sans SDK ; l’enveloppe est le
contrat.
Endpoint
Section intitulée « Endpoint »POST /api/v1/ai/ingestHost: api.monsys.aiAuthorization: Bearer aiv_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxContent-Type: application/jsonEnveloppe top-level
Section intitulée « Enveloppe top-level »{ "trace_id": "uuid", // UUIDv4 client (requis) "root_op": "rag.chat", // texte libre (requis) "status": "ok" | "error" | "partial", // (requis) "started_at": "2026-05-12T09:50:00Z", // RFC3339 (requis) "ended_at": "2026-05-12T09:50:01Z", // RFC3339 (optionnel) "user_session_hash": "", // SHA256 de session id, optionnel "sampling_decision": "full", // "full" | "head" | "summary" "spans": [ ... ] // 1..N spans (requis)}{ "span_id": "uuid", "parent_span_id": "uuid", // "" pour root "op": "openai.chat", "provider": "openai", "model": "gpt-4o-mini", "started_at": "...", "ended_at": "...", "status": "ok", // "ok" | "error" | "refused" | "partial" "input_tokens": 42, "output_tokens": 17,
"prompt": "...", // brut — rédigé sur le hub "completion": "...", // brut — rédigé sur le hub "system_msg": "...", "tool_io": "...",
"attributes": { ... }, "events": [ { ... }, ... ]}Canaux agent (events)
Section intitulée « Canaux agent (events) »Un agent, c’est plus qu’un prompt et une completion. Ce qu’un outil renvoie, quel schéma d’outil le modèle voit et ce qu’il écrit en mémoire sont les canaux par lesquels arrivent l’injection indirecte, l’empoisonnement d’outils MCP et l’empoisonnement de mémoire. Vous les consignez comme événements typés sur un span ; le hub hache et expurge le contenu comme pour les prompts, recherche des indicateurs d’injection déterministes et suit la dérive des schémas MCP. monsys ne bloque rien (ADR-0009, ADR-0029).
"events": [ { "kind": "tool_call", "name": "read_email", "args": { "folder": "inbox" }, "at": "2026-10-30T09:00:00Z" }, { "kind": "tool_result", "name": "read_email", "result": "…texte vu par le modèle…" }, { "kind": "mcp_schema", "server": "crm", "name": "delete_user", "description": "Deletes a user by id", "input_schema": { "type": "object", "properties": { "id": { "type": "string" } } } }, { "kind": "memory_write", "store": "vector", "key": "customer-404", "content": "…" }]| kind | obligatoire | traitement par le hub |
|---|---|---|
tool_call |
name, args |
hash + expurgation ; statistiques d’outils |
tool_result |
name, result |
hash + expurgation ; indicateurs d’injection |
mcp_schema |
server, name, description, input_schema |
hash canonique ; alerte de dérive au changement ; indicateurs sur la description |
memory_write |
store, key, content |
hash + expurgation ; indicateurs d’injection |
Indicateurs (regex, pas de modèle) : ignore_previous, role_override,
system_prompt_exfil, tool_invocation, secrecy, hidden_html,
zero_width, markdown_exfil, shell_pipe, prompt_delimiters,
base64_blob. Une correspondance crée une alerte ai_injection dans la
boîte d’actions ; un schéma modifié crée ai_mcp_drift et compte comme
dérive de configuration dans le Trust Score jusqu’à confirmation. Tout
atterrit haché dans l’evidence pack (agent_events.jsonl, mcp_schemas.json).
Helpers SDK : Python span.tool_call(), span.tool_result(),
span.mcp_schema(), span.memory_write() ; Node span.toolCall() etc. ;
Go span.ToolCall() etc.
Noms canoniques providers
Section intitulée « Noms canoniques providers »| Provider | Valeur provider |
|---|---|
| OpenAI | openai |
| Anthropic Claude | anthropic |
| Google Gemini | google |
| Mistral AI | mistral |
| Azure OpenAI | azure |
| Local (Ollama) | ollama |
Les autres providers sont acceptés mais n’ont pas de lookup tarifaire (coût = 0).
Lookup tarifaire
Section intitulée « Lookup tarifaire »À l’ingestion, le hub cherche ai_model_pricing par (provider, model).
Match exact : les nouveaux modèles non présents dans la table donnent
total_cost_micro_eur = 0. Demandez une mise à jour via
info@be-hosted.be (changelog tarifaire : bientôt).
La ligne tarifaire utilisée est épinglée par span via une FK
pricing_snapshot_id : un backfill des prix ne change pas les coûts
historiques.
{ "received": true, "trace_id": "uuid", "spans": 3, "pii_hits": 1, "total_cost_micro_eur": 603290}Statuts HTTP :
200: traité (voir body)401: token invalide ou révoqué403:ai_observability_enabled = false400: enveloppe invalide5xx: erreur côté hub ; le SDK ne retry pas
Exemple curl
Section intitulée « Exemple curl »curl -X POST https://api.monsys.ai/api/v1/ai/ingest \ -H "Authorization: Bearer aiv_xxxx" \ -H "Content-Type: application/json" \ -d '{ "trace_id": "0e22…", "root_op": "test", "status": "ok", ... }'Compat OpenTelemetry GenAI
Section intitulée « Compat OpenTelemetry GenAI »Nous mappons les conventions sémantiques OTel GenAI sur cette enveloppe en interne mais n’acceptons pas encore OTLP directement. Raison : l’overhead binaire OTLP/HTTP est surdimensionné pour un-call-par-trace. Si vous avez une stack OTel-only, écrivez un adaptateur léger OTel span → notre enveloppe (voir envelope-from-otel.md : bientôt).