@juspay/neurolink
Version:
The pipe layer of an AI nervous system: one interface connecting provider neurons to your application, across three inference types — generate, stream and decide. `decide` returns typed, calibrated judgements from a non-generative model (~400ms, ~$0.00002
177 lines (176 loc) • 7.53 kB
TypeScript
/**
* Timeout utilities for NeuroLink
*
* Provides flexible timeout parsing and error handling for AI operations.
* Supports multiple time formats: milliseconds, seconds, minutes, hours.
*/
import type { TimeoutConfig, TimeoutResult } from "../types/index.js";
import { TimeoutError as BaseTimeoutError } from "./async/withTimeout.js";
/**
* Custom error class for timeout operations.
*
* Extends the base {@link BaseTimeoutError} (from `./async/withTimeout.js`)
* rather than `Error` directly, merging what were two independent internal
* `TimeoutError` classes onto one prototype chain — an `instanceof` check
* against either module's `TimeoutError` now recognizes errors thrown by
* this class. Constructor signature, `.name`, and the extra
* `timeout`/`provider`/`operation` fields are unchanged so all 15 existing
* `instanceof TimeoutError` call sites keep working exactly as before;
* `super(message, timeout)` additionally populates the base class's
* `timeoutMs` field (equal to `timeout`) as a byproduct.
*/
export declare class TimeoutError extends BaseTimeoutError {
readonly timeout: number;
readonly provider?: string | undefined;
readonly operation?: "generate" | "stream" | undefined;
constructor(message: string, timeout: number, provider?: string | undefined, operation?: "generate" | "stream" | undefined);
}
/**
* Parse timeout value from various formats
* @param timeout - Can be number (ms), string with unit, or undefined
* @returns Parsed timeout in milliseconds or undefined
* @throws Error if format is invalid
*
* Examples:
* - parseTimeout(5000) => 5000
* - parseTimeout('30s') => 30000
* - parseTimeout('2m') => 120000
* - parseTimeout('1.5h') => 5400000
* - parseTimeout(undefined) => undefined
*/
export declare function parseTimeout(timeout: number | string | undefined): number | undefined;
/**
* Default timeout configurations for different providers and operations
*/
export declare const DEFAULT_TIMEOUTS: {
global: string;
streaming: string;
providers: {
openai: string;
bedrock: string;
vertex: string;
anthropic: string;
azure: string;
"google-ai": string;
huggingface: string;
ollama: string;
mistral: string;
litellm: string;
};
tools: {
default: string;
filesystem: string;
network: string;
computation: string;
};
};
/**
* Get default timeout for a specific provider
* @param provider - Provider name
* @param operation - Operation type (generate or stream)
* @returns Default timeout string
*/
export declare function getDefaultTimeout(provider: string, operation?: "generate" | "stream"): string;
/**
* Create a timeout promise that rejects after specified duration
* @param timeout - Timeout duration
* @param provider - Provider name for error message
* @param operation - Operation type for error message
* @returns Promise that rejects with TimeoutError
*/
export declare function createTimeoutPromise(timeout: number | string | undefined, provider: string, operation: "generate" | "stream"): Promise<never> | null;
/**
* Enhanced timeout manager with proper cleanup and abort controller integration
* Consolidated from timeout-manager.ts
*/
export declare class TimeoutManager {
private activeTimeouts;
/**
* Execute operation with timeout and proper cleanup
*/
executeWithTimeout<T>(operation: () => Promise<T>, config: TimeoutConfig): Promise<TimeoutResult<T>>;
private performSingleOperation;
private getTimeoutMs;
private generateOperationId;
private createTimeoutPromise;
private registerTimeout;
cleanup(operationId: string): void;
gracefulShutdown(): void;
}
/**
* Wrapper functions consolidated from timeout-wrapper.ts
*/
/**
* Wrap a promise with timeout
* @param promise - The promise to wrap
* @param timeout - Timeout duration (number in ms or string with unit)
* @param provider - Provider name for error messages
* @param operation - Operation type (generate or stream)
* @returns The result of the promise or throws TimeoutError
*/
export declare function withTimeout<T>(promise: Promise<T>, timeout: number | string | undefined, provider: string, operation: "generate" | "stream"): Promise<T>;
/**
* Wrap a streaming async generator with timeout
* @param generator - The async generator to wrap
* @param timeout - Timeout duration for the entire stream
* @param provider - Provider name for error messages
* @returns Wrapped async generator that respects timeout
*/
export declare function withStreamingTimeout<T>(generator: AsyncGenerator<T>, timeout: number | string | undefined, provider: string): AsyncGenerator<T>;
/**
* Create an abort controller with timeout
* @param timeout - Timeout duration
* @param provider - Provider name for error messages
* @param operation - Operation type
* @returns AbortController and cleanup function
*/
export declare function createTimeoutController(timeout: number | string | undefined, provider: string, operation: "generate" | "stream"): {
controller: AbortController;
cleanup: () => void;
/**
* Re-arm the timeout window from now. Streaming consumers call this on
* every chunk so the timeout bounds *idle* time rather than total
* duration — a slow-but-alive upstream is not killed mid-generation.
* No-op once the controller has already aborted.
*/
reset: () => void;
timeoutMs: number;
} | null;
/**
* Compose an external abort signal with a timeout controller's signal.
* Returns a single AbortSignal that fires when either signal aborts.
* If only one signal is present, returns it directly without wrapping.
*
* @param externalSignal - User-provided AbortSignal (e.g., from options.abortSignal)
* @param timeoutSignal - Timeout controller's signal
* @returns Combined AbortSignal, or undefined if neither is present
*/
export declare function composeAbortSignals(externalSignal?: AbortSignal, timeoutSignal?: AbortSignal): AbortSignal | undefined;
/**
* Scoped variant of {@link composeAbortSignals} for per-step / per-request
* composition against a LONG-LIVED external signal (e.g. the generate-call
* signal inside a multi-step agent loop). `AbortSignal.any` keeps its source
* registration alive until the derived signal is GC'd, so composing per step
* accumulates listeners on the outer signal for the whole turn
* (MaxListenersExceededWarning at 10+ steps). This helper registers plain
* listeners instead and returns a `dispose()` that removes them the moment
* the step settles.
*/
export declare function composeAbortSignalsScoped(externalSignal?: AbortSignal, timeoutSignal?: AbortSignal): {
signal: AbortSignal | undefined;
dispose: () => void;
};
/**
* Merge abort signals (for combining user abort with timeout)
*
* Implemented via `AbortSignal.any` with a single once-listener forward, so
* no per-source listeners are left behind on long-lived input signals once
* the merged controller becomes unreachable (registrations are released with
* the derived signal). The previous implementation attached one permanent
* listener per source per call — repeated stream calls sharing one caller
* signal accumulated listeners for the life of that signal.
*
* @param signals - Array of abort signals to merge
* @returns Combined abort controller
*/
export declare function mergeAbortSignals(signals: (AbortSignal | undefined)[]): AbortController;