You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
session.disconnect() sends session.destroy over RPC and clears local handlers, but does not close the underlying MessageConnection. Any in-flight sendAndWait() continues to await events from the CLI for up to TCP-timeout duration. The method name implies abortive semantics; the behavior is cooperative signaling.
Repro
constclient=newCopilotClient();awaitclient.start();constsession=awaitclient.createSession({/* ... */});// Start a long-running callconstinflight=session.sendAndWait({prompt: "Write a very long story..."});// Try to abort after 5 secondssetTimeout(async()=>{awaitsession.disconnect();console.log("disconnect() returned");},5000);// `inflight` does NOT reject after disconnect returns; it continues to// pend for up to 30–90 minutes (until the CLI's natural completion or// TCP timeout).awaitinflight;
Expected
disconnect() returns → underlying transport closed → in-flight sendAndWait() rejects with a clean SessionAborted (or similar) error → consumer can release resources immediately.
Actual
disconnect() returns immediately but the JSON-RPC transport stays open. The in-flight sendAndWait() is unaffected and continues running until the CLI naturally returns or TCP times out (often 30+ minutes).
Evidence (SDK source)
nodejs/src/session.ts (v0.3.0): disconnect() calls sendRequest("session.destroy", { sessionId }) and clears local eventHandlers. No call to connection.close() or transport-level termination. session.abort() (same file, line ~1073) sends session.abort to cancel the current message at the CLI but also doesn't close the SDK-side transport.
Workaround (consumer-side)
Layer an AbortController on the polling layer plus a "session result ignored" flag so the eventually-resolving sendAndWait doesn't pollute downstream state. ~50–100 LOC of scaffolding that every consumer with reliability requirements has to reinvent.
Suggested fix (pick one)
Enhance abort() to also reject in-flight sendAndWait with a clean SessionAborted error, preserving session validity for new messages. Suits "cancel and retry" consumers.
Add session.disconnect({ force: true }) (or session.kill()) that closes the underlying JSON-RPC connection immediately. Suits "tear down for good" consumers — the watchdog scenario above. Keep current cooperative disconnect() behavior as the default.
Related
Long-running prompt suddenly hangs forever with no error or exception #590 — "Long-running prompt suddenly hangs forever with no error or exception" — describes the symptom from the consumer side. The disconnect-doesn't-abort behavior is one mechanism that contributes to this symptom: even when the consumer notices the hang and tries to recover, disconnect() doesn't free the in-flight call cleanly.
Summary
session.disconnect()sendssession.destroyover RPC and clears local handlers, but does not close the underlyingMessageConnection. Any in-flightsendAndWait()continues to await events from the CLI for up to TCP-timeout duration. The method name implies abortive semantics; the behavior is cooperative signaling.Repro
Expected
disconnect()returns → underlying transport closed → in-flightsendAndWait()rejects with a cleanSessionAborted(or similar) error → consumer can release resources immediately.Actual
disconnect()returns immediately but the JSON-RPC transport stays open. The in-flightsendAndWait()is unaffected and continues running until the CLI naturally returns or TCP times out (often 30+ minutes).Evidence (SDK source)
nodejs/src/session.ts(v0.3.0):disconnect()callssendRequest("session.destroy", { sessionId })and clears localeventHandlers. No call toconnection.close()or transport-level termination.session.abort()(same file, line ~1073) sendssession.abortto cancel the current message at the CLI but also doesn't close the SDK-side transport.Workaround (consumer-side)
Layer an
AbortControlleron the polling layer plus a "session result ignored" flag so the eventually-resolvingsendAndWaitdoesn't pollute downstream state. ~50–100 LOC of scaffolding that every consumer with reliability requirements has to reinvent.Suggested fix (pick one)
abort()to also reject in-flightsendAndWaitwith a cleanSessionAbortederror, preserving session validity for new messages. Suits "cancel and retry" consumers.session.disconnect({ force: true })(orsession.kill()) that closes the underlying JSON-RPC connection immediately. Suits "tear down for good" consumers — the watchdog scenario above. Keep current cooperativedisconnect()behavior as the default.Related
disconnect()doesn't free the in-flight call cleanly.Environment