Conversation
LocalConversation.condense() used to process the condensation request by calling agent.step(), which also executes pending actions, including tool calls still waiting for user confirmation. Invoke the condenser directly instead so an explicit compaction only compacts history. The condense endpoint now maps the ValueError raised when no compatible condenser exists to HTTP 409 instead of a 500. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ersations
Add a conversation-scoped voice API under /api/conversations/{id}/voice,
restricted to conversations tagged as Insider controllers:
- GET reports availability, provider, model, and whether a run is active.
- POST /realtime brokers a WebRTC offer. On the default OpenAI provider the
server builds the Realtime session (instructions, bounded saved context,
send_to_insider and end_voice_call tools) and exchanges the SDP through
OpenAI's calls endpoint with the server-held API key.
- GET and DELETE /realtime/{call_id} poll and end a call, with call IDs
bound to their conversation.
Add an opt-in Codex Voice relay (voice_provider = "codex") that delegates
the call to a Codex app-server sign-in kept in a dedicated home directory,
configured through codex_voice_home.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
REST API breakage checks (OpenAPI) — ✅ PASSEDResult: ✅ PASSED |
Build lifecycle test state with the Codex Voice manager created by create_app and verify it is awaited during shutdown. Co-authored-by: openhands <openhands@all-hands.dev>
|
Traceability and validation update (2026-09-19): the original tested SDK worktree is now preserved at enyst/agent-sdk@7c806a919, on The six failing lifecycle cases were missing the Voice manager in their fake application state. The test-only follow-up adds that manager and verifies shutdown awaits it. Production behavior is unchanged. The corresponding fix is also preserved on the original tested branch at d5dc75ee6. Validation:
The HTTP regression verifies authentication, missing-provider availability, and safe rejection of condensation without a condenser. Pending-approval preservation is covered by the separate condensation unit test. Full CI still needs to complete on the new head; this update does not claim that the earlier |
Coverage Report •
|
||||||||||||||||||||||||||||||||||||||||||||||||||
Validate and deduplicate realtime handoffs before dispatch, speak only saved results, and expose safe error codes for connection and request failures. Co-authored-by: openhands <openhands@all-hands.dev>
HUMAN:
AGENT:
Why
Insider Cat needs Voice to remain attached to its saved controller conversation, with credentials held by Agent Server. A real Codex call could hear the user but lose the request when its intermediate reasoning turn completed without selecting the forwarding tool. Dispatch explicit realtime handoffs directly so the Cat receives the request and the caller hears its saved result.
Summary
handoff_request.input_transcript, reserve eachhandoff_idbefore dispatch, and forward at most once per call. No Codex tool call chooses the destination or supplies the answer.appendSpeech. Replays, conflicts, concurrent requests, disconnects, and uncertain outcomes preserve accepted work and avoid automatic resubmission.error_codevalues to call status so clients distinguish requests that were not sent, uncertain saved results, and connection failures without displaying provider error text.LocalConversation.condense()invoke the condenser without executing pending unconfirmed tools; return 409 when no compatible condenser exists.REST API contract changes
Compared with base OpenAPI
28e8ed273617for public/api/**paths.Issue Number
None.
How to Test
From the repository root:
58 passed on publication commit
02a51ae46, in its own frozen environment. All required pre-commit hooks passed on the three files changed by the handoff repair. The HTTP regression checks authentication, missing-key availability, safe condensation, conversation-bound status, fixed error codes, and no-store caching.Real Codex WebRTC verification, September 19–20, 2026: generated speech with an existing Codex sign-in and a Luna/high saved Cat produced a saved request and answer and returned the answer as audio. A fresh call recalled the same saved test word, saved its new question and answer, and spoke the correct word. Temporary calls and the test conversation were removed afterward. This verifies actual provider round trips; physical iPad microphone/speaker behavior and the API-key transport still need live device/provider validation.
Video/Screenshots
No new browser capture; real audio and saved-event checks were run through WebRTC.
Type
Notes
voice_providerdefaults toopenai; the API path requiresOPENAI_API_KEY. Codex is explicit opt-in and uses a dedicatedcodex_voice_home; there is no automatic credential/provider fallback.codex-cli 0.154.0. Live still must emit a handoff; the protocol does not guarantee that every utterance is saved.🐳 Agent Server images for this PR — GHCR package, pull/run commands, and all pushed tags (click to expand)
• GHCR package: https://github.com/OpenHands/agent-sdk/pkgs/container/agent-server
Variants & Base Images
eclipse-temurin:17-jdkpython-node-runtimepython-node-runtimepython-node-runtimegolang: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:02a51ae-pythonRun
All tags pushed for this build
About Multi-Architecture Support
02a51ae-python) is a multi-arch manifest supporting both amd64 and arm6402a51ae-python-amd64) are also available if needed