github / github/copilot-sdk

`session.disconnect()` is cooperative; doesn't abort `sendAndWait` or close the transport

Abierto
#1,273 1 comentario 0 reacciones 0 asignados Ver en GitHub
enhancement
Lenguaje dominante
Java
Estrellas
10.5k
Forks
1.5k
Merge medio
1 d 11 h
PR fusionados (30 d)
128

Descripción

### Summary

`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

```ts
const client = new CopilotClient();
await client.start();
const session = await client.createSession({ /* ... */ });

// Start a long-running call
const inflight = session.sendAndWait({ prompt: "Write a very long story..." });

// Try to abort after 5 seconds
setTimeout(async () => {
await session.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).
await inflight;
```

### 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

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

### Environment

```
- SDK: @github/copilot-sdk@0.3.0
- CLI: @github/copilot@1.0.45
- Node: 22 LTS
- OS: Windows 11 (primary), macOS 14 (secondary)
- Model: claude-sonnet-4-6 (CLI default routing)
```

Guía de contribución

Abrir la guía de contribución

Evaluación

Este issue todavía no se ha evaluado.

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.