Skip to content

Proposal: Adding Function Call Approvals in OpenResponses #62

Description

@bbqiu

Adding Tool Call Approvals in OpenResponses

Description

Agents require user approval for state-changing operations and reads of sensitive data. We propose adding tool call approvals as a subtype of a new generic elicitation item type, with options to approve once, approve for all sessions, approve for this session, or deny the request.

The OpenAI Responses API has types mcp_approval_request and mcp_approval_response, but as server side tool execution increases in popularity, a generic, non-MCP specific option will unlock additional capabilities for server-side tool execution. When/if MCP specific events are added to the OpenResponses spec, we should reuse these events for MCP approvals as well.

The elicitation Item Type

This proposal introduces a generic elicitation item type to the Responses API. The elicitation type uses an elicitation_type field as a discriminator to support different kinds of server-to-client interactions that require user input. Tool call approvals are the first subtype (elicitation_type: "tool_call_approval"), and this same pattern is reused by the OAuth Logins proposal (elicitation_type: "oauth_login").

All elicitation items share a common structure:

Field Type Required Description
id string Yes Unique identifier for this elicitation
type string Yes Always "elicitation"
elicitation_type string Yes Discriminator: "tool_call_approval", "oauth_login", or future types
message string Yes Human-readable explanation of why the interaction is needed

All elicitation responses share a common structure:

Field Type Required Description
id string Yes Unique identifier for this response
type string Yes Always "elicitation_response"
elicitation_id string Yes References the elicitation item being responded to
action string Yes One of "accept", "decline", "cancel"
reason string No Optional reason for the action

Subtype-specific fields are added alongside these common fields. This design is forward-compatible with the MCP Elicitation specification:

  • The action field uses the same vocabulary as MCP elicitation responses (accept, decline, cancel).
  • The message field matches MCP's requirement for a human-readable explanation.
  • Future MCP elicitation subtypes (e.g. elicitation_type: "form" for MCP form mode, elicitation_type: "url" for MCP URL mode) can be added without breaking changes.

Example

When adding a comment to a GitHub PR, an agent will ask for permission before adding.

Requirements

  • Applicable for all tool calls (including MCP tools if compatibility is added in the future)
  • For the response fields of a tool call approval elicitation_response:
    • action determines the user's choice:
      • accept: approve the tool call (requires a scope)
      • decline: deny this singular call to the specified tool
      • cancel: user dismissed the prompt without making a choice
    • scope (required when action is accept) determines the duration of the approval:
      • once: approve this singular call to the specified tool
      • session: for followup messages within the same session (i.e. one multi-turn chat thread), all calls to the specified tool are approved
      • always: for all invocations of the agent loop in the future from this user, all calls to the specified tool are approved
  • Server-side agent loop requirements:
    • When attempting any tool calls that require permission, scan the list of input Items for any accept + always or accept + session approvals. Also check if this user has ever selected always in previous conversations with this agent for this tool. Providers will need to maintain this mapping (user <> tool approval status).
      • If this tool has been pre-approved, proceed in the agent loop.
      • If the tool has not been pre-approved, break out of the agent loop and yield control back to the client.
    • If a tool call has been approved, run the server-side tool and continue the agent loop.
    • If a tool call has been declined, pass the decline reason (if available) to the LLM to decide the next step.
    • If a tool call has been cancelled, treat it as an implicit decline with no reason.
    • For requests with parallel tool calls, any requests lacking an explicit response are implicitly declined.
  • Client-side requirements:
    • Present the user with options for approval. Clearly explain the implication behind each option of this approval request.
    • Send the payload with the action and scope fields filled out.
    • Elicitation items and responses should be kept in client history in a multi-turn conversation.
    • For responses with multiple elicitation items, clients should not send a request until all items have been responded to OR the user has explicitly submitted the request.

Open Questions

  • Can we change function_call_output to tool_call_output? Per the Responses API docs, Functions are meant to be client-side tools, but we hope to allow provider-specific tools to be outputted as well. This would influence the naming of the elicitation_type field on the tool_call_approval elicitation.

Sample Spec

TODO link to PR with spec in code

Tool Call Approval Elicitation Fields

In addition to the common elicitation fields, tool_call_approval adds:

Field Type Required Description
name string Yes Name of the tool being called
arguments string Yes JSON-encoded arguments of the tool call

In addition to the common elicitation response fields, the response adds:

Field Type Required Description
scope string When action is accept One of "once", "session", "always"

Streaming Response

// response.created
// response.in_progress
{
  "type": "response.output_item.added",
  "item": {
    "id": "elicit_123",
    "type": "elicitation",
    "elicitation_type": "tool_call_approval",
    "message": "The agent wants to add a comment to PR #123",
    "name": "add_pr_comment",
    "arguments": "{\"pr_number\": 123, \"body\": \"Looks good!\"}"
  },
  "output_index": 0,
  "sequence_number": 2
}
{
  "type": "response.output_item.done",
  "item": {
    "id": "elicit_123",
    "type": "elicitation",
    "elicitation_type": "tool_call_approval",
    "message": "The agent wants to add a comment to PR #123",
    "name": "add_pr_comment",
    "arguments": "{\"pr_number\": 123, \"body\": \"Looks good!\"}"
  },
  "output_index": 0,
  "sequence_number": 3
}
// response.completed

Non-Streaming Response

{
  "id": "resp_0a31882ebb2d3b550069cc629e73",
  "object": "response",
  "output": [
    {
      "id": "elicit_123",
      "type": "elicitation",
      "elicitation_type": "tool_call_approval",
      "message": "The agent wants to add a comment to PR #123",
      "name": "add_pr_comment",
      "arguments": "{\"pr_number\": 123, \"body\": \"Looks good!\"}"
    }
  ]
}

Client Follow-Up Request

{
  "input": [
    {
      "role": "user",
      "content": [
        {
          "type": "input_text",
          "text": "<user input>"
        }
      ]
    },
    {
      "id": "elicit_123",
      "type": "elicitation",
      "elicitation_type": "tool_call_approval",
      "message": "The agent wants to add a comment to PR #123",
      "name": "add_pr_comment",
      "arguments": "{\"pr_number\": 123, \"body\": \"Looks good!\"}"
    },
    {
      "id": "elicit_resp_123",
      "type": "elicitation_response",
      "elicitation_id": "elicit_123",
      "action": "accept",
      "scope": "once",
      "reason": "optional reason for approving or declining"
    }
  ]
}

Decline Example

{
  "id": "elicit_resp_123",
  "type": "elicitation_response",
  "elicitation_id": "elicit_123",
  "action": "decline",
  "reason": "I don't want to comment on this PR"
}

Cancel Example

{
  "id": "elicit_resp_123",
  "type": "elicitation_response",
  "elicitation_id": "elicit_123",
  "action": "cancel"
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions