UNPKG

@tanstack/ai

Version:

Type-safe TypeScript AI SDK for streaming chat, tool calling, agents, structured outputs, and multimodal generation.

42 lines (41 loc) 2.54 kB
import { createCapability } from "./capabilities.js"; //#region src/activities/chat/middleware/run-disconnect.ts /** * Internal seam the chat engine PROVIDES so middleware can learn that the * DELIVERY socket closed while the run is still going — and, crucially, learn it * WITHOUT the run being cancelled. * * WHY THIS EXISTS. Before it, the only way a disconnect reached middleware was for * the application to mirror `request.signal` into `chat()`'s `abortController`, * which ABORTS THE RUN. For a durable run that is precisely wrong, and wrong in * the most expensive direction: `chat()` returns at its `isCancelled()` check * immediately after middleware `setup`, so the harness adapter's `chatStream` is * never called and the agent in the sandbox that `setup` just spent minutes * creating is NEVER LAUNCHED. The user switched away during "starting the * sandbox", came back, and found an empty log belonging to a run that had done * nothing — with no takeover able to recover it, because an agent that never * started wrote no journal to replay. Applications were forced to choose between * "the middleware learns about the disconnect" and "the run survives it". * * So a disconnect is delivered as a NOTIFICATION. `withSandbox` uses it to stamp * `detachedSince`/`sandboxKey` and publish the detach verdict while the run keeps * producing into its still-open durable log — which is exactly what a re-attaching * client tails to catch up. * * A SUBSCRIPTION RATHER THAN A MIDDLEWARE HOOK, deliberately. `ChatMiddleware` is * public API and a new lifecycle hook there is a permanent commitment — including * the obligation to explain that it is the one hook that is NOT terminal. This * concern has exactly one consumer in the tree (`withSandbox`) and it reaches it * through the same internal channel the sandbox layer already uses for its runtime * (`SandboxRuntimeCapability`), so it ships with no public surface at all. * * DISPATCHED FROM THE TRANSPORT, NOT FROM THE RUN'S UNWINDING. That is what makes * it prompt. A run suspended inside a minutes-wide `setup` cannot dispatch anything * from its own `finally`, because the `finally` is reached only once the generator * unwinds — which is what made `detachedSince` land three minutes late. */ var RunDisconnectCapability = createCapability()("run-disconnect"); var [getRunDisconnect, provideRunDisconnect] = RunDisconnectCapability; //#endregion export { RunDisconnectCapability, getRunDisconnect, provideRunDisconnect }; //# sourceMappingURL=run-disconnect.js.map