Skip to content

fix(ai): chat connection opens duplicate durable SSE subscriptions for one mounted island #1583

Description

@rickylabs

Reproduction

NetScript 0.0.5 durableStreamConnection / createNetScriptChatConnection is used as the connection passed to TanStack AI Preact useChat({ live: true }).

A single browser page with exactly one ChatPane island produced:

  • 1 component mount
  • 3 renders of the same component instance
  • 0 unmounts before navigation
  • 2 simultaneous live SSE GETs to the same durable chat stream

The evidence came from one Playwright CDP target, so the second request was not the separately launched desktop CEF client. Both live requests remained active. Navigating away aborted both requests and Vite surfaced two The signal has been aborted overlays from @remix-run/node-fetch-server.

On HTTP/1.1 the Durable Streams client also warns that browsers allow about six concurrent connections per origin; duplicate chat subscriptions consume two slots and correlate with page freezes when other session/knowledge streams are active. Two consumers can also process the same durable chunks, which risks duplicate transcript entries.

Expected

The public NetScript chat connection should own one physical live stream per connection/session and either:

  1. make repeated subscribe() calls idempotent/multicast, or
  2. explicitly transfer ownership to the latest subscriber without opening another upstream request.

Teardown should abort one upstream stream and should not surface an application error during normal route navigation.

Acceptance

  • One mounted chat connection opens exactly one physical live subscription across repeated render/subscription attempts.
  • stop() / dispose() aborts the physically in-flight live request.
  • After an explicit subscriber stop, a legitimate re-subscription opens and receives from a fresh upstream request.

Adoption gap

EIS-chat cannot use createNetScriptChatConnection directly as a complete replacement yet because its send adapter narrows TanStack UIMessage values to simplified text messages, losing multimodal parts/attachments and app-owned forwarded request data. A temporary app adapter is therefore required to preserve UIMessage fidelity while enforcing one upstream subscriber.

The adapter can be removed once NetScript provides single-upstream subscription ownership and preserves the full TanStack message/data contract.

Version evidence

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions