Refusals v1
- URI:
https://standards.upperhandai.com/ext/refusals/v1 - Kind: declarative AgentCard extension + runtime data Part
- Media type:
application/vnd.upperhand.refusal+json - Status: Current
- Since: 2026-08-18
Purpose
An agent that will not compute something must say so as typed data, not prose — so callers can pre-filter their requests, workbenches can render the refusal visibly, and evals can assert it. A refusal is intentional, correct behavior: it is never a protocol error and never a fabricated answer.
This extension has two halves: a card-level advertisement of the agent's refusal posture, and a runtime Part emitted when a refusal fires.
Card declaration
{
"uri": "https://standards.upperhandai.com/ext/refusals/v1",
"required": false,
"description": "Rules this agent will not compute. Callers should not request these; the agent refuses with a typed Part if asked anyway.",
"params": {
"seg-mix": "Segmentation families cannot be crossed; ask for one family per cut.",
"invalid-cut": "That demographic cut is not defined for this study."
}
}
params is a flat object mapping rule id (kebab-case string) to a
one-line, user-facing reason. The same map is the agent's single source
of truth: the card, the agent's system prompt, and its tool-level guards
must agree (see STD-010 §3.3 for the internal enforcement rule).
Runtime Part
When a refusal fires, the agent emits two Parts in its response message:
- a
text/plainPart carrying the user-facing reason, so plain clients degrade gracefully; - a data Part with media type
application/vnd.upperhand.refusal+json:
{
"rule": "seg-mix",
"reason": "Segmentation families cannot be crossed; ask for one family per cut.",
"detail": "Requested cut combined Polaris segment with news ideology."
}
rule(required) — MUST match a key advertised in the card declaration.reason(required) — the advertised one-liner.detail(optional) — per-call context.
A refused request is a successful protocol exchange: the JSON-RPC response is a normal result, not an error object. When a tool result is refused, the refusal Parts replace that result's text/json/ui/citation Parts entirely.
Consumer requirements
- MUST render refusals visibly, naming the rule — never silently drop them, and never substitute generated content for a refused answer.
- MUST NOT retry a refused request unchanged.
- SHOULD use the card's advertised map to avoid asking for refused computations in the first place.
Conformance (probed)
- Card
paramsis a non-empty flat string→string map with kebab-case keys. - A provoked refusal round-trips both Parts, with
rulepresent in the card's advertised map and JSON-RPC success at the envelope level.