Skip to content

Composio write actions run without an approval prompt, and the agent path stores the raw provider envelope #5299

Description

@yh928

Summary

A Composio write action run by the agent fires with no approval prompt at all, even when the user has configured "ask before sending". On the same surface, the agent path stores the provider's full response envelope into context instead of the slimmed record.

Problem

No approval card for a write. The human-in-the-loop card is raised only for a tool whose external_effect_with_args is true. Neither composio_execute nor the per-action ComposioActionTool declares it, so a GMAIL_SEND_EMAIL through integrations_agent sends mail unprompted. Nothing else covers this: the contract gate only ensures the action's schema is in context, and permission_level = Write is a channel cap (allow/block), not a prompt.

Steps to reproduce:

  1. Connect a Gmail toolkit and enable the approval gate.
  2. Ask the agent to send an email, so it routes through integrations_agent.
  3. The mail is sent; no approval card is ever raised.

Expected: a write- or admin-scoped action parks for the approval card; a pure read flows through unprompted.

Verbose envelope on the agent path. When the agent calls an action directly, the raw-JSON fallback body carries the provider envelope — Gmail's full MIME tree under payload.parts[], dozens of Received: headers. The reshape that slims that into one clean record per message was wired only into the sync path, so the agent path pays the full envelope in context on every call.

Solution (optional)

Report external-effect from the action's own scope on both surfaces (write/admin true, read false), and run the existing response reshape inline on the agent paths before the body becomes tool output.

Acceptance criteria

  • Repro gone — a write-scoped Composio action raises the approval card on both the dispatcher and per-action surfaces.
  • Reads stay unprompted — a fetch/list action is not gated.
  • Envelope slimmed — the agent path stores the reshaped record, and a backend-rendered markdown body is left alone.
  • Regression safety — coverage asserting the gate/no-gate split for send/delete vs fetch.
  • Diff coverage ≥ 80% — the fix PR meets the changed-lines coverage gate.

Related

Fix: #5259. The reshape restored here is the one introduced by #2585.

Activity

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

Metadata

Metadata

Assignees

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