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 requirements
- 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.
The current probe checks structure but does not deliberately provoke every rule or verify its correspondence with the card. See probe coverage and acceptance evidence.