Files
adk-python/contributing/samples/human_in_loop/README.md
T
Krishna vamsi DhulipallaandCopybara-Service 4111f85b61 docs(adk): fix run_async example and correct ticketId payload key
Merge https://github.com/google/adk-python/pull/3875

# Problem
The example in `contributing/samples/human_in_loop/README.md` shows:

```python
await runner.run_async(...)
```

However, `run_async` returns an **async generator**, so awaiting it raises:

```
TypeError: object async_generator can't be used in 'await' expression
```

Additionally, the example payload uses `"ticket-id"` while ADK tools and other examples use `"ticketId"`, creating a mismatch that breaks copy/paste usage.

# Solution
- Updated the snippet to consume the async generator correctly:

```python
async for event in runner.run_async(...):
    ...
```

- Aligned the payload key from `"ticket-id"` → `"ticketId"` for consistency with ADK schema and other examples.

These changes make the example runnable and consistent with the API’s actual behavior.

# Testing Plan
This PR is a **small documentation correction**, so no unit tests are required per contribution guidelines.

- Verified the corrected snippet manually to ensure it no longer raises `TypeError`.

# Checklist
- [x] I have read the CONTRIBUTING.md document.
- [x] I have performed a self-review of my own code.
- [ ] I have commented my code, particularly in hard-to-understand areas. *(N/A – docs only)*
- [ ] I have added tests that prove my fix is effective or that my feature works. *(N/A – docs only)*
- [ ] New and existing unit tests pass locally with my changes. *(N/A – docs only)*
- [x] I have manually tested my changes end-to-end.
- [ ] Any dependent changes have been merged and published in downstream modules. *(N/A)*

COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/3875 from krishna-dhulipalla:docs/fix-adk-run_async-example 83fc5b430690b63b8b7bf1025ef03b0761264751
PiperOrigin-RevId: 842952362
2025-12-10 17:24:58 -08:00

45 lines
2.6 KiB
Markdown

# Agent with Long-Running Tools
This example demonstrates an agent using a long-running tool (`ask_for_approval`).
## Key Flow for Long-Running Tools
1. **Initial Call**: The agent calls the long-running tool (e.g., `ask_for_approval`).
2. **Initial Tool Response**: The tool immediately returns an initial response, typically indicating a "pending" status and a way to track the request (e.g., a `ticket-id`). This is sent back to the agent as a `types.FunctionResponse` (usually processed internally by the runner and then influencing the agent's next turn).
3. **Agent Acknowledges**: The agent processes this initial response and usually informs the user about the pending status.
4. **External Process/Update**: The long-running task progresses externally (e.g., a human approves the request).
5. **❗️Crucial Step: Provide Updated Tool Response❗️**:
* Once the external process completes or updates, your application **must** construct a new `types.FunctionResponse`.
* This response should use the **same `id` and `name`** as the original `FunctionCall` to the long-running tool.
* The `response` field within this `types.FunctionResponse` should contain the *updated data* (e.g., `{'status': 'approved', ...}`).
* Send this `types.FunctionResponse` back to the agent as a part within a new message using `role="user"`.
```python
# Example: After external approval
updated_tool_output_data = {
"status": "approved",
"ticketId": ticket_id, # from original call
# ... other relevant updated data
}
updated_function_response_part = types.Part(
function_response=types.FunctionResponse(
id=long_running_function_call.id, # Original call ID
name=long_running_function_call.name, # Original call name
response=updated_tool_output_data,
)
)
# Send this back to the agent
async for _ in runner.run_async(
# ... session_id, user_id ...
new_message=types.Content(
parts=[updated_function_response_part], role="user"
),
):
pass # exhaust generator (or handle events)
```
6. **Agent Acts on Update**: The agent receives this message containing the `types.FunctionResponse` and, based on its instructions, proceeds with the next steps (e.g., calling another tool like `reimburse`).
**Why is this important?** The agent relies on receiving this subsequent `types.FunctionResponse` (provided in a message with `role="user"` containing the specific `Part`) to understand that the long-running task has concluded or its state has changed. Without it, the agent will remain unaware of the outcome of the pending task.