Conversation
…oud parents
A Cloud parent has no way to start a child conversation today. Agent Canvas
registers its browser-executed child launch tool only for parents running on
a local agent server, and AppConversationStartRequest cannot carry client
tools.
Add POST /api/v1/webhooks/conversations/{conversation_id}/children as the
Cloud launcher for the SDK's start_child_conversation tool. It authenticates
with the sandbox session key like the other webhook callbacks, checks that
the parent belongs to the calling sandbox, and starts the child through
start_app_conversation as the parent's owner, scoped to the parent's
organization. parent_conversation_id is set on the start request, so the
child inherits the parent's sandbox, repository, branch and model, and the
usual quota and secrets handling applies. The response carries the child's
id, launch status and URL; a failed start comes back as a 500 with the start
task detail.
Attach start_child_conversation to non-planner OpenHands agents whenever
web_url is configured, with launch_url pointing at that endpoint, so the tool
runs inside the sandbox and calls back into the app server instead of
depending on a browser.
This needs an openhands-sdk release that ships start_child_conversation; the
dependency pins are bumped once that release exists.
5 tasks
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
HUMAN:
A Cloud parent has no way to start a child conversation today: Agent Canvas only registers its browser-executed launch tool for parents on a local agent server, and the Cloud start request cannot carry client tools. This adds the Cloud launcher for the SDK's
start_child_conversationtool, so the child goes through the normal app-conversation start and is linked to its parent. Validated with the unit tests and the CI-parity hooks against the SDK branch in OpenHands/software-agent-sdk#5126; the dev-stack walkthrough below is still to be done.AGENT:
Why
Agent Canvas launches child conversations from the browser through a client-defined tool. That makes a side-effecting, billable operation depend on browser event delivery and on a per-browser localStorage ledger to avoid duplicates, and it does not work for Cloud at all:
AppConversationStartRequesthas noclient_tools, so a Cloud-hosted parent never gets the tool.OpenHands/software-agent-sdk#5126 adds a server-executed
start_child_conversationtool that posts{task, title, isolation}to a configurablelaunch_urland returns the child'sconversation_id,statusandurlto the agent. Children of a Cloud parent should run on the same Cloud backend and go through the normal lifecycle (sandbox, repository, credentials, quota), so the launcher has to live here rather than in the sandbox's agent server.The app server already supports sub-conversations end to end:
parent_conversation_idon the start request,_inherit_configuration_from_parent(sandbox, repository, branch, provider, model), the indexed column,sub_conversation_ids, cascade delete and list filtering. What was missing is a way for the agent inside the sandbox to trigger that start without a browser.Summary
POST /api/v1/webhooks/conversations/{conversation_id}/childreninwebhook_router.py. It authenticates with the sandbox session key through the existingvalid_sandboxdependency (the/api/v1/webhooks/prefix is already exempt from the SaaS auth middleware), returns 404 for an unknown parent and rejects a parent owned by another user or sandbox. It then runsstart_app_conversationto completion as the parent's owner, withparent_conversation_idand the task as the initial message, scoped to the parent's organization throughset_effective_org_id_override(resolved fromconversation_metadata_saas, a no-op outside SaaS). It returnsStartChildConversationResponsewith the child id, start-task status and{web_url}/conversations/{id}; a failed start comes back as a 500 carrying the start task's detail._build_start_conversation_request_for_userattachesTool(name="start_child_conversation", params={"launch_url": "{web_url}/api/v1/webhooks/conversations/{conversation_id}/children"})to non-planner OpenHands agents whenweb_urlis configured. Planner and ACP agents are unchanged.tests/unit/app_server/test_webhook_router_child_conversation.py(6) and two cases intest_live_status_app_conversation_service.py.Issue Number
Fixes #278
Linear: https://linear.app/all-hands-ai/issue/OHE-3176/support-server-side-same-backend-child-conversation-launches-in-cloud
Depends on: OpenHands/software-agent-sdk#5126 (OHE-3232)
How to Test
Unit tests and type checking. The pinned
openhands-sdk1.47.0 does not ship the tool yet, so install the SDK branch from feat(agent-server): add start_child_conversation tool with a pluggable launcher software-agent-sdk#5126 over the synced venv. Docker needs to be up for the Postgres testcontainer that the rootconftest.pystarts.The webhook tests pin that one call provisions exactly one child whose start request carries the parent id, title and task; that the launch is scoped to the parent's organization; that the response carries the child id,
READYstatus and URL; that an unknown parent is 404 with nothing started; that a parent from another sandbox raisesAuthErrorwith nothing started; and that anERRORstart task surfaces as a 500 with its detail. The service tests pin the injected tool and itslaunch_url, and that nothing is attached withoutweb_url.Dev-stack walkthrough, with a sandbox image built from the SDK branch:
start_child_conversation.conversation_id, statusREADYand a/conversations/<id>link.GET /api/v1/app-conversations?ids=<child>showsparent_conversation_idset to the parent, the samesandbox_id, and the parent's repository and branch; the parent'ssub_conversation_idslists the child.Video/Screenshots
To be added with the dev-stack walkthrough.
Type
Notes
openhands.tools.child_conversationand the request/response models are not inopenhands-sdk1.47.0, so imports ofwebhook_routerfail in CI until feat(agent-server): add start_child_conversation tool with a pluggable launcher software-agent-sdk#5126 ships in a release and the pins inpyproject.toml/uv.lockare bumped on this branch.Tool(name="start_child_conversation"). Default sandboxes follow the bundled agent-server version, so they move in lockstep; custom images that lag would hit that failure.launch_child_conversationtool attached to every native agent, with no way to route the launch through the host. On Cloud that would create children inside the sandbox outside this lifecycle, andon_conversation_updatewould record them without the parent link, because it only preserves an existingparent_conversation_id. If that shape is chosen instead, the launcher here still applies but the SDK side needs a seam to reach it.start_app_conversationtoREADYwithin the tool call (the SDK tool times out after 300 s) and calls back into the same sandbox agent server while the parent's step is in flight. Locks are per conversation, but this is the main thing to watch on the dev stack.isolationfrom the tool is ignored here: children share the parent's sandbox, and their workspace layout follows the sandbox grouping strategy.Enterprise server image for this PR: