# interactions/v1 (/docs/a2a/interactions/v1)



URI: `https://docs.nylorun.com/a2a/interactions/v1`

```json
{
  "status": {
    "state": "TASK_STATE_AUTH_REQUIRED",
    "message": {
      "role": "ROLE_AGENT",
      "parts": [{ "text": "Approve github / create_pull_request?" }],
      "extensions": ["https://docs.nylorun.com/a2a/interactions/v1"],
      "metadata": {
        "https://docs.nylorun.com/a2a/interactions/v1": {
          "interactionId": "eff_01J…",
          "kind": "approval",
          "prompt": "Approve github / create_pull_request?",
          "detail": { "server": "github", "tool": "create_pull_request" }
        }
      }
    }
  }
}
```

A turn pauses when the [tool policy](/docs/run/tool-policy) holds a tool call
for a person, when the agent asks a question, or when it asks for an app to be
connected. The task's status message then carries the open interaction under
this extension, and the caller answers on the same task.

A client that has not activated the extension sees the same status message as
plain text. Text never approves: a text reply to a task that waits for an
approval is refused with `UnsupportedOperationError`. A text or data reply to a
question answers it.

## The open interaction [#the-open-interaction]

On the status message of a task in an interrupted state.

| Field           | Type                                    | Meaning                                                                                                                                      |
| --------------- | --------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `interactionId` | string                                  | The interaction to answer. For a held tool call, the effect id.                                                                              |
| `kind`          | `approval`, `question`, or `connection` | What the agent waits for.                                                                                                                    |
| `prompt`        | string                                  | The text to show a person. The status message's text part says the same.                                                                     |
| `detail`        | object, optional                        | What the interaction is about: a held call's `server`, `tool`, and `reason`, or a connection's `app` and `reason`. Never a call's arguments. |

| Kind         | Task state                  | Raised by                              | Answer with                                                                                                 |
| ------------ | --------------------------- | -------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| `approval`   | `TASK_STATE_AUTH_REQUIRED`  | The tool policy holding a call         | `approved`: `true` sends the held call as the person saw it; `false` fails it to the model as `tool.denied` |
| `question`   | `TASK_STATE_INPUT_REQUIRED` | The agent asking                       | `value`: any JSON value                                                                                     |
| `connection` | `TASK_STATE_AUTH_REQUIRED`  | The agent calling `request_connection` | `value`: `{ "connected": true }` once the app is connected; `{ "connected": false }` to decline             |

## Connections [#connections]

An agent asks for an app to be connected with `request_connection`, a
built-in tool of our harness that is off by default. Turn it on in the agent's
`AGENT.md`:

```markdown title="AGENT.md"
---
name: coder
description: Writes and ships changes to the team's repositories.
loop:
  connections: true
---
```

The tool takes `{ app, reason }`: the app cut at 80 characters, the reason at
280\. The turn pauses with the prompt `Connect <app>: <reason>` and
`detail: { app, reason }`. The person connects the app wherever your product
keeps its connections, then you answer. `{ "connected": true }`, or `true`,
tells the model `Connected: <app>`; any other value tells it
`Not connected: <app>`. `approved: true` or `false` is read the same way. See
[AGENT.md](/docs/build/agent-manifests#agentmd).

## The answer [#the-answer]

A message on the same `taskId` and `contextId`, listing the extension:

```json
{
  "message": {
    "role": "ROLE_USER",
    "messageId": "m-2",
    "taskId": "t1.…",
    "contextId": "ticket-4821",
    "parts": [{ "data": { "approved": true } }],
    "extensions": ["https://docs.nylorun.com/a2a/interactions/v1"],
    "metadata": {
      "https://docs.nylorun.com/a2a/interactions/v1": {
        "interactionId": "eff_01J…",
        "approved": true
      }
    }
  }
}
```

| Field           | Type     | Meaning                                                                                                 |
| --------------- | -------- | ------------------------------------------------------------------------------------------------------- |
| `interactionId` | string   | The open interaction's id.                                                                              |
| `approved`      | boolean  | The answer to an `approval`. For a question or a connection, it is read as the `value`.                 |
| `value`         | any JSON | The answer to a `question` or a `connection`. For an approval, a boolean `value` is read as `approved`. |

An approval is the Runtime's `approve` command, and a question or connection
its `respond` command, as on
[Pauses and control](/docs/run/control#resolve-a-pause). The Runtime records
the caller's subject as `approvedBy`. The `messageId` is the answer's
idempotency key: a retry with the same id answers once. Answered, the task
returns to `TASK_STATE_WORKING` on the same `taskId`.

With the SDK:

```ts
await a2a.answer({
  taskId: task.id,
  contextId: task.contextId,
  interactionId,
  approved: true,
  messageId: `answer:${interactionId}`,
});
```

See [A2A client](/docs/a2a/client#answer-an-interaction).
