Java SDK: add CopilotClient.createCloudSession#1398
Closed
tclem wants to merge 2 commits into
Closed
Conversation
- Add createCloudSession(SessionConfig) to CopilotClient that sends a session.create request without a caller-supplied sessionId, letting the runtime assign one (cloud-managed routing) - Add PendingRoutingState: thread-safe buffer for events and parked request futures that arrive before cloud session registration; bounded at 128 entries per id, drop-oldest; flush on registerAndFlush() - Add SessionRequestBuilder.buildCloudCreateRequest that omits sessionId and provider from the wire payload - Update RpcHandlerDispatcher to accept PendingRoutingState and route all inbound server requests (tool.call, permission, user-input, exit-plan-mode, auto-mode-switch, hooks.invoke, system-message-transform) through resolveSessionForRequest so they park on the pending state when the session is still in flight - Guard createSession against being called with cloud config; guard createCloudSession against caller-supplied sessionId or provider - Preserve existing non-cloud rekey-on-mismatch logic unchanged - 10 new tests in CloudSessionTest covering all 7 contract scenarios; fix RpcHandlerDispatcherTest constructor call for new signature Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Carries forward the Rust SDK PR #1394 review feedback into the Java port: 1. Cap the per-session inbound-request parked-waiter list at 128 (BUFFER_LIMIT). When exceeded, evict the oldest waiter via completeExceptionally("pending session buffer overflow"). The RpcHandlerDispatcher thread blocked in waiter.get() wakes up, catches ExecutionException, and resolveSessionForRequest calls rpc.sendErrorResponse(-32603, ...) so the runtime isn't left waiting on a request id that will never get a reply. Mirrors Rust commit 491b442 and TS commit c167bc3 on PR #1395. 2. decrementGuard now completes all stale waiters internally with a distinct message ("pending session routing ended before session was registered") instead of returning them for callers to complete with ad-hoc strings. A single canonical message lets debugging tell the overflow-eviction path from the create-failed path. Mirrors Rust commit e0ff254 and TS commit c167bc3. 3. Fix isDone() fast path in resolveSessionForRequest: the existing catch-all "fall through" swallowed ExecutionException from an overflow-evicted waiter, sending a generic -32602 "Unknown session" error instead of -32603. Now explicitly catches ExecutionException in the isDone() branch and sends the same -32603 error as the blocking path. Adds two new unit tests in CloudSessionTest: - parkedRequestWaiterBuffer_overflow_evictsOldestWithOverflowMessage: parks 129 waiters, verifies oldest completes with "pending session buffer overflow", remaining 128 resolve normally after registration. - parkedRequestWaiter_guardDropMessage_isDistinctFromOverflowMessage: parks a request via the full handler path, drops the guard without registration, verifies the JSON-RPC error response contains "routing ended before session was registered" but not "buffer overflow". Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Member
Author
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.
Ports
createCloudSessionto the Java SDK, following the same contract as the Rust (#1394) and TypeScript (#1395) implementations.What changed
CopilotClientcreateCloudSession(SessionConfig)— new public API; sendssession.createwithout a caller-suppliedsessionId, letting the runtime assign one (cloud-managed routing); returnsCompletableFuture<CopilotSession>createSessionnow rejectsSessionConfigthat has a non-nullcloudfield withIllegalArgumentExceptioncreateCloudSessionrejects caller-suppliedsessionIdorproviderPendingRoutingState(new class)registerAndFlush()atomically registers the session and drains buffered events/waiters inside the same lock, closing the TOCTOU raceRpcHandlerDispatcherPendingRoutingState(nullable; null = non-cloud, fast path unchanged)tool.call,permission,user-input,exit-plan-mode,auto-mode-switch,hooks.invoke,system-message-transform) now callresolveSessionForRequest, which parks the handler on the pending state for up to 60 s when the session is still in flighthandleSessionEventbuffers events viapendingState.tryBufferNotificationduring the pending windowSessionRequestBuilderbuildCloudCreateRequest(SessionConfig)— omitssessionIdandproviderfrom the wire payloadTests
10 new tests in
CloudSessionTestcovering all 7 contract scenarios:createCloudSessionrejects callersessionIdcreateCloudSessionrejects callerprovidercreateCloudSessionrejects nullcloudcreateSessionrejects cloud configsessionIdabsent in JSON payloadExisting
RpcHandlerDispatcherTest(27 tests) updated for new 4-arg constructor; all pass.