import type { AbortSignal } from 'bare-abort-controller'; import type { DisposableScope } from './disposable-scope.js'; import { createRequestRegistry as createRegistry, type RequestRegistry } from './request-registry.js'; import type { Logger } from '../logging/types.js'; /** * Coarse classification of a long-running request. Used by * `RequestRegistry.cancel({ modelId, kind })` so a broad cancel can target * just one operation kind on a given model (e.g. cancel an in-flight * completion without touching a finetune running on the same model). * * The set is intentionally open-coded — adding a new kind is a one-line * change and the union surfaces in editor autocomplete at every call site. */ export type RequestKind = 'completion' | 'batchCompletion' | 'embeddings' | 'decision' | 'transcribe' | 'translate' | 'diffusion' | 'world' | 'audiogen' | 'tts' | 'ocr' | 'vla' | 'finetune' | 'loadModel' | 'downloadAsset' | 'rag' | 'rpcServer' | 'rpcDiscovery'; /** * Lifecycle states a request transitions through. A new context starts in * `"running"`. `cancel(...)` flips it to `"cancelling"` and aborts the * signal; `end({ outcome: "completed" | "failed" | "cancelled" })` flips * it to a terminal state and removes it from the registry. * * Kept as a string union (not a state machine) on purpose — handlers read * `state` defensively at most a couple of points and a flat enum is easier * to log/assert than a transition table. */ export type RequestState = 'running' | 'cancelling' | 'completed' | 'failed' | 'cancelled'; /** * Per-request lifecycle handle. Created by `RequestRegistry.begin(...)` * and consumed by long-running handlers as the single owner of: * * - `requestId` — stable identity; visible to the caller so it can * target this exact request with `cancel({ requestId })`. * - `signal` — `AbortSignal` that fires when the request is cancelled. * Composes with addon-level cancellation through a single * `signal.addEventListener("abort", ...)` hook installed by the * handler. * - `scope` — `DisposableScope` for `await using` / `Symbol.asyncDispose` * cleanup. The scope unwinds whether the handler returns, throws, or * is cancelled — there is no manual cleanup path for handlers to * forget on the cancel branch. * - `state` — current lifecycle state. Treat as read-mostly; the * registry mutates it. */ export interface RequestContext { readonly requestId: string; readonly kind: RequestKind; readonly modelId: string | undefined; readonly signal: AbortSignal; readonly scope: DisposableScope; state: RequestState; } export declare function getRequestRegistry(): RequestRegistry; export { createRegistry as createRequestRegistry }; export interface RequestLogContext { requestId: string; kind: string; modelId: string | undefined; } /** * Wraps `logger` so every emit is prefixed with * `[request-lifecycle requestId= modelId=] ` * (the `modelId=...` segment is dropped when absent). The wrapper is a * thin shim: `setLevel` / `getLevel` / `addTransport` / `setConsoleOutput` * pass through to the underlying logger, and transport callbacks receive * the prefixed message. * * @example * await using ctx = await registry.begin({ requestId, kind: "completion", modelId }); * const log = withRequestContext(getEngineLogger(), ctx); * log.info("decoding token 7"); * // → "[request-lifecycle completion requestId= modelId=] decoding token 7" */ export declare function withRequestContext(logger: Logger, ctx: RequestLogContext): Logger;