What happened?
Harness.close() returns without releasing pi-ai resources associated with its pi.provider.sessionId. After a real Codex response, a standalone Node process retained a WebSocket and its five-minute idle timer. Explicit provider-session cleanup allowed it to exit.
A deterministic faux-model reproduction confirms the missing cleanup without FastAgent, MCP, extensions, credentials or network requests. The app and Harness resolve the same pi-ai module. Automatic closure after a storage failure also retains the resource.
Steps to reproduce
- Install
@earendil-works/pi-durable@1.4.0,@earendil-works/pi-ai@1.4.0and@earendil-works/chord@1.4.0. - Run the script in the following comment. It allocates a simulated provider resource under the actual request
sessionIdand registers pi-ai's cleanup callback. - After a completed input,
harness.close()leaves the resource alive with zero cleanup calls.cleanupSessionResources(providerId)then releases it.
This exercises the library Harness, not the pi CLI; pi -ne does not cover this path.
Expected behavior
Release resources for this Harness's provider IDs after running tasks have joined, including failure-driven closure. Preserve the durable IDs for reopening. Global cleanup is unsafe when another Harness is live.
Downstream investigation: https://github.com/fastagent-sh/fastagent/issues/896
Version
pi-durable / pi-ai / chord 1.4.0; Node 26.11.1, macOS. AI-assisted report; tested reproduction and disclosure follow below.
Activity
0No activity yet.