Metadata-first, enforced at the API
AgentSpeed stores metrics and metadata about your runs, not their contents. This is not just a policy line: there is no prompt or output field in the ingest contract, and known content-bearing keys are stripped at the boundary before anything is parsed, so a client that attaches them out of habit cannot get them stored. One thing stays yours to control — the short error message and log line you choose to send are stored as you send them. Treat those the way you would any log you ship off-box.
This page explains the approach. For the formal document, see our Privacy Policy.
- Run status (succeeded / failed / timeout) and timing
- Latency, and p50/p95 rollups
- Token counts and computed cost
- A quality score (a number 0–1) when you choose to send one
- Model name, agent name, span names, tool names
- Error type and the short error message you send
- Log-line severity and a short message label
- Prompts or system prompts
- Model outputs / completions
- Message or conversation content
- Retrieved documents or tool inputs/outputs
- Anything under prompt, output, messages, content, choices, …
- There is no content field. The ingest contract has no prompt, completion, or message-content field on a run, span, or event. The two free-text fields it does have — a short error message and a short log line, both capped at 2,000 characters — are written by you and stored verbatim. We cannot tell prompt text from a log line, so those are the one place content can land, and only because you put it there.
- Known content keys are stripped before validation. A denylist drops fields like
prompt,completion,messages,content,output, and their variants, recursively, even if your SDK attaches them by habit. They are removed before anything is parsed. - The schema is strict. After stripping, validation runs in strict mode, so any remaining unrecognized key is rejected with a 422 rather than quietly stored.
- We log that it happened, not what it was. When a content key is stripped we record the key name (e.g.
prompt), never its value, so the drop is auditable without leaking anything.
A run report is just this. There is nowhere in it for prompt or output text:
curl -X POST https://agentspeed.com/api/v1/runs \
-H "Authorization: Bearer $AGENTSPEED_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"agent": "checkout-assistant",
"status": "succeeded",
"model": "claude-opus-4-8",
"inputTokens": 1200,
"outputTokens": 340,
"costUsd": 0.0185,
"score": 0.92,
"outcome": "converted",
"promptVersion": "checkout-v3",
"durationMs": 4200,
"idempotencyKey": "run_123",
"spans": [
{
"name": "vector search",
"type": "retrieval",
"status": "ok",
"durationMs": 180,
"order": 0
},
{
"name": "completion",
"type": "llm",
"status": "ok",
"durationMs": 4000,
"order": 1,
"inputTokens": 1200,
"outputTokens": 340
}
],
"events": [
{
"level": "info",
"message": "order #4823 placed"
}
]
}'Journey canaries follow the same rule: a run records each step's pass/fail and timing, not the page contents it read or any prompt used to evaluate it.