Exportation d’observabilité

Un point d’accès /v1 pour tous les fournisseurs. Pointez votre client OpenAI vers une autre URL et une clé, avec vos clés et 0 % de majoration.

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

json
{
  "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
  }
}
Des métadonnées seulement. L’enregistrement n’a aucun champ pour une invite ou une complétion ; aucune destination ne peut donc en recevoir. La passerelle ne conserve pas le contenu des requêtes (Ce que nous conservons), et une diffusion n’est pas un moyen de le contourner. La seule exception est délibérée, et vôtre : un agent hébergé dont la définition nomme un 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
javascript
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-Event et X-AgentsRouter-Signature, avec les mêmes valeurs.
  • header_name et header_value ajoutent 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_status et last_error de 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-…) et langfuse_secret_key (sk-lf-…), et url comme hôte — le nuage européen de Langfuse si omis, ou us., 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) et datadog_api_key. Chaque requête devient un journal, service:autonomousrelay, étiqueté par modèle, fournisseur et statut, avec l’enregistrement en attributs.

L’API

GET/v1/broadcast
POST/v1/broadcast
PATCH/v1/broadcast/:id
DELETE/v1/broadcast/:id
POST/v1/broadcast/:id/test
curl
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

GET/v1/logging
PUT/v1/logging

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.