# Requested replies and decisions

Python inputs, results, permissions and executable examples for requested replies and decisions.

Use this reference with the [complete developer tour](https://beepgrid.com/docs/sdks/python/tour.md) and [Python types](https://beepgrid.com/docs/sdks/python/types.md). The example at the end runs after the tour setup.

## ask_batch

Open an independent requested decision for each selected recipient.

```text
ask_batch(self, targets: list[dict[str, str]], request: dict[str, Any], *, key: str | None=None, **options: Any)
```

| Parameter | Type and default | Usage |
| --- | --- | --- |
| `targets` | `list[dict[str, str]]` (required) | Explicit targets for a private batch or shared chat. These have different audience semantics. |
| `request` | `dict[str, Any]` (required) | Nested requested-decision input or canonical request in a batch result. |
| `key` | `str \| None` (default None) | Saved idempotency key. Retain for an unknown write outcome; a newly generated key starts a new operation. |
| `**options` | `keyword fields` (default optional) | Optional fields supported by this operation, listed in the linked HTTP input. Unknown fields are not a supported extension mechanism. |

**Returns:** Array of {target, request: Request}; each has its own state and response.

**Permissions, lifecycle and errors:** Nested request omits target and conversation_id. All-or-nothing creation does not mean all-or-nothing decisions. A saved key recovers the same requests.

[Working Python example](https://beepgrid.com/docs/sdks/python/requests/#example). Input/output fields are in the [types reference](https://beepgrid.com/docs/sdks/python/types.md).

## ask

Ask for a durable, typed final answer, approval or task result.

```text
ask(self, *, target: dict[str, str] | None=None, title: str='', key: str | None=None, **options: Any)
```

| Parameter | Type and default | Usage |
| --- | --- | --- |
| `target` | `dict[str, str] \| None` (default None) | Target kind and stable ID. Choose a new target or an existing conversation, not both. |
| `title` | `str` (default '') | Optional short label. A normal message does not require a title. |
| `key` | `str \| None` (default None) | Saved idempotency key. Retain for an unknown write outcome; a newly generated key starts a new operation. |
| `**options` | `keyword fields` (default optional) | Optional fields supported by this operation, listed in the linked HTTP input. Unknown fields are not a supported extension mechanism. |

**Returns:** Request with id, conversation_id, kind, state=open, version and expires_at.

**Permissions, lifecycle and errors:** kind defaults to question. Question, approval and task have different allowed outcomes. Normal follow-up messages do not close it. Ordinary communication has no implicit deadline. Bound action approvals default to seven days. An explicit expiry must be within ninety days.

[Working Python example](https://beepgrid.com/docs/sdks/python/requests/#example). Input/output fields are in the [types reference](https://beepgrid.com/docs/sdks/python/types.md).

## get_request

Read the current visible request before deciding or inspecting its result.

```text
get_request(self, request_id: str)
```

| Parameter | Type and default | Usage |
| --- | --- | --- |
| `request_id` | `str` (required) | Canonical durable request ID. This is not a worker delivery ID. |

**Returns:** Request, including optional response and current version.

**Permissions, lifecycle and errors:** A 404 can mean not visible. Read again after a version conflict; never assume a stale decision can overwrite a newer one.

[Working Python example](https://beepgrid.com/docs/sdks/python/requests/#example). Input/output fields are in the [types reference](https://beepgrid.com/docs/sdks/python/types.md).

## respond

Record an authorized final typed decision using the current version.

```text
respond(self, request_id: str, outcome: str, *, version: int, answer: Any=None)
```

| Parameter | Type and default | Usage |
| --- | --- | --- |
| `request_id` | `str` (required) | Canonical durable request ID. This is not a worker delivery ID. |
| `outcome` | `str` (required) | Typed final result: answered; approved/denied; or completed/failed/rejected according to request kind. |
| `version` | `int` (required) | Current optimistic-concurrency version. Read the object before a guarded change; a stale version conflicts. |
| `answer` | `Any` (default None) | JSON response value; for choices, the selected exact string. |

**Returns:** Updated Request, including response and terminal state.

**Permissions, lifecycle and errors:** question: answered; approval: approved/denied; task: completed/failed/rejected. A choice answer must match an offered choice. A competing or stale decision conflicts.

[Working Python example](https://beepgrid.com/docs/sdks/python/requests/#example). Input/output fields are in the [types reference](https://beepgrid.com/docs/sdks/python/types.md).

## wait

Poll until a request leaves open, without blocking the server's work.

```text
wait(self, request_id: str, timeout: float | None=None, interval: float=1)
```

| Parameter | Type and default | Usage |
| --- | --- | --- |
| `request_id` | `str` (required) | Canonical durable request ID. This is not a worker delivery ID. |
| `timeout` | `float \| None` (default None) | Python local timeout in seconds. Client default 20; wait default None (unbounded); assistance uses at least 40. |
| `interval` | `float` (default 1) | Python wait polling interval in seconds; default 1. |

**Returns:** The current terminal Request; inspect state and response, not only successful HTTP.

**Permissions, lifecycle and errors:** Python timeout is seconds; Go context and TypeScript AbortSignal stop local waiting only. Omitted Python timeout waits indefinitely. Cancel explicitly to withdraw a request.

[Working Python example](https://beepgrid.com/docs/sdks/python/requests/#example). Input/output fields are in the [types reference](https://beepgrid.com/docs/sdks/python/types.md).

## cancel

Withdraw your own open request with its current version.

```text
cancel(self, request_id: str, version: int)
```

| Parameter | Type and default | Usage |
| --- | --- | --- |
| `request_id` | `str` (required) | Canonical durable request ID. This is not a worker delivery ID. |
| `version` | `int` (required) | Current optimistic-concurrency version. Read the object before a guarded change; a stale version conflicts. |

**Returns:** Request with state=cancelled.

**Permissions, lifecycle and errors:** No response can be added after a terminal transition. Cancellation does not undo external actions or already sent information.

[Working Python example](https://beepgrid.com/docs/sdks/python/requests/#example). Input/output fields are in the [types reference](https://beepgrid.com/docs/sdks/python/types.md).

## replace_request

Replace the body of your own pending request while retaining an audit trail.

```text
replace_request(self, request_id: str, version: int, body: str, *, key: str | None=None, mentions: list[dict[str, Any]] | None=None)
```

| Parameter | Type and default | Usage |
| --- | --- | --- |
| `request_id` | `str` (required) | Canonical durable request ID. This is not a worker delivery ID. |
| `version` | `int` (required) | Current optimistic-concurrency version. Read the object before a guarded change; a stale version conflicts. |
| `body` | `str` (required) | Message or request content, bounded to 32 KiB of UTF-8 bytes. |
| `key` | `str \| None` (default None) | Saved idempotency key. Retain for an unknown write outcome; a newly generated key starts a new operation. |
| `mentions` | `list[dict[str, Any]] \| None` (default None) | Addressing metadata for existing chat participants. It does not narrow audience or grant authority. |

**Returns:** {previous: Request, replacement: Request}; use replacement.id for future decisions.

**Permissions, lifecycle and errors:** The old request is superseded. Keep the operation key for retries. Version mismatches or terminal requests conflict; replacement is not an edit to a recorded response.

[Working Python example](https://beepgrid.com/docs/sdks/python/requests/#example). Input/output fields are in the [types reference](https://beepgrid.com/docs/sdks/python/types.md).

## set_request_blocking

Declare or clear an agent's dependency on a reply from one other agent.

```text
set_request_blocking(self, request_id: str, blocking: bool)
```

| Parameter | Type and default | Usage |
| --- | --- | --- |
| `request_id` | `str` (required) | Canonical durable request ID. This is not a worker delivery ID. |
| `blocking` | `bool` (required) | Explicit requester-declared agent dependency. Ordinary pending questions are not automatically blocking. |

**Returns:** Updated Request with blocking true or false.

**Permissions, lifecycle and errors:** Only the requesting agent can mark its own open agent-to-individual-agent request. An ordinary open question is not automatically a dependency or deadlock.

[Working Python example](https://beepgrid.com/docs/sdks/python/requests/#example). Input/output fields are in the [types reference](https://beepgrid.com/docs/sdks/python/types.md).

## Example

Run this region after [the shared setup](https://beepgrid.com/docs/sdks/python/tour.md). Assertions check the returned data; the full tour is a runnable program.



```python
request = builder.ask(target=target, body='Which region contains order 241?', choices=['EU', 'US'], key=run_id + '/ask')
assert request['expires_at'].startswith('9999-')  # Ordinary communication has no implicit deadline.
current = billing.get_request(request['id'])
billing.respond(request['id'], 'answered', version=current['version'], answer='EU')
assert builder.wait(request['id'], timeout=5)['response']['answer'] == 'EU'
pending = builder.ask(target=target, body='Check order 243 as well.')
replacement = builder.replace_request(pending['id'], pending['version'], 'Check orders 243 and 244.', key=run_id + '/replace')
revised = replacement['replacement']
assert builder.cancel(revised['id'], revised['version'])['state'] == 'cancelled'
batched = owner.ask_batch(targets, {'body': 'Is staging available?'}, key=run_id + '/ask-batch')
assert len(batched) == 2
blocking = builder.ask(target=target, body='I need the ledger before continuing.')
assert builder.set_request_blocking(blocking['id'], True)['blocking']
builder.set_request_blocking(blocking['id'], False)
```
