Après chaque requête — complétions de clavardage, plongements, images, audio, reclassement, vidéo et soumissions de lots — un enregistrement peut partir vers des destinations que vous configurez : un webhook signé, un collecteur OpenTelemetry, un compartiment compatible S3, Langfuse ou Datadog. Jusqu’à dix par organisation, chacune avec son taux d’échantillonnage, réglées sous Observabilité dans votre espace de travail ou par l’API ci-dessous.
Ce que reçoit une destination
{
"type": "request.completed",
"request": {
"id": "gen-...",
"created_at": "2026-11-01T14:03:11.412Z",
"finished_at": "2026-11-01T14:03:13.907Z",
"requested_model": "anthropic/claude-sonnet-5",
"served_model": "anthropic/claude-sonnet-5",
"provider": "anthropic",
"status": "completed",
"finish_reason": "stop",
"error_code": null,
"streamed": true,
"is_byok": true,
"cache_hit": false,
"usage": {"prompt_tokens": 812, "completion_tokens": 240, "cached_tokens": 0},
"cost_usd": 0.00604,
"latency_ms": {"ttft": 410, "generation": 2495, "routing_overhead": 18},
"key_name": "production",
"workspace_id": null,
"agent": "claude-code",
"session_id": null,
"run_id": null,
"app": null
}
}output.destination_id y voit livrer le résultat de chaque exécution terminée, en enveloppe agent.run.completed.L’enregistrement est relu un instant après la fin de la réponse ; il porte donc ce que le règlement a écrit : le modèle servi, le coût, et cache_hit quand la mémoire cache des réponses a répondu. Aucune requête n’attend rien de tout cela ; une destination lente ou en panne ne coûte que ses propres livraisons.
Webhooks
Un POST du JSON ci-dessus vers votre URL https, avec X-Autonomous-Relay-Event: request.completed et, la destination ayant été créée avec un secret de signature (chaque webhook en a un), X-Autonomous-Relay-Signature :
t=1793000000,v1=5f1d... # HMAC-SHA256 over "<t>.<raw body>", hex, keyed by the signing secret
import { createHmac, timingSafeEqual } from 'node:crypto';
export function verify(rawBody, header, secret) {
const t = /(?:^|,)t=(\d+)/.exec(header)?.[1];
const v1 = /(?:^|,)v1=([0-9a-f]+)/.exec(header)?.[1];
if (!t || !v1) return false;
const expected = createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');
return expected.length === v1.length && timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
}- Le secret de signature est renvoyé une seule fois, dans la réponse qui a créé la destination, et jamais plus.
- Les deux en-têtes sont aussi envoyés sous leurs anciens noms,
X-AgentsRouter-EventetX-AgentsRouter-Signature, avec les mêmes valeurs. header_nameetheader_valueajoutent un en-tête à vous, par exemple un jeton porteur ; la valeur est scellée à l’arrivée et l’API en montre les quatre derniers caractères.- Une livraison que le réseau, un 429 ou un 5xx fait échouer est réessayée, au plus trois fois en tout, après une courte attente aléatoire ; tout autre refus est définitif. Les champs
last_attempt_at,last_success_at,last_http_statusetlast_errorde la destination rapportent l’issue finale.
OpenTelemetry
Une destination otlp reçoit une trace (span) par requête en OTLP/HTTP JSON à l’URL donnée, nommée chat <model> et attribuée selon les conventions sémantiques GenAI (gen_ai.request.model, gen_ai.response.model, gen_ai.usage.input_tokens, gen_ai.usage.output_tokens, gen_ai.response.finish_reasons), le reste de l’enregistrement en attributs autonomousrelay.* et session.id. L’identifiant de trace dérive de l’identifiant de la requête : une livraison réessayée est la même trace, pas un double. Une requête échouée est une trace en état d’erreur.
Stockage compatible S3
Une destination s3 écrit des objets JSON délimités par des sauts de ligne — chaque ligne étant l’enregistrement qu’un webhook reçoit — vers AWS S3, Cloudflare R2, Backblaze B2, MinIO ou l’API XML de Google Cloud Storage. Les enregistrements sont regroupés par destination et écrits à 500 enregistrements, à 4 Mo, ou 60 secondes après le premier. url est le point d’accès du stockage (p. ex. https://s3.us-east-1.amazonaws.com), avec s3_region, s3_bucket, un s3_prefix facultatif, s3_path_style quand le point d’accès l’exige, et la paire de clés d’accès (s3_access_key_id, s3_secret_access_key, scellée). Les téléversements sont signés en SigV4.
Langfuse et Datadog
- Langfuse :
langfuse_public_key(pk-lf-…) etlangfuse_secret_key(sk-lf-…), eturlcomme hôte — le nuage européen de Langfuse si omis, ouus.,jp.,hipaa.cloud.langfuse.com, ou le vôtre. Chaque requête devient une trace à une génération, envoyée au point d’accès OpenTelemetry que Langfuse documente ; la génération a le modèle, l’usage, le coût, le niveau et le délai du premier jeton, et ni entrée ni sortie. - Datadog :
datadog_site(datadoghq.com,us3.,us5.,datadoghq.eu,ap1.,ap2.,uk1.ou les sites gouvernementaux américains) etdatadog_api_key. Chaque requête devient un journal,service:autonomousrelay, étiqueté par modèle, fournisseur et statut, avec l’enregistrement en attributs.
L’API
curl -X POST https://autonomousrelay.com/v1/broadcast \
-H "Authorization: Bearer $AUTONOMOUSRELAY_MANAGEMENT_KEY" \
-H 'content-type: application/json' \
-d '{"kind": "webhook", "url": "https://hooks.example.com/relay", "name": "warehouse", "sample_rate": 1}'kind est webhook, otlp, s3, langfuse ou datadog ; sample_rate (au-dessus de 0, au plus 1) envoie cette part des requêtes. PATCH change disabled, sample_rate et name ; tout le reste est une nouvelle destination. /test envoie tout de suite un enregistrement synthétique et répond {"delivered", "http_status", "error"}. Tout rôle lit la liste ; créer, changer et retirer des destinations exige config:write, puisqu’elles décident où les métadonnées des requêtes quittent la passerelle.
Journalisation des entrées et des sorties
Distincte de la diffusion, et désactivée : conserver les invites et les complétions de clés choisies pour votre propre relecture (GET /v1/generation/:id/content). Ses réglages — les clés, une rétention d’au moins 90 jours, un verrou — peuvent être préparés dès maintenant, mais enabled: true est refusé dans cette version en attendant un examen de protection de la vie privée ; aucun contenu n’est donc conservé aujourd’hui. Clés de gestion seulement : une clé d’inférence ne peut pas changer ce qui est consigné sur son propre trafic.