@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
560 lines (559 loc) • 22.5 kB
TypeScript
/**
* NeuroLink Configuration Types
* Centralized configuration type definitions following the established architecture pattern
*/
import type { MCPToolRegistry } from "../mcp/toolRegistry.js";
import type { TaskManagerConfig } from "./task.js";
import type { HITLConfig } from "../types/hitl.js";
import type { ConversationMemoryConfig } from "./conversation.js";
import type { ArtifactStorageConfig } from "./artifact.js";
import type { ObservabilityConfig } from "./observability.js";
import type { AuthProvider, AuthProviderType, AuthProviderConfig, Auth0Config, ClerkConfig, FirebaseConfig, SupabaseConfig, WorkOSConfig, BetterAuthConfig, JWTConfig, OAuth2Config, CognitoConfig, KeycloakConfig, AuthenticatedContext } from "./auth.js";
import type { NeurolinkCredentials } from "./providers.js";
import type { ModelPoolConfig } from "./modelPool.js";
import type { RequestRouter } from "./requestRouter.js";
import type { ClassifierRouterConfig } from "./classifierRouter.js";
import type { ContextRelevanceOptions } from "./context.js";
import type { SkillsConfig } from "./skills.js";
import type { KnowledgeGroundingConfig } from "./knowledge.js";
/**
* Main NeuroLink configuration type
*/
export type NeuroLinkConfig = {
providers?: Record<string, ProviderRuntimeConfig>;
performance?: PerformanceConfig;
analytics?: AnalyticsConfig;
tools?: ToolConfig;
lastUpdated?: number;
configVersion?: string;
[key: string]: unknown;
};
/**
* Curator P2-3: callback signature for centralized fallback policy. When an
* explicit callback is configured (per-call or instance), it is invoked for
* ANY error thrown by a generate/stream call except genuine caller cancels —
* network errors, 5xx, timeouts, auth failures included. A caller cancel is
* identified by the caller-supplied `abortSignal` having fired, not by error
* shape: abort-shaped errors from NeuroLink's own turn/stall watchdogs and
* per-step timeouts DO invoke the callback, so provider hangs can fall back.
* The callback receives the error unmodified so hosts can classify it
* themselves (status codes, `isNonRetryableProviderError`, …). Return
* `{ provider, model }` (either / both optional) to drive a retry; return
* `null` to bubble the original error untouched.
*/
export type ProviderFallbackCallback = (error: unknown) => Promise<{
provider?: string;
model?: string;
} | null>;
/**
* Configuration object for NeuroLink constructor.
*/
export type NeurolinkConstructorConfig = {
conversationMemory?: Partial<ConversationMemoryConfig>;
enableOrchestration?: boolean;
hitl?: HITLConfig;
/**
* Instance-level tool policy: master switch, include/exclude lists
* (with `*` glob support), and on-demand MCP tool discovery.
* See {@link ToolConfig}.
*/
tools?: ToolConfig;
toolRegistry?: MCPToolRegistry;
observability?: ObservabilityConfig;
modelAliasConfig?: ModelAliasConfig;
/** MCP enhancement modules configuration (cache, router, batcher, annotations, middleware) */
mcp?: MCPEnhancementsConfig;
/**
* Artifact storage: where externalized MCP tool outputs and banked payloads
* live. The backend follows `STORAGE_TYPE` exactly like conversation memory
* unless chosen here. See {@link ArtifactStorageConfig}.
*/
artifacts?: ArtifactStorageConfig;
/** Authentication provider configuration */
auth?: NeuroLinkAuthConfig;
/** TaskManager configuration (scheduled and self-running tasks) */
tasks?: TaskManagerConfig;
/**
* Per-provider credential overrides.
* When set here, applies as the default for all generate()/stream() calls
* from this NeuroLink instance. Per-call credentials override these.
*/
credentials?: NeurolinkCredentials;
/**
* Curator P2-3: callback invoked when a generate/stream call fails with
* any error except a genuine caller cancel — i.e. the caller-supplied
* `abortSignal` fired (network errors, 5xx, timeouts, auth failures,
* model-access-denied, and internal watchdog aborts all invoke it). Lets
* a host (e.g. Curator) centrally drive fallback policy — "provider A
* primary, provider B on failure". The callback receives the original
* error unmodified and returns the next `{ provider, model }` to try, or
* `null` to bubble the error.
*/
providerFallback?: ProviderFallbackCallback;
/**
* Curator P2-3: ordered list of model names to try in sequence. Sugar
* over `providerFallback`, but with a narrower trigger: without an
* explicit callback the chain only advances on model-access-denied
* errors — other failures (network, 5xx, timeouts) bubble immediately.
* The current provider is preserved across the chain; only the model
* name changes.
*/
modelChain?: string[];
/**
* Pre-call tool routing: a cheap router LLM picks the tool servers
* relevant to each stream() turn and the unpicked servers' tools are
* dropped from the request via `excludeTools`. Fails open (all tools) on
* any router failure. See {@link ToolRoutingConfig}.
*/
toolRouting?: ToolRoutingConfig;
/**
* Opt-in tool-signature deduplication. When enabled, tools whose
* canonical signatures are sufficiently similar (Jaccard ≥ threshold) are
* collapsed to a single representative before being sent to the model,
* reducing token cost and model confusion caused by near-identical tools.
*
* Disabled by default — enabling this changes nothing unless you
* explicitly set `enabled: true`. Always fails open: any error in the
* dedup pass returns the original tool set unchanged.
*
* See {@link ToolDedupConfig}.
*/
toolDedup?: ToolDedupConfig;
/**
* Multi-provider pool for error-class-aware failover with per-member
* cooldown. When set, generate() and stream() source their candidate
* provider sequence from the pool instead of (or in addition to) the
* static providerPriority fallback. Fails open: a pool error leaves
* existing behavior unchanged.
*/
modelPool?: ModelPoolConfig;
/**
* Pluggable pre-call router: inspects lightweight request characteristics
* (token estimate, tools, vision, thinkingLevel) and returns an optional
* provider/model/region override. Only runs when the caller did NOT
* explicitly set options.provider/options.model. Fails open: a router
* error proceeds unrouted.
*/
requestRouter?: RequestRouter;
/**
* Pre-call classifier router: classifies each request by difficulty and
* selects a provider/model from a configured "available base" pool — routing
* harder tasks to more capable models and easier tasks to cheaper/faster
* ones — and optionally narrows the tool set. Opt-in (`enabled: false` by
* default) and fails open. Skipped when a `modelPool` is configured or the
* caller pinned both `provider` and `model`. See {@link ClassifierRouterConfig}.
*/
classifierRouter?: ClassifierRouterConfig;
/**
* Relevance-driven context compaction. When a decision provider is
* configured, compaction gains a stage-zero pass that drops the earlier
* messages the current request provably does not need, before the
* positional stages (which protect by recency alone) get to choose.
*
* This object only TUNES that stage; it does not enable it. The stage runs
* whenever a decision provider is configured, and does nothing otherwise,
* which is the same activation rule every other decision consumer uses.
*/
contextRelevance?: ContextRelevanceOptions;
/**
* Native skills: versioned, discoverable instruction packs (SOPs,
* playbooks) with progressive disclosure. When enabled, each
* generate()/stream() call gets a skills discovery listing plus
* use_skill / read_skill_resource tools; activated skill instructions
* pin to the session so they are loaded once and replayed from history.
* Opt-in and fails open on read paths. See {@link SkillsConfig}.
*/
skills?: SkillsConfig;
/**
* Knowledge grounding: lexical-first host-supplied knowledge retrieval. When
* enabled with at least one source, a deterministic in-memory retrieval runs
* before each generate()/stream() turn — independently of tool routing — and
* attaches a token-bounded, ephemeral knowledge block to the model call. No
* embeddings or vector store. Opt-in (`enabled: false` by default) and fails
* open: any retrieval failure leaves the turn ungrounded. Sources are fixed
* for the lifetime of the instance. See
* {@link KnowledgeGroundingConfig}.
*/
knowledgeGrounding?: KnowledgeGroundingConfig;
};
/**
* Configuration for MCP enhancement modules wired into generate()/stream() paths.
*
* These modules are automatically applied during tool execution when configured:
* - cache: Tool result caching (enabled by default, opt out with enabled: false)
* - annotations: Auto-infer tool safety metadata (enabled by default)
* - router: Multi-server tool routing (auto-activates with 2+ servers)
* - batcher: Batch programmatic tool calls (disabled by default)
* - discovery: Enhanced tool search and filtering (enabled by default)
* - middleware: Global tool execution middleware chain (empty by default)
*/
export type MCPEnhancementsConfig = {
/** Tool result caching. Default: enabled. Set enabled: false to opt out. */
cache?: {
enabled?: boolean;
/** Cache TTL in milliseconds. Default: 300000 (5 min) */
ttl?: number;
/** Maximum cache entries. Default: 500 */
maxSize?: number;
/** Eviction strategy. Default: 'lru' */
strategy?: CacheStrategy;
};
/** Tool annotation auto-inference. Default: enabled. */
annotations?: {
enabled?: boolean;
/** Auto-infer annotations from tool name/description. Default: true */
autoInfer?: boolean;
};
/** Tool routing for multi-server environments. Auto-activates when 2+ external servers exist. */
router?: {
enabled?: boolean;
/** Routing strategy. Default: 'least-loaded' */
strategy?: RoutingStrategy;
/** Enable session affinity. Default: false */
enableAffinity?: boolean;
};
/** Request batching for programmatic executeTool() calls. Default: disabled. */
batcher?: {
enabled?: boolean;
/** Max requests per batch. Default: 10 */
maxBatchSize?: number;
/** Max wait before flushing batch in ms. Default: 100 */
maxWaitMs?: number;
};
/** Enhanced tool discovery. Default: enabled. */
discovery?: {
enabled?: boolean;
};
/** Global tool middleware applied to every tool execution. Default: empty. */
middleware?: ToolMiddleware[];
/**
* Large MCP tool output handling.
*
* MCP servers can return arbitrarily large payloads. Without limits these
* are loaded entirely into memory, cached in full, stored whole in Redis, and
* injected into the LLM context window — all of which silently fail at scale.
*
* When configured, NeuroLink intercepts oversized outputs at the tool boundary
* (before caching and before memory persistence) and applies the chosen
* strategy so the model receives a compact surrogate instead of a firehose.
*
* Two strategies:
* - "inline" Keep sending the full payload to the model regardless of
* size. A warning is emitted above warnBytes.
* - "externalize" Store the full payload on disk as an artifact and return a
* compact surrogate with a head/tail preview and an artifact
* ID. The model uses `retrieve_context` with that ID to read
* the full output on demand, with offset/limit pagination.
*
* Defaults (when `outputLimits` is set):
* strategy = "externalize"
* maxBytes = 100 KB (100 * 1024)
* warnBytes = 50 KB (50 * 1024)
*/
outputLimits?: {
/** What to do when output exceeds maxBytes. Default: "externalize". */
strategy?: "inline" | "externalize";
/** Byte ceiling above which the strategy fires. Default: 102400 (100 KB). */
maxBytes?: number;
/** Bytes at which a warning is emitted even when still inline. Default: 51200 (50 KB). */
warnBytes?: number;
};
};
/**
* Authentication configuration for NeuroLink SDK
*/
export type NeuroLinkAuthConfig = AuthProvider | {
provider: AuthProvider;
} | {
type: "auth0";
config: Auth0Config;
} | {
type: "clerk";
config: ClerkConfig;
} | {
type: "firebase";
config: FirebaseConfig;
} | {
type: "supabase";
config: SupabaseConfig;
} | {
type: "workos";
config: WorkOSConfig;
} | {
type: "better-auth";
config: BetterAuthConfig;
} | {
type: "jwt";
config: JWTConfig;
} | {
type: "oauth2";
config: OAuth2Config;
} | {
type: "cognito";
config: CognitoConfig;
} | {
type: "keycloak";
config: KeycloakConfig;
} | {
type: AuthProviderType;
config: AuthProviderConfig;
};
/**
* Re-export auth types for convenience
*/
export type { AuthProvider, AuthProviderType, AuthProviderConfig, AuthenticatedContext, };
/**
* Provider-specific configuration
*/
export type ProviderRuntimeConfig = {
model?: string;
available?: boolean;
lastCheck?: number;
reason?: string;
apiKey?: string;
endpoint?: string;
maxTokens?: number;
temperature?: number;
timeout?: number;
costPerToken?: number;
features?: string[];
[key: string]: unknown;
};
/**
* Performance and caching configuration
*/
export type PerformanceConfig = {
cache?: CacheConfig;
fallback?: FallbackConfig;
timeoutMs?: number;
maxConcurrency?: number;
retryConfig?: RetryConfig;
};
/**
* Cache configuration
*/
export type CacheConfig = {
enabled?: boolean;
ttlMs?: number;
strategy?: "memory" | "writeThrough" | "cacheAside";
maxSize?: number;
persistToDisk?: boolean;
diskPath?: string;
};
/**
* Fallback configuration
*/
export type FallbackConfig = {
enabled?: boolean;
maxAttempts?: number;
delayMs?: number;
circuitBreaker?: boolean;
commonResponses?: Record<string, string>;
localFallbackPath?: string;
degradedMode?: boolean;
};
/**
* Retry configuration
*/
export type RetryConfig = {
enabled?: boolean;
maxAttempts?: number;
baseDelayMs?: number;
maxDelayMs?: number;
exponentialBackoff?: boolean;
retryConditions?: string[];
};
/**
* Analytics configuration
*/
export type AnalyticsConfig = {
enabled?: boolean;
trackTokens?: boolean;
trackCosts?: boolean;
trackPerformance?: boolean;
trackErrors?: boolean;
exportFormat?: "json" | "csv" | "prometheus";
exportPath?: string;
retention?: {
days?: number;
maxEntries?: number;
};
};
/**
* Instance-level tool configuration (`new NeuroLink({ tools: {...} })`).
*
* The four primary keys (`enabled`, `include`, `exclude`, `discovery`) form
* the complete modern surface; per-call options (`toolFilter`,
* `excludeTools`, `enabledToolNames`, `disableTools`) keep working and are
* merged with this config by `resolveToolPolicy()`.
*/
export type ToolConfig = {
/**
* Master switch. `false` disables all tools for every call from this
* instance (equivalent to passing `disableTools: true` on each call).
* Default: true.
*/
enabled?: boolean;
/**
* Allowlist of tool names. Supports `*` globs (e.g. `"github*"`).
* Undefined = all tools; an EMPTY array means no tools (fail-closed).
* Per-call `toolFilter` is bounded by this list (a per-call filter can
* narrow it further but never widen past it).
*/
include?: string[];
/** Denylist of tool names (supports `*` globs). Applied after `include`. */
exclude?: string[];
/**
* Defer external MCP tool schemas behind a `search_tools` meta-tool: the
* model sees a compact name+summary catalog instead of full schemas and
* loads a tool on demand by searching for it. Built-in tools, per-call
* tools, per-call whitelists (`toolFilter`/`enabledToolNames`), forced
* `toolChoice` tools, and already-discovered tools are always sent in
* full. Note: the instance-level `include` list deliberately does NOT
* force tools hot — it scopes the catalog, and discovery defers within
* that scope (a scoped-but-large catalog is exactly where deferral pays).
* Default: false.
*/
discovery?: boolean;
/** Whether built-in tools should be disabled (equivalent to excluding all direct tools) */
disableBuiltinTools?: boolean;
/** Whether custom tools are allowed */
allowCustomTools?: boolean;
/**
* @deprecated Never enforced; retained for compile compatibility only.
*/
maxToolsPerProvider?: number;
/** Whether MCP tools should be enabled */
enableMCPTools?: boolean;
/** Whether the bash command execution tool should be enabled (opt-in, defaults to false) */
enableBashTool?: boolean;
/**
* Directories the built-in file tools (readFile, listDirectory, writeFile,
* analyzeCSV) and bash's `cwd` argument may touch. Resolved through
* symlinks; each must be an existing directory. Default: the process
* working directory. An empty array denies all file access. Per-call
* `toolRoots` can only narrow this list. Roots do not sandbox the shell
* commands themselves — a command can still `cd` anywhere.
*/
fileRoots?: string[];
/**
* Byte ceiling for the safety-net truncation `ToolsManager` applies to
* every direct/custom/external-MCP tool result before it reaches the AI
* SDK accumulator (BZ-666). Independent of `mcp.outputLimits`, which only
* governs external MCP results earlier in the pipeline via its own
* externalize-to-artifact-store strategy. Default: 51200 (50 KB) —
* unchanged from the previous hard-coded ceiling, so existing consumers
* see no behavior change unless they set this explicitly.
*/
outputTruncationMaxBytes?: number;
};
/**
* Backup metadata information
*/
export type BackupInfo = {
filename: string;
path: string;
metadata: BackupMetadata;
config: NeuroLinkConfig;
};
/**
* Backup metadata
*/
export type BackupMetadata = {
reason: string;
timestamp: number;
version: string;
originalPath: string;
hash?: string;
size?: number;
createdBy?: string;
};
/**
* Configuration validation result
*/
export type ConfigValidationResult = {
valid: boolean;
errors: string[];
warnings: string[];
suggestions: string[];
};
/**
* Configuration update options
*/
export type ConfigUpdateOptions = {
createBackup?: boolean;
validate?: boolean;
merge?: boolean;
reason?: string;
silent?: boolean;
};
/**
* Default configuration values
*/
export declare const DEFAULT_CONFIG: NeuroLinkConfig;
import { TOOL_TIMEOUTS, BACKOFF_CONFIG, PERFORMANCE_PROFILES, PROVIDER_OPERATION_CONFIGS, MCP_OPERATION_CONFIGS } from "../constants/index.js";
import type { ToolMiddleware, CacheStrategy, RoutingStrategy, ToolDedupConfig, ToolRoutingConfig } from "./index.js";
import type { ModelAliasConfig } from "./generate.js";
/** Timeout category keys from TOOL_TIMEOUTS. */
export type TimeoutCategory = keyof typeof TOOL_TIMEOUTS;
/** Retry strategy keys from BACKOFF_CONFIG. */
export type RetryStrategy = keyof typeof BACKOFF_CONFIG;
/** Performance profile keys from PERFORMANCE_PROFILES. */
export type PerformanceProfile = keyof typeof PERFORMANCE_PROFILES;
/** Provider-specific operation config. */
export type ProviderOperationConfig = (typeof PROVIDER_OPERATION_CONFIGS)[keyof typeof PROVIDER_OPERATION_CONFIGS];
/** MCP-specific operation config. */
export type McpOperationConfig = (typeof MCP_OPERATION_CONFIGS)[keyof typeof MCP_OPERATION_CONFIGS];
/** Configuration options for the token bucket rate limiter. */
export type RateLimiterConfig = {
/** Maximum tokens (downloads) allowed per interval */
maxTokens: number;
/** Refill interval in milliseconds */
refillIntervalMs: number;
/** Number of tokens to add per refill interval */
tokensPerRefill: number;
/** Maximum queue size for pending requests */
maxQueueSize: number;
/** Timeout for queued requests in milliseconds */
queueTimeoutMs: number;
};
/** ThinkingLevel type for Gemini 3 models. */
export type ThinkingLevel = "minimal" | "low" | "medium" | "high";
/** ThinkingConfig matching the SDK's expected structure. */
export type ThinkingConfig = {
enabled?: boolean;
type?: "enabled" | "disabled";
/** Token budget for thinking (Anthropic models: 5000-100000) */
budgetTokens?: number;
/** Thinking level for Gemini 3 models */
thinkingLevel?: ThinkingLevel;
};
/** Options for creating a thinkingConfig from CLI-style options. */
export type CreateThinkingConfigOptions = {
/** Enable thinking mode */
thinking?: boolean;
/** Token budget for thinking (defaults to 10000) */
thinkingBudget?: number;
/** Thinking level for Gemini 3 models */
thinkingLevel?: ThinkingLevel;
};
/**
* Native SDK thinkingConfig structure for Gemini native SDK.
*
* `thinkingLevel` and `thinkingBudget` are mutually exclusive on the wire:
* Gemini 3 models accept `thinkingLevel`; Gemini 2.5 models reject it outright
* with INVALID_ARGUMENT "thinking_level not supported by this model" and
* require the numeric `thinkingBudget` instead. Gemini 2.5 is also the only
* family `createNativeThinkingConfig` emits a budget for:
* `getGemini25ThinkingBudgetRange` has no verified range for anything earlier,
* so those models get no `thinkingConfig` at all — and a one-time WARN —
* rather than a guessed shape that might itself 400.
*
* Both fields are optional here so a single type can represent either shape —
* callers building the request pick whichever field the target model accepts.
*/
export type NativeThinkingConfig = {
includeThoughts: boolean;
thinkingLevel?: ThinkingLevel;
thinkingBudget?: number;
};