Skip to main content
Plain shows your agent’s tool calls differently depending on where it is working. In a discussion, tool calls are interactive: you report each call, the user watches it run, and you can pause a call until the user approves it. On a thread, you record tool calls as thread events on the timeline. Those are a log for the team, not something a user can act on.

In discussions

Your machine user’s API key needs to have the threadDiscussion:read and threadDiscussion:edit permissions.

Report a tool call

Call upsertDiscussionToolCall with a toolCallId you define. The initial tool call should be in a status of PENDING. When your tool call completes, update the status to SUCCESS or ERROR depending on the outcome. Plain shows the call in the discussion with its duration.
  • toolCallId: yours, unique within the discussion, 1–256 characters of [A-Za-z0-9_-]
  • text: required on every write, max 2000 characters. This is what the user reads.
  • error: required on ERROR, max 4000 characters
  • SUCCESS and ERROR are final. A later write returns result: NOOP.

Asking for approval

For a call that needs a user’s decision, you can call the requestDiscussionToolCallApproval mutation. Plain shows a card with text as the heading, justification underneath, and Approve and Deny buttons. The discussion’s agentStatus will automatically be set to TOOL_CALL_APPROVAL_PENDING.
When requesting approval, the tool call must be in a status of PENDING. Asking again for the same id returns the same approval. Several approvals can be open on one discussion at once. Plain sends discussion.tool_call_approval_requested as an echo, then discussion.tool_call_approval_resolved when the user makes a decision:
  • APPROVED: means your tool call was approved and you can run the tool.
  • DENIED: means the user rejected your tool call. Your tool will have already been updated to a status of FAILED and will include the user’s reviewerNote if provided. This is a human-provided message as to why the tool call was rejected.
  • If your agent stops waiting, report ERROR so the call doesn’t stay open.

On threads

On a thread there is no approval flow. You can record what the agent did by using thread events so you can see it on a thread’s timeline. The API key needs threadEvent:create.
title is the line users see on the timeline. components hold the detail, built from UI components. Set isCollapsed to true so a run with many calls doesn’t crowd out the conversation. Pass an externalId if you want Plain to reject a duplicate tool call thread event. If a tool on a thread needs a user’s decision, ask for it somewhere a user can answer: post a note that mentions them, or hand the thread off.