Skip to content

Commit dc99c81

Browse files
fix: Address review feedback for conversation status checking
- Add Note warning about production error handling at start of section - Add raise_for_status() for HTTP error handling in all examples - Use safe list access with len() checks to prevent IndexError - Improve status documentation with actions for each state - Add terminal states Note explaining which states exit polling loops - Handle waiting_for_confirmation state in Complete Polling Example - Handle ERROR status in start task polling loop Co-authored-by: openhands <openhands@all-hands.dev>
1 parent ddfe9be commit dc99c81

1 file changed

Lines changed: 55 additions & 23 deletions

File tree

openhands/usage/cloud/cloud-api.mdx

Lines changed: 55 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,11 @@ Each update is streamed as it occurs, allowing you to provide real-time feedback
171171

172172
After starting a conversation, you can check its status to monitor whether the agent has completed its task.
173173

174+
<Note>
175+
The examples below show basic polling patterns. For production use, add proper error handling,
176+
exponential backoff, and handle network failures gracefully.
177+
</Note>
178+
174179
#### Step 1: Check Start Task Status
175180

176181
When you start a conversation, you receive a start task ID. Poll this endpoint until `status` becomes `READY` and `app_conversation_id` is available:
@@ -218,12 +223,15 @@ Once you have the `app_conversation_id`, check whether the agent has finished it
218223
headers=headers,
219224
params={"ids": conversation_id}
220225
)
226+
response.raise_for_status() # Raise exception for HTTP errors
221227
conversations = response.json()
222228

223-
if conversations:
229+
if conversations and len(conversations) > 0:
224230
conv = conversations[0]
225231
print(f"Sandbox Status: {conv.get('sandbox_status')}")
226232
print(f"Execution Status: {conv.get('execution_status')}")
233+
else:
234+
print("Conversation not found")
227235
```
228236
</Tab>
229237
</Tabs>
@@ -244,20 +252,25 @@ Once you have the `app_conversation_id`, check whether the agent has finished it
244252
#### Status Fields
245253

246254
**`sandbox_status`** - The state of the sandbox environment:
247-
- `STARTING` - Sandbox is being created
248-
- `RUNNING` - Sandbox is active
249-
- `PAUSED` - Sandbox is paused (due to rate limits or user action)
250-
- `ERROR` - Sandbox encountered an error
251-
- `MISSING` - Sandbox was deleted
255+
- `STARTING` - Sandbox is being created. **Action:** Continue polling.
256+
- `RUNNING` - Sandbox is active. **Action:** Check `execution_status` for task progress.
257+
- `PAUSED` - Sandbox is paused (due to rate limits or user action). **Action:** The sandbox will resume automatically when resources are available, or resume manually via the UI.
258+
- `ERROR` - Sandbox encountered an error. **Action:** This is a terminal state. Check conversation details in the UI for error information.
259+
- `MISSING` - Sandbox was deleted. **Action:** This is a terminal state. Start a new conversation if needed.
252260

253261
**`execution_status`** - The state of the agent's task (available when sandbox is `RUNNING`):
254-
- `idle` - Agent is ready to receive tasks
255-
- `running` - Agent is actively working
256-
- `paused` - Execution is paused
257-
- `waiting_for_confirmation` - Agent is waiting for user confirmation
258-
- `finished` - Agent has completed the task
259-
- `error` - Agent encountered an error
260-
- `stuck` - Agent is stuck and unable to proceed
262+
- `idle` - Agent is ready to receive tasks. **Action:** Continue polling if task was recently submitted.
263+
- `running` - Agent is actively working. **Action:** Continue polling.
264+
- `paused` - Execution is paused. **Action:** Continue polling; will resume automatically.
265+
- `waiting_for_confirmation` - Agent is waiting for user confirmation. **Action:** This is a blocking state. The agent needs user input via the UI to proceed. Your polling loop should treat this as a terminal state or alert the user.
266+
- `finished` - Agent has completed the task. **Action:** Terminal state. Task is done successfully.
267+
- `error` - Agent encountered an error. **Action:** Terminal state. Check conversation in UI for error details.
268+
- `stuck` - Agent is stuck and unable to proceed. **Action:** Terminal state. Manual intervention may be required.
269+
270+
<Note>
271+
**Terminal states** that should exit your polling loop: `finished`, `error`, `stuck`, `waiting_for_confirmation`.
272+
The `waiting_for_confirmation` state requires user action through the UI before the agent can continue.
273+
</Note>
261274

262275
#### Complete Polling Example
263276

@@ -287,6 +300,7 @@ start_response = requests.post(
287300
"selected_repository": "yourusername/your-repo"
288301
}
289302
)
303+
start_response.raise_for_status()
290304
start_task = start_response.json()
291305
task_id = start_task["id"]
292306
print(f"Start task ID: {task_id}")
@@ -301,12 +315,18 @@ while not conversation_id and attempts < max_attempts:
301315
headers=headers,
302316
params={"ids": task_id}
303317
)
318+
task_response.raise_for_status()
304319
tasks = task_response.json()
305-
if tasks and tasks[0].get("status") == "READY":
320+
321+
if tasks and len(tasks) > 0 and tasks[0].get("status") == "READY":
306322
conversation_id = tasks[0].get("app_conversation_id")
307323
print(f"Conversation ready: {base_url}/conversations/{conversation_id}")
324+
elif tasks and len(tasks) > 0 and tasks[0].get("status") == "ERROR":
325+
print(f"Start task failed with error")
326+
exit(1)
308327
else:
309-
print(f"Start task status: {tasks[0].get('status') if tasks else 'unknown'}")
328+
status = tasks[0].get("status") if tasks and len(tasks) > 0 else "no response"
329+
print(f"Start task status: {status}")
310330
time.sleep(5)
311331
attempts += 1
312332

@@ -315,6 +335,7 @@ if not conversation_id:
315335
exit(1)
316336

317337
# Poll conversation until agent finishes (with timeout)
338+
# Terminal states: finished, error, stuck, waiting_for_confirmation
318339
max_attempts = 120 # 1 hour with 30-second intervals
319340
attempts = 0
320341
while attempts < max_attempts:
@@ -323,16 +344,27 @@ while attempts < max_attempts:
323344
headers=headers,
324345
params={"ids": conversation_id}
325346
)
347+
conv_response.raise_for_status()
326348
conversations = conv_response.json()
327349

328-
if conversations:
329-
conv = conversations[0]
330-
exec_status = conv.get("execution_status")
331-
print(f"Execution status: {exec_status}")
332-
333-
if exec_status in ["finished", "error", "stuck"]:
334-
print(f"Conversation completed with status: {exec_status}")
335-
break
350+
if not conversations or len(conversations) == 0:
351+
print("Warning: Conversation not found")
352+
time.sleep(30)
353+
attempts += 1
354+
continue
355+
356+
conv = conversations[0]
357+
exec_status = conv.get("execution_status")
358+
print(f"Execution status: {exec_status}")
359+
360+
# Check for terminal states
361+
if exec_status in ["finished", "error", "stuck"]:
362+
print(f"Conversation completed with status: {exec_status}")
363+
break
364+
elif exec_status == "waiting_for_confirmation":
365+
print("Agent is waiting for user confirmation in the UI")
366+
print(f"Visit: {base_url}/conversations/{conversation_id}")
367+
break
336368

337369
time.sleep(30)
338370
attempts += 1

0 commit comments

Comments
 (0)