Goal
When a client disconnects from a stateless Gemini request, stop only that request's provider/transport work, then clean up and release its lease without affecting unrelated concurrent requests.
Status
Blocked on request-scoped transport cancellation support.
Phase 4C is intentionally paused. Phase 4D remains independent and may proceed separately.
Why this is blocked
Current direct WebAPI call path:
WebAI-to-API
→ gemini-webapi
→ curl-cffi
→ libcurl
→ Gemini
Cancelling the WebAI endpoint coroutine does not currently provide a reliable request-scoped guarantee that the underlying curl transfer stops.
Closing the shared GeminiClient, AsyncSession, or shared AsyncCurl is not acceptable because concurrent requests may share those resources.
A best-effort disconnect watcher alone is therefore insufficient for the required contract.
Decisions already made
- Do not use shared
GeminiClient.close() for per-request cancellation.
- Do not use shared
AsyncSession.close() or shared AsyncCurl.close().
- Do not treat coroutine cancellation alone as proof that provider work stopped.
- Keep Phase 4D retry/concurrency isolation separate from Phase 4C.
- Prefer an upstream-compatible request-scoped abort mechanism.
- Do not integrate the current prototype API into WebAI or gemini-webapi until the upstream API/lifecycle direction is clearer.
External dependency
Upstream curl-cffi design issue:
A working D1 prototype exists in the curl-cffi fork, rebased onto current upstream main (0.16.2). It validates request isolation, streaming abort, retry-delay interruption, repeated abort handling, wait_closed(), and session reuse.
Current prototype branch:
feat/request-scoped-abort
- prototype commit after rebase:
e77cbb6be96be8e727fc9fb44f4697e292598ab9
- preserved pre-rebase backup:
backup/request-scoped-abort-v0.16.0
Known D1 gap: explicit abort does not yet interrupt a request blocked while waiting in pop_curl() for a pooled Curl handle.
Resume criteria
Resume Phase 4C when one of these is true:
- curl-cffi maintainers agree on an upstream request-scoped cancellation design; or
- we explicitly decide to use a temporary immutable fork/pin with a reviewed API while upstream work continues.
Next steps after unblock
- Finalize or redesign the curl-cffi request-scoped abort API based on upstream feedback.
- Add missing race/lifecycle coverage and prepare a focused upstream PR if appropriate.
- Add D2 propagation through
gemini-webapi, including retry/reinit bypass for explicit abort.
- Add WebAI client-disconnect watching for buffered requests and buffered tool-generation paths.
- On disconnect: abort the exact provider request, await request-local cleanup, release lease, and avoid affecting concurrent requests.
- Add cancellation, cleanup, concurrency-isolation, and regression tests.
- Update stable API/lifecycle documentation only after the final contract is implemented.
Required Phase 4C contract
client disconnect
→ stop only that provider request
→ request-local transport cleanup completes
→ lease/resources are released
→ unrelated concurrent requests continue
→ shared client/session remains reusable
Non-goals
- Playwright stateless backend support.
- Phase 4D retry/concurrency isolation work.
- Closing shared provider/session resources as a cancellation mechanism.
- Broad provider lifecycle redesign unrelated to request-scoped cancellation.
Goal
When a client disconnects from a stateless Gemini request, stop only that request's provider/transport work, then clean up and release its lease without affecting unrelated concurrent requests.
Status
Blocked on request-scoped transport cancellation support.
Phase 4C is intentionally paused. Phase 4D remains independent and may proceed separately.
Why this is blocked
Current direct WebAPI call path:
Cancelling the WebAI endpoint coroutine does not currently provide a reliable request-scoped guarantee that the underlying curl transfer stops.
Closing the shared
GeminiClient,AsyncSession, or sharedAsyncCurlis not acceptable because concurrent requests may share those resources.A best-effort disconnect watcher alone is therefore insufficient for the required contract.
Decisions already made
GeminiClient.close()for per-request cancellation.AsyncSession.close()or sharedAsyncCurl.close().External dependency
Upstream curl-cffi design issue:
A working D1 prototype exists in the curl-cffi fork, rebased onto current upstream
main(0.16.2). It validates request isolation, streaming abort, retry-delay interruption, repeated abort handling,wait_closed(), and session reuse.Current prototype branch:
feat/request-scoped-aborte77cbb6be96be8e727fc9fb44f4697e292598ab9backup/request-scoped-abort-v0.16.0Known D1 gap: explicit abort does not yet interrupt a request blocked while waiting in
pop_curl()for a pooled Curl handle.Resume criteria
Resume Phase 4C when one of these is true:
Next steps after unblock
gemini-webapi, including retry/reinit bypass for explicit abort.Required Phase 4C contract
Non-goals