Generated via Copilot on behalf of @krukow
query-seq! can leak a session/tap when the lazy seq is abandoned
Found during the GA Phase 2 correctness/async review.
query-seq! (src/github/copilot_sdk/helpers.clj) returns a lazy sequence backed by a
live session and an event tap. The cleanup (finish! / disconnect!) only runs when the
seq is fully realized to its natural end (nil / session.idle / session.error, or
:max-events reached). If a caller abandons the seq early — e.g. (take 1 (query-seq! ...))
or (first ...) — cleanup never runs, leaking the session and its tap.
This is the inherent tension of returning a lazy sequence over a managed resource: the
consumer controls realization, but the resource needs deterministic release.
Proposed resolution (options)
- Document the foot-gun prominently on
query-seq! and steer callers toward query-chan
/ query (which clean up deterministically) when they may not consume the whole seq.
- And/or provide a bounded/closeable variant (explicit
close/with-open-style lifecycle,
or a :max-events-bounded realization) so early termination still releases the session.
Severity: post-ga (no impact when the seq is consumed to completion, which is the
documented usage).
query-seq!can leak a session/tap when the lazy seq is abandonedFound during the GA Phase 2 correctness/async review.
query-seq!(src/github/copilot_sdk/helpers.clj) returns a lazy sequence backed by alive session and an event tap. The cleanup (
finish!/disconnect!) only runs when theseq is fully realized to its natural end (nil /
session.idle/session.error, or:max-eventsreached). If a caller abandons the seq early — e.g.(take 1 (query-seq! ...))or
(first ...)— cleanup never runs, leaking the session and its tap.This is the inherent tension of returning a lazy sequence over a managed resource: the
consumer controls realization, but the resource needs deterministic release.
Proposed resolution (options)
query-seq!and steer callers towardquery-chan/
query(which clean up deterministically) when they may not consume the whole seq.close/with-open-style lifecycle,or a
:max-events-bounded realization) so early termination still releases the session.Severity:
post-ga(no impact when the seq is consumed to completion, which is thedocumented usage).