@tanstack/ai
Version:
Type-safe TypeScript AI SDK for streaming chat, tool calling, agents, structured outputs, and multimodal generation.
54 lines (53 loc) • 2.32 kB
JavaScript
//#region src/activities/chat/cancel.ts
/**
* Abort reason that marks an abort as an explicit cancellation.
*
* Namespaced so an application's own reason string cannot collide with it by
* accident, and matched with `===` (never a substring test) so an arbitrary
* provider error message can never be read as a deliberate cancel.
*/
var RUN_CANCEL_REASON = "tanstack-ai:cancel-requested";
/** Whether an abort reason means "the user explicitly cancelled this run". */
function isCancelRequestedReason(reason) {
return reason === RUN_CANCEL_REASON;
}
/**
* Record an explicit cancel on the run record.
*
* Deliberately does NOT set a status. The driver is the only actor that knows
* when the agent has actually stopped and the sandbox has been torn down, so it
* owns the transition to `'aborted'`. Writing a terminal status here would tell
* every reader the run is over while the agent is still burning tokens.
*
* A no-op for an unknown `runId`, inheriting `RunStore.update`'s documented
* invariant.
*/
async function requestRunCancel(runs, runId) {
await runs.update(runId, { cancelRequested: true });
}
/**
* Whether an explicit cancel has been recorded for `runId`.
*
* Answers `false` rather than throwing when the store cannot be read. Callers
* are middleware abort hooks, which are already on a teardown path, and a
* store failure there must not replace the caller's own reason for tearing
* down with a store error. The cost of a false negative is that a cancel
* degrades into a detach — the run record gains `detachedSince`/`sandboxKey`
* instead of transitioning to `'aborted'`. `@tanstack/ai-sandbox`'s
* `reapDetachedRuns` recovers that run once the `detachedRunTtlMs` the
* application passes to that sweep has elapsed — nothing derives it from
* `withSandbox`, which has no TTL option — so the cost is a delayed teardown
* rather than a lost one, provided the application actually schedules the
* sweep, which is its job and not the framework's. Still strictly better than
* failing the teardown.
*/
async function wasCancelRequested(runs, runId) {
try {
return (await runs.get(runId))?.cancelRequested === true;
} catch {
return false;
}
}
//#endregion
export { RUN_CANCEL_REASON, isCancelRequestedReason, requestRunCancel, wasCancelRequested };
//# sourceMappingURL=cancel.js.map