Fix 16_deferred_init example: poll on real execution-status values#3793
Conversation
The 16_deferred_init.py example checked for a non-existent "stopped" status and never included the real terminal "finished" state, so the poll loop spun the full max_wait (120s) and the final assert raised AssertionError (exit 1) even though the conversation finished in ~2s. Use the actual ConversationExecutionStatus terminal values (finished/error/stuck) for the break, and assert on "finished".
Python API breakage checks — ✅ PASSEDResult: ✅ PASSED |
REST API breakage checks (OpenAPI) — ✅ PASSEDResult: ✅ PASSED |
|
🔍 Review in progress… We are performing the review through OpenHands Cloud Automation. You can log in and view the conversation here. |
|
@OpenHands CI Docs example fails. Check if there is an opened PR in openhands/docs repo documenting that example, if not open one, if yes review it yourself. Note that the branch name has to match something so that CI doesnt fail here. |
|
@enyst it looks like you haven't created an OpenHands account yet. Please sign up at OpenHands Cloud and try again. |
|
I'm on it! enyst can track my progress at all-hands.dev |
|
Found the existing docs PR for this example: OpenHands/docs#577. I reviewed and approved it, and verified it documents |
|
OpenHands encountered an error: **Failed to send message to agent server: HTTP 503 error: no available server See the conversation for more information. |
all-hands-bot
left a comment
There was a problem hiding this comment.
✅ QA Report: PASS
The deferred-init example now exits successfully as soon as the conversation reaches finished, instead of polling until timeout and failing its final assertion.
Does this PR achieve its stated goal?
Yes. I reproduced the bug on origin/main: the example reached execution_status == "finished" after 2 seconds, kept polling through 118 seconds, then exited with AssertionError: Unexpected final status: finished and SCRIPT_EXIT:1. On PR commit df5aff5a79a22716a6fef02fefc0d0e1971eae6f, the same example stopped at finished, fetched the agent response ('42'), printed EXAMPLE_COST, and exited with SCRIPT_EXIT:0.
| Phase | Result |
|---|---|
| Environment Setup | ✅ make build completed and installed the uv-managed dev environment. |
| CI Status | [Optional] Docs example/check-examples is now passing. |
| Functional Verification | ✅ Before/after execution of examples/02_remote_agent_server/16_deferred_init.py confirms the fix. |
Functional Verification
Test 1: Deferred-init example terminal status polling
Step 1 — Reproduce baseline without the fix:
Checked out origin/main, then ran the actual example with a real local agent-server and LLM-backed conversation:
git checkout --detach origin/main
nohup bash -lc 'env -u TMUX TMUX_TMPDIR=/tmp/oh-qa-tmux-main OPENHANDS_SUPPRESS_BANNER=1 LLM_API_KEY="$LLM_API_KEY" uv run python examples/02_remote_agent_server/16_deferred_init.py > /tmp/deferred_init_main.log 2>&1; printf "\nSCRIPT_EXIT:%s\n" "$?" >> /tmp/deferred_init_main.log' &Relevant output:
✅ Server is dormant — {'state': 'dormant', 'error': None}
✅ /api/conversations correctly returns 503 while dormant
✅ Server is now ready — {'state': 'ready', 'error': None}
✅ Conversation started: 2a2a887a-424d-4954-b6b5-f44a38f950a6
status: running (0s elapsed)
status: finished (2s elapsed)
...
status: finished (118s elapsed)
✅ Conversation finished — status: finished
Traceback (most recent call last):
File ".../examples/02_remote_agent_server/16_deferred_init.py", line 163, in <module>
assert execution_status in ("stopped", "paused"), (
AssertionError: Unexpected final status: finished
SCRIPT_EXIT:1
This confirms the reported bug: the deferred-init flow and conversation both worked, but the example did not treat finished as a terminal success status and failed after the full polling window.
Step 2 — Apply the PR's changes:
Checked out the PR branch at the requested commit:
git checkout fix/deferred-init-example-terminal-status
git rev-parse HEAD
# df5aff5a79a22716a6fef02fefc0d0e1971eae6fStep 3 — Re-run with the fix in place:
Ran the same example entry point again:
nohup bash -lc 'env -u TMUX TMUX_TMPDIR=/tmp/oh-qa-tmux-pr OPENHANDS_SUPPRESS_BANNER=1 LLM_API_KEY="$LLM_API_KEY" uv run python examples/02_remote_agent_server/16_deferred_init.py > /tmp/deferred_init_pr.log 2>&1; printf "\nSCRIPT_EXIT:%s\n" "$?" >> /tmp/deferred_init_pr.log' &Relevant output:
✅ Server is dormant — {'state': 'dormant', 'error': None}
✅ /api/conversations correctly returns 503 while dormant
✅ Server is now ready — {'state': 'ready', 'error': None}
✅ Conversation started: 41810fe4-f917-48c9-91e9-d90010a2f091
status: running (0s elapsed)
✅ Conversation finished — status: finished
Agent response: '42'
Conversation deleted
🎉 Deferred-init example completed successfully!
EXAMPLE_COST: 0.02425
SCRIPT_EXIT:0
This shows the fix works: finished is now recognized as the successful terminal state, the example proceeds to fetch the final response and cleanup, and the process exits successfully instead of timing out and asserting.
Issues Found
None.
This QA review was created by an AI agent (OpenHands) on behalf of the user.
Problem
examples/02_remote_agent_server/16_deferred_init.pyfails with exit code 1 (e.g. in the v1.29.0 release PR #3787, after ~2m30s). The deferred-init flow itself works — dormant → 503 gate →POST /api/init→ ready → conversation runs and the agent finishes in ~2s. The bug is purely in the poll/assert logic at the end of the example, which uses execution-status strings that don't exist.The server's
ConversationExecutionStatusterminal values arefinished,error,stuck— there is no"stopped"status. The example did:So:
execution_status == "finished"."finished"isn't in the break set → the loop spins the fullmax_wait = 120s(the wall of repeatedstatus: finishedlog lines).assert "finished" in ("stopped", "paused")raisesAssertionError→ exit 1.Fix
Use the real terminal values from
ConversationExecutionStatus.is_terminal()(finished/error/stuck) for the break, and assert on"finished". Two-line change; no behavior change to the deferred-init feature.Agent Server images for this PR
• GHCR package: https://github.com/OpenHands/agent-sdk/pkgs/container/agent-server
Variants & Base Images
eclipse-temurin:17-jdknikolaik/python-nodejs:python3.13-nodejs22-slimgolang:1.21-bookwormPull (multi-arch manifest)
# Each variant is a multi-arch manifest supporting both amd64 and arm64 docker pull ghcr.io/openhands/agent-server:df5aff5-pythonRun
All tags pushed for this build
About Multi-Architecture Support
df5aff5-python) is a multi-arch manifest supporting both amd64 and arm64df5aff5-python-amd64) are also available if needed