Skip to content

Permission prompts can silently lose tool-call context: DefaultOnError on rawInput #1979

Open

Description

@PMP57

Observation (at v1.6.0, tag 5e89c71)

ToolCallUpdate.raw_input is deserialized with serde_as(deserialize_as = "DefaultOnError") + serde(default) (agent-client-protocol-schema/src/v1/tool_call.rs:69-73), exported in the JSON schema as x-deserialize-default-on-error: true. Several sibling display fields (name, kind, status, title path) carry the same annotation. Meanwhile RequestPermissionRequest requires only sessionId/toolCall/options, and ToolCallUpdate requires only toolCallId.

Consequence for permission flows

If an agent sends a rawInput that fails to deserialize, the field silently becomes None. For a client rendering a permission prompt, "agent provided no input" and "agent provided input that didn't parse" are indistinguishable — a fully conformant request can render an argument-free approval prompt even though the agent believed it transmitted the arguments, and the human (or policy engine) approves with less context than was sent.

We hit this while evaluating ACP as the harness boundary for an agent-orchestration system where the permission request is the exact surface an approval binds to.

Not proposing erroring

The robustness intent is clear and good — a malformed metadata field shouldn't kill a session. The gap is only observability of the substitution.

Suggestions (either would resolve it)

  1. Have the deserializing layer surface substitution, e.g. a reserved _meta marker or per-field flag, so clients can distinguish absent from unparseable and permission UIs can refuse or visibly flag defaulted context; or
  2. A spec note in the permission-request docs that clients SHOULD apply heightened display treatment (or refusal) when rawInput is absent/defaulted on a permission-bearing tool call.

Verified against the v1.6.0 tag; apologies if the v2 draft already addresses this.

Drafted by an AI reviewer during an independent protocol evaluation; filed and endorsed by this account's owner.

Activity

  1. Brodin2001 commented on Aug 27, 2026

    @Brodin2001

    This is a really interesting failure mode.

    I've been testing a small authorization layer around agent tool calls, and one thing I'm deliberately treating as part of the authorization decision is the exact normalized arguments — not just "the agent is allowed to use this tool."

    Your example makes the distinction pretty important: approving the intent/tool while losing the actual arguments isn't really approving the action.

    I'm curious whether you've considered binding the approval to a normalized/hashable representation of the exact tool + arguments, so any material change between approval and execution invalidates it.

    I'm experimenting with that idea in AgentGuard and would be happy to share it if useful to you.

  2. Brodin2001 commented on Aug 27, 2026

    @Brodin2001

    Hey — your ACP issue about rawInput potentially disappearing from permission prompts is really interesting.

    I'm testing a small authorization layer where the exact normalized tool + arguments form part of the authorization decision, rather than treating "allowed to use this tool" as sufficient.

    I'd love to pressure-test that idea against the problem you found.

    Would you be interested in installing the tiny Python prototype and trying it on a real tool call? I'll help get it running for free — I'd mainly want to learn whether binding the decision to the exact call actually addresses something useful or whether I'm overengineering it.

  3. gustavo89587 commented on Sep 9, 2026

    @gustavo89587

    The interesting part here is not the deserialization failure itself, but the authority transition that follows it.

    If material tool-call context is lost during normalization, the approval surface no longer represents the action that was originally proposed.

    That creates a runtime invariant:

    approval authority should not be granted from degraded action evidence unless that degradation is explicit and policy-visible.

    In other words:

    provided input → parsing failure → silent absence

    should not be equivalent to:

    no input was provided.

    The session can remain robust without making approval semantics lossy.

  4. Brodin2001 commented on Sep 10, 2026

    @Brodin2001
  5. gustavo89587 commented on Sep 11, 2026

    @gustavo89587

    Glad that distinction was useful. I think the execution boundary is exactly where this gets interesting.

    An approval can prove what a human authorized, but unless the approved representation is bound to the operation that reaches the side effect, it still cannot prove what was executed.

    I’ve been treating that uncertainty as first-class state rather than filling the gap with implied authority.

    Your execution_binding = "external" framing makes that limitation explicit, which I think is the right direction.

  6. gustavo89587 commented on Sep 23, 2026

    @gustavo89587

    A re-fetch could be a recovery mechanism, but I wouldn't make authorization depend on successful recovery alone.

    The stronger invariant is:

    if material action context was lost, approval authority remains incomplete until the reconstructed context is explicitly rebound to the operation being authorized.

    So the flow could be:

    parse failure → degraded evidence → no approval authority

    then, if recovery succeeds:

    re-fetched context → normalized action → explicit approval → execution binding

    That avoids treating the re-fetch itself as proof that the recovered action is the same action originally proposed.

    The important property is not just “show the context again,” but preserving continuity between proposed → displayed → approved → executed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions