Skip to content

Fix 16_deferred_init example: poll on real execution-status values#3793

Merged
VascoSch92 merged 1 commit into
mainfrom
fix/deferred-init-example-terminal-status
Jun 18, 2026
Merged

Fix 16_deferred_init example: poll on real execution-status values#3793
VascoSch92 merged 1 commit into
mainfrom
fix/deferred-init-example-terminal-status

Conversation

@VascoSch92

@VascoSch92 VascoSch92 commented Jun 18, 2026

Copy link
Copy Markdown
Member

Problem

examples/02_remote_agent_server/16_deferred_init.py fails 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 ConversationExecutionStatus terminal values are finished, error, stuck — there is no "stopped" status. The example did:

if execution_status in ("stopped", "paused", "error"):   # never matches "finished"
    break
...
assert execution_status in ("stopped", "paused"), ...     # "finished" not in set

So:

  1. Agent completes → execution_status == "finished".
  2. "finished" isn't in the break set → the loop spins the full max_wait = 120s (the wall of repeated status: finished log lines).
  3. After the loop, assert "finished" in ("stopped", "paused") raises AssertionError → 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

Variant Architectures Base Image Docs / Tags
java amd64, arm64 eclipse-temurin:17-jdk Link
python amd64, arm64 nikolaik/python-nodejs:python3.13-nodejs22-slim Link
golang amd64, arm64 golang:1.21-bookworm Link

Pull (multi-arch manifest)

# Each variant is a multi-arch manifest supporting both amd64 and arm64
docker pull ghcr.io/openhands/agent-server:df5aff5-python

Run

docker run -it --rm \
  -p 8000:8000 \
  --name agent-server-df5aff5-python \
  ghcr.io/openhands/agent-server:df5aff5-python

All tags pushed for this build

ghcr.io/openhands/agent-server:df5aff5-golang-amd64
ghcr.io/openhands/agent-server:df5aff5a79a22716a6fef02fefc0d0e1971eae6f-golang-amd64
ghcr.io/openhands/agent-server:fix-deferred-init-example-terminal-status-golang-amd64
ghcr.io/openhands/agent-server:df5aff5-golang_tag_1.21-bookworm-amd64
ghcr.io/openhands/agent-server:df5aff5-golang-arm64
ghcr.io/openhands/agent-server:df5aff5a79a22716a6fef02fefc0d0e1971eae6f-golang-arm64
ghcr.io/openhands/agent-server:fix-deferred-init-example-terminal-status-golang-arm64
ghcr.io/openhands/agent-server:df5aff5-golang_tag_1.21-bookworm-arm64
ghcr.io/openhands/agent-server:df5aff5-java-amd64
ghcr.io/openhands/agent-server:df5aff5a79a22716a6fef02fefc0d0e1971eae6f-java-amd64
ghcr.io/openhands/agent-server:fix-deferred-init-example-terminal-status-java-amd64
ghcr.io/openhands/agent-server:df5aff5-eclipse-temurin_tag_17-jdk-amd64
ghcr.io/openhands/agent-server:df5aff5-java-arm64
ghcr.io/openhands/agent-server:df5aff5a79a22716a6fef02fefc0d0e1971eae6f-java-arm64
ghcr.io/openhands/agent-server:fix-deferred-init-example-terminal-status-java-arm64
ghcr.io/openhands/agent-server:df5aff5-eclipse-temurin_tag_17-jdk-arm64
ghcr.io/openhands/agent-server:df5aff5-python-amd64
ghcr.io/openhands/agent-server:df5aff5a79a22716a6fef02fefc0d0e1971eae6f-python-amd64
ghcr.io/openhands/agent-server:fix-deferred-init-example-terminal-status-python-amd64
ghcr.io/openhands/agent-server:df5aff5-nikolaik_s_python-nodejs_tag_python3.13-nodejs22-slim-amd64
ghcr.io/openhands/agent-server:df5aff5-python-arm64
ghcr.io/openhands/agent-server:df5aff5a79a22716a6fef02fefc0d0e1971eae6f-python-arm64
ghcr.io/openhands/agent-server:fix-deferred-init-example-terminal-status-python-arm64
ghcr.io/openhands/agent-server:df5aff5-nikolaik_s_python-nodejs_tag_python3.13-nodejs22-slim-arm64
ghcr.io/openhands/agent-server:df5aff5-golang
ghcr.io/openhands/agent-server:df5aff5a79a22716a6fef02fefc0d0e1971eae6f-golang
ghcr.io/openhands/agent-server:fix-deferred-init-example-terminal-status-golang
ghcr.io/openhands/agent-server:df5aff5-golang_tag_1.21-bookworm
ghcr.io/openhands/agent-server:df5aff5-java
ghcr.io/openhands/agent-server:df5aff5a79a22716a6fef02fefc0d0e1971eae6f-java
ghcr.io/openhands/agent-server:fix-deferred-init-example-terminal-status-java
ghcr.io/openhands/agent-server:df5aff5-eclipse-temurin_tag_17-jdk
ghcr.io/openhands/agent-server:df5aff5-python
ghcr.io/openhands/agent-server:df5aff5a79a22716a6fef02fefc0d0e1971eae6f-python
ghcr.io/openhands/agent-server:fix-deferred-init-example-terminal-status-python
ghcr.io/openhands/agent-server:df5aff5-nikolaik_s_python-nodejs_tag_python3.13-nodejs22-slim

About Multi-Architecture Support

  • Each variant tag (e.g., df5aff5-python) is a multi-arch manifest supporting both amd64 and arm64
  • Docker automatically pulls the correct architecture for your platform
  • Individual architecture tags (e.g., df5aff5-python-amd64) are also available if needed

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".
@github-actions

Copy link
Copy Markdown
Contributor

Python API breakage checks — ✅ PASSED

Result:PASSED

Action log

@github-actions

Copy link
Copy Markdown
Contributor

REST API breakage checks (OpenAPI) — ✅ PASSED

Result:PASSED

Action log

Copy link
Copy Markdown
Collaborator

🔍 Review in progress…

We are performing the review through OpenHands Cloud Automation. You can log in and view the conversation here.

@VascoSch92 VascoSch92 enabled auto-merge (squash) June 18, 2026 14:57
@enyst

enyst commented Jun 18, 2026

Copy link
Copy Markdown
Member

@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.

@openhands-development

Copy link
Copy Markdown

@enyst it looks like you haven't created an OpenHands account yet. Please sign up at OpenHands Cloud and try again.

@openhands-ai

openhands-ai Bot commented Jun 18, 2026

Copy link
Copy Markdown

I'm on it! enyst can track my progress at all-hands.dev

@VascoSch92 VascoSch92 merged commit 9e29079 into main Jun 18, 2026
34 of 37 checks passed
@VascoSch92 VascoSch92 deleted the fix/deferred-init-example-terminal-status branch June 18, 2026 14:59

enyst commented Jun 18, 2026

Copy link
Copy Markdown
Member

Found the existing docs PR for this example: OpenHands/docs#577. I reviewed and approved it, and verified it documents examples/02_remote_agent_server/16_deferred_init.py with the expected expandable example code block.\n\nI also created the matching OpenHands/docs branch fix/deferred-init-example-terminal-status at the same commit as the docs PR so this PR's check-examples workflow can checkout the docs content by branch name. I reran the failed check-examples job, and it is now passing.\n\n_This comment was created by an AI agent (OpenHands) on behalf of the user._

@openhands-ai

openhands-ai Bot commented Jun 18, 2026

Copy link
Copy Markdown

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 all-hands-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ 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 ⚠️ Current checks: 37 successful, 3 skipped, 1 pending QA Changes, 1 failing PR Description Check; [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
# df5aff5a79a22716a6fef02fefc0d0e1971eae6f

Step 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.

enyst pushed a commit that referenced this pull request Jun 18, 2026
…3793)

(cherry picked from commit 9e29079)

Co-authored-by: openhands <openhands@all-hands.dev>
@enyst enyst mentioned this pull request Jun 18, 2026
5 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants