/** * NeuroLink - Unified AI Interface with Real MCP Tool Integration * * REDESIGNED FALLBACK CHAIN - NO CIRCULAR DEPENDENCIES * Enhanced AI provider system with natural MCP tool access. * Uses real MCP infrastructure for tool discovery and execution. */ import type { CompactionConfig, CompactionResult, SpanData, ObservabilityConfig, MetricsSummary, MCPToolAnnotations, TraceView, AuthenticatedContext, AuthProvider, JsonObject, NeuroLinkEvents, TypedEventEmitter, MCPEnhancementsConfig, NeuroLinkAuthConfig, NeurolinkConstructorConfig, ChatMessage, ExternalMCPOperationResult, ExternalMCPServerInstance, ExternalMCPToolInfo, GenerateOptions, GenerateResult, ProviderStatus, TextGenerationOptions, TextGenerationResult, MCPExecutableTool, MCPServerInfo, MCPStatus, StreamOptions, StreamResult, ToolExecutionContext, ToolExecutionSummary, ToolInfo, ToolRegistrationOptions, BatchOperationResult, StreamGenerationEndContext } from "./types/index.js"; import { ConversationMemoryManager } from "./core/conversationMemoryManager.js"; import type { RedisConversationMemoryManager } from "./core/redisConversationMemoryManager.js"; import { ExternalServerManager } from "./mcp/externalServerManager.js"; import { MCPToolRegistry } from "./mcp/toolRegistry.js"; import type { DynamicOptions } from "./types/index.js"; import { TaskManager } from "./tasks/taskManager.js"; /** * Curator P2-4 dedup (concurrency-safe): native providers emit * `generation:end` on the shared SDK emitter. We attach a fresh * mutable `dedupContext` object directly to the per-call * `StreamOptions` (under `_streamDedupContext`) so each stream gets * its own instance — concurrent streams have different option objects * and therefore different contexts, so they cannot interfere. * * Native provider emit sites read `options._streamDedupContext` and * flip `.providerEmitted = true` before emitting; the orchestration's * finally block reads the same closed-over reference and skips its * own emit when the flag is set. * * This avoids the AsyncLocalStorage approach which doesn't reliably * propagate through async-generator yield boundaries when iteration * happens from outside the original `run()` scope (e.g. when the * consumer drives `for await of result.stream` after `sdk.stream(...)` * returns). */ export declare const STREAM_DEDUP_CONTEXT_KEY: "_streamDedupContext"; /** * Native providers call this from their `generation:end` emit sites, * passing the same `options` object they received. Safe no-op when * the field isn't set. */ export declare function markStreamProviderEmittedGenerationEnd(options: { _streamDedupContext?: StreamGenerationEndContext; } | undefined): void; /** * Symbol-based brand for cross-module identification without circular imports. * * Provider constructors receive `sdk?: unknown` (the factory layer's * contract). Rather than duck-typing via `"getInMemoryServers" in sdk`, * use `isNeuroLink(value)` from this module to do a brand check — * survives minification AND doesn't rely on method-name stability. */ export declare const NEUROLINK_BRAND: unique symbol; /** * Type-guard for opaque values that should be a {@link NeuroLink} instance. * * Designed for the provider-factory boundary where TS can't carry the type * through `UnknownRecord` without forcing every caller into a circular * dependency. Cheap to call and unaffected by minification. */ export declare function isNeuroLink(value: unknown): value is NeuroLink; export declare class NeuroLink { private mcpInitialized; private mcpSkipped; private mcpInitPromise; private emitter; private _taskManager?; private _taskManagerConfig?; private toolRegistry; private autoDiscoveredServerInfos; private externalServerManager; private toolCache; private readonly toolCacheDuration; private modelAliasConfig?; private lastCompactionMessageCount; /** Extract sessionId from options context for compaction watermark keying */ private getCompactionSessionId; private mcpToolResultCache?; private mcpToolRouter?; private mcpToolBatcher?; private mcpEnhancedDiscovery?; private mcpToolMiddlewares; /** Artifact store for externalized MCP tool outputs (set when strategy=externalize). */ private mcpArtifactStore?; private _disableToolCacheForCurrentRequest; private mcpEnhancementsConfig?; private toolCircuitBreakers; private toolExecutionMetrics; private currentStreamToolExecutions; private toolExecutionHistory; private activeToolExecutions; /** * Helper method to emit tool end event in a consistent way * Used by executeTool in both success and error paths * @param toolName - Name of the tool * @param startTime - Timestamp when tool execution started * @param success - Whether the tool execution was successful * @param result - The result of the tool execution (optional) * @param error - The error if execution failed (optional) */ private emitToolEndEvent; conversationMemory?: ConversationMemoryManager | RedisConversationMemoryManager | null; private conversationMemoryNeedsInit; private conversationMemoryConfig?; private enableOrchestration; private authProvider?; private pendingAuthConfig?; private authInitPromise?; private credentials?; private readonly fallbackConfig; /** * Merge instance-level credentials with per-call credentials. * * Semantics: **deep merge at the provider level.** For each provider key * present in both `this.credentials` and `callCredentials`, the per-call * fields are merged ON TOP of the instance-level fields, so fields not * mentioned in the per-call slice are preserved. * * Example: * ``` * instance: { openai: { apiKey: "key1", baseURL: "url1" } } * per-call: { openai: { apiKey: "key2" } } * merged: { openai: { apiKey: "key2", baseURL: "url1" } } // baseURL preserved * ``` * * Providers present only in one source are carried through unchanged. * Unrelated providers (not overridden in callCredentials) are carried through * from instance credentials unchanged. */ private resolveCredentials; private hitlManager?; private _sessionCostUsd; private fileRegistry; private cachedFileTools; private memoryInstance?; private memorySDKConfig?; /** * Extract and set Langfuse context from options with proper async scoping */ private setLangfuseContextFromOptions; private createMetricsTraceContext; private enforceSessionBudget; private assertInputText; private applyAuthenticatedRequestContext; private applyGenerateLifecycleMiddleware; private applyStreamLifecycleMiddleware; private initializeMemoryConfig; /** * Lazy initialization for memory — called during generate/stream. */ private ensureMemoryReady; /** * Context storage for tool execution * This context will be merged with any runtime context passed by the AI model */ private toolExecutionContext?; /** * Creates a new NeuroLink instance for AI text generation with MCP tool integration. * * @param config - Optional configuration object * @param config.conversationMemory - Configuration for conversation memory features * @param config.conversationMemory.enabled - Whether to enable conversation memory (default: false) * @param config.conversationMemory.maxSessions - Maximum number of concurrent sessions (default: 100) * @param config.conversationMemory.maxTurnsPerSession - Maximum conversation turns per session (default: 50) * @param config.enableOrchestration - Whether to enable smart model orchestration (default: false) * @param config.hitl - Configuration for Human-in-the-Loop safety features * @param config.hitl.enabled - Whether to enable HITL tool confirmation (default: false) * @param config.hitl.dangerousActions - Keywords that trigger confirmation (default: ['delete', 'remove', 'drop']) * @param config.hitl.timeout - Confirmation timeout in milliseconds (default: 30000) * @param config.hitl.allowArgumentModification - Allow users to modify tool parameters (default: true) * @param config.toolRegistry - Optional tool registry instance for advanced use cases (default: new MCPToolRegistry()) * * @example * ```typescript * // Basic usage * const neurolink = new NeuroLink(); * * // With conversation memory * const neurolink = new NeuroLink({ * conversationMemory: { * enabled: true, * maxSessions: 50, * maxTurnsPerSession: 20 * } * }); * * // With orchestration enabled * const neurolink = new NeuroLink({ * enableOrchestration: true * }); * * // With HITL safety features * const neurolink = new NeuroLink({ * hitl: { * enabled: true, * dangerousActions: ['delete', 'remove', 'drop', 'truncate'], * timeout: 30000, * allowArgumentModification: true * } * }); * ``` * * @throws {Error} When provider registry setup fails * @throws {Error} When conversation memory initialization fails (if enabled) * @throws {Error} When external server manager initialization fails * @throws {Error} When HITL configuration is invalid (if enabled) */ private observabilityConfig?; private metricsAggregator; /** * Per-request metrics trace context backed by AsyncLocalStorage. * Safe for concurrent requests on the same SDK instance. * Context is set via metricsTraceContextStorage.run() in generate/stream. */ private get _metricsTraceContext(); constructor(config?: NeurolinkConstructorConfig); /** * TaskManager — scheduled and self-running tasks. * Lazy-initialized on first access. Configurable via constructor `tasks` option. * The actual async initialization (Redis connect, backend start) happens * lazily inside TaskManager on first operation. */ get tasks(): TaskManager; /** * Initialize provider registry with security settings */ private initializeProviderRegistry; /** * Initialize conversation memory if enabled */ private initializeConversationMemory; /** * Initialize HITL (Human-in-the-Loop) if enabled */ private initializeHITL; /** * Initialize MCP enhancement modules (cache, router, batcher, discovery). * Wires standalone MCP modules into the core SDK execution path. */ private initializeMCPEnhancements; /** * Register file reference tools with the MCP tool registry. * * Creates file access tools (list_attached_files, read_file_section, * search_in_file, get_file_preview) bound to the FileReferenceRegistry * and registers them as direct tools so they're available to LLMs. */ private registerFileTools; /** * Register task management tools bound to a TaskManager instance. * Follows the same factory + registry pattern as registerFileTools(). * Called when TaskManager is created (eagerly or lazily via the `tasks` getter). */ private registerTaskTools; /** * Register memory retrieval tools that allow the AI to access * conversation history, including full tool outputs. * Only registered when Redis conversation memory is active. */ private registerMemoryRetrievalTools; /** Format memory context for prompt inclusion */ private formatMemoryContext; /** * Format memory context from multiple users into a labeled block. */ private formatMultiUserMemoryContext; /** * Determine whether memory should be read (retrieved) for this call. * Respects both the global memory SDK config and per-call overrides. */ private shouldReadMemory; /** * Determine whether memory should be written (stored) for this call. * Respects both the global memory SDK config and per-call overrides. */ private shouldWriteMemory; /** * Retrieve condensed memory for a user (and optionally additional users). * Returns the input text enhanced with memory context, or unchanged if no memory. */ private retrieveMemory; /** * Store a conversation turn in memory (non-blocking). * Calls add(userId, content) which internally condenses old + new via LLM. * Supports additional users with per-user prompt and maxWords overrides. */ private storeMemoryInBackground; /** * Set up HITL event forwarding to main emitter */ private setupHITLEventForwarding; /** * Initialize external server manager with event handlers */ private initializeExternalServerManager; /** * Setup event handlers for external server manager */ private setupExternalServerEventHandlers; /** * Initialize Langfuse observability for AI operations tracking */ private initializeLangfuse; /** * Log constructor completion with final state summary */ private logConstructorComplete; /** * Initialize MCP registry with enhanced error handling and resource cleanup * Uses isolated async context to prevent hanging */ private initializeMCP; /** * Actual one-shot MCP initialization logic. Called at most once per * NeuroLink instance lifetime (unless cleanup() resets the flag). */ private performMCPInitializationOnce; /** * Import performance manager with error handling */ private importPerformanceManager; /** * Perform main MCP initialization logic */ private performMCPInitialization; /** * Initialize tool registry with timeout protection */ private initializeToolRegistryInternal; /** * Initialize provider registry */ private initializeProviderRegistryInternal; /** * Register direct tools server */ private registerDirectToolsServerInternal; /** * Load MCP configuration from .mcp-config.json with parallel loading for improved performance */ private loadMCPConfigurationInternal; /** * Log MCP initialization completion */ private logMCPInitComplete; /** * Apply orchestration to determine optimal provider and model * @param options - Original GenerateOptions * @returns Modified options with orchestrated provider marked in context, or empty object if validation fails */ private applyOrchestration; /** * Apply orchestration to determine optimal provider and model for streaming * @param options - Original StreamOptions * @returns Modified options with orchestrated provider marked in context, or empty object if validation fails */ private applyStreamOrchestration; /** * MAIN ENTRY POINT: Enhanced generate method with new function signature * Replaces both generateText and legacy methods */ /** * Extracts the original prompt text from the provided input. * If a string is provided, it returns the string directly. * If a GenerateOptions object is provided, it returns the input text from the object. * @param optionsOrPrompt The prompt input, either as a string or a GenerateOptions object. * @returns The original prompt text as a string. */ private _extractOriginalPrompt; /** * Generate AI content using the best available provider with MCP tool integration. * This is the primary method for text generation with full feature support. * * @param optionsOrPrompt - Either a string prompt or a comprehensive GenerateOptions object * @param optionsOrPrompt.input - Input configuration object * @param optionsOrPrompt.input.text - The text prompt to send to the AI (required) * @param optionsOrPrompt.provider - AI provider to use ('auto', 'openai', 'anthropic', etc.) * @param optionsOrPrompt.model - Specific model to use (e.g., 'gpt-4', 'claude-3-opus') * @param optionsOrPrompt.temperature - Randomness in response (0.0 = deterministic, 2.0 = very random) * @param optionsOrPrompt.maxTokens - Maximum tokens in response * @param optionsOrPrompt.systemPrompt - System message to set AI behavior * @param optionsOrPrompt.disableTools - Whether to disable MCP tool usage * @param optionsOrPrompt.enableAnalytics - Whether to include usage analytics * @param optionsOrPrompt.enableEvaluation - Whether to include response quality evaluation * @param optionsOrPrompt.context - Additional context for the request * @param optionsOrPrompt.evaluationDomain - Domain for specialized evaluation * @param optionsOrPrompt.toolUsageContext - Context for tool usage decisions * * @returns Promise resolving to GenerateResult with content, usage data, and optional analytics * * @example * ```typescript * // Simple usage with string prompt * const result = await neurolink.generate("What is artificial intelligence?"); * console.log(result.content); * * // Advanced usage with options * const result = await neurolink.generate({ * input: { text: "Explain quantum computing" }, * provider: "openai", * model: "gpt-4", * temperature: 0.7, * maxTokens: 500, * enableAnalytics: true, * enableEvaluation: true, * context: { domain: "science", level: "intermediate" } * }); * * // Access analytics and evaluation data * console.log(result.analytics?.usage); * console.log(result.evaluation?.relevance); * ``` * * @throws {Error} When input text is missing or invalid * @throws {Error} When all providers fail to generate content * @throws {Error} When conversation memory operations fail (if enabled) */ /** * Get observability configuration */ getObservabilityConfig(): ObservabilityConfig | undefined; /** * Check if Langfuse telemetry is enabled * Centralized utility to avoid duplication across providers */ isTelemetryEnabled(): boolean; /** * Get comprehensive telemetry status including Langfuse, OTel, and exporter health */ getTelemetryStatus(): { enabled: boolean; langfuse?: { enabled: boolean; baseUrl?: string; environment?: string; }; openTelemetry?: { enabled: boolean; endpoint?: string; serviceName?: string; }; exporters?: Array<{ name: string; enabled: boolean; healthy: boolean; pendingSpans: number; lastExportTime?: string; latencyMs?: number; errors?: string[]; }>; }; /** * Get aggregated observability metrics (latency, tokens, cost, success rate) */ getMetrics(): MetricsSummary; /** * Get all recorded spans */ getSpans(): SpanData[]; /** * Get traces (spans grouped by traceId with parent-child hierarchy) */ getTraces(): TraceView[]; /** * Reset all collected metrics and spans */ resetMetrics(): void; /** * Record a span for metrics tracking */ recordMetricsSpan(span: SpanData): void; /** * Record a memory operation span to both instance and global metrics aggregators. * This ensures memory spans are visible via sdk.getSpans() and getMetricsAggregator().getSpans(). */ private recordMemorySpan; /** * Public method to initialize Langfuse observability * This method can be called externally to ensure Langfuse is properly initialized */ initializeLangfuseObservability(): Promise; /** * Gracefully shutdown NeuroLink and all MCP connections */ shutdown(): Promise; /** * Initialize event listeners that feed span data to MetricsAggregator. * Listens to generation:end, stream:complete, and tool:end events. */ private initializeMetricsListeners; /** * Generate AI response with comprehensive feature support. * * Primary method for AI generation with support for all NeuroLink features: * - Multi-provider support (14+ providers) * - MCP tool integration * - Structured JSON output with Zod schemas * - Conversation memory (Redis or in-memory) * - HITL security workflows * - Middleware execution * - Multimodal inputs (images, PDFs, CSV) * * @category Generation * * @param optionsOrPrompt - Generation options or simple text prompt * @param optionsOrPrompt.input - Input text and optional files * @param optionsOrPrompt.provider - AI provider name (e.g., 'vertex', 'openai', 'anthropic') * @param optionsOrPrompt.model - Model name to use * @param optionsOrPrompt.tools - MCP tools to enable for this generation * @param optionsOrPrompt.schema - Zod schema for structured output validation * @param optionsOrPrompt.temperature - Sampling temperature (0-2, default: 1.0) * @param optionsOrPrompt.maxTokens - Maximum tokens to generate * @param optionsOrPrompt.thinkingConfig - Extended thinking configuration (thinkingLevel: 'minimal'|'low'|'medium'|'high') * @param optionsOrPrompt.context - Context with conversationId and userId for memory * @returns Promise resolving to generation result with content and metadata * * @example Basic text generation * ```typescript * const result = await neurolink.generate({ * input: { text: 'Explain quantum computing' } * }); * console.log(result.content); * ``` * * @example With specific provider * ```typescript * const result = await neurolink.generate({ * input: { text: 'Write a poem' }, * provider: 'anthropic', * model: 'claude-3-opus' * }); * ``` * * @example With MCP tools * ```typescript * const result = await neurolink.generate({ * input: { text: 'Read README.md and summarize it' }, * tools: ['readFile'] * }); * ``` * * @example With structured output * ```typescript * import { z } from 'zod'; * * const schema = z.object({ * name: z.string(), * age: z.number(), * city: z.string() * }); * * const result = await neurolink.generate({ * input: { text: 'Extract person info: John is 30 years old from NYC' }, * schema: schema * }); * // result.structuredData is type-safe! * ``` * * @example With conversation memory * ```typescript * const result = await neurolink.generate({ * input: { text: 'What did we discuss earlier?' }, * context: { * conversationId: 'conv-123', * userId: 'user-456' * } * }); * ``` * * @example With multimodal input * ```typescript * const result = await neurolink.generate({ * input: { * text: 'Describe this image', * images: ['/path/to/image.jpg'] * }, * provider: 'vertex' * }); * ``` * * @throws {Error} When input text is missing or invalid * @throws {Error} When all providers fail to generate content * @throws {Error} When structured output validation fails * @throws {Error} When HITL approval is denied * * @see {@link GenerateOptions} for all available options * @see {@link GenerateResult} for result structure * @see {@link stream} for streaming generation * @since 1.0.0 */ generate(optionsOrPrompt: GenerateOptions | DynamicOptions | string): Promise; private fireConsumerOnErrorIfNotFired; /** * Curator P2-3: wraps a generate/stream call with the fallback * orchestration (`providerFallback` callback + `modelChain` walker). * * On a model-access-denied error from the inner call: * 1. Resolve the effective callback (per-call > instance > synthesised * from modelChain) and the effective chain (per-call > instance). * 2. Walk attempts: invoke callback (or pop next chain entry) → emit * `model.fallback` event → re-call inner with the new {provider, * model}. * 3. Stop on first success, on a callback returning null, or after * exhausting the chain (throw the most recent error). */ private runWithFallbackOrchestration; private attemptInner; private executeGenerateWithMetricsContext; private executeGenerateRequest; private prepareGenerateRequest; private maybeHandleEarlyGenerateResult; private runStandardGenerateRequest; private maybeApplyGenerateOrchestration; private prepareGenerateAugmentations; private buildGenerateTextOptions; private finalizeGenerateRequestResult; private emitGenerateErrorEvent; /** * Schedule non-blocking memory storage after generate completes. */ private scheduleGenerateMemoryStorage; /** * Handle PPT generation mode */ private generateWithPPT; /** * Dispatch a music-generation request to the registered music handler * for the provider named in `options.output.music.provider`. */ private generateWithMusic; /** * Dispatch an avatar (lip-sync) request to the registered avatar handler * for the provider named in `options.output.avatar.provider`. */ private generateWithAvatar; /** * Generate with workflow engine integration * Returns both original and processed responses for AB testing */ private generateWithWorkflow; /** * Stream with workflow engine integration * Progressive streaming: yields preliminary response (first model) then final synthesis */ private streamWithWorkflow; /** * BACKWARD COMPATIBILITY: Legacy generateText method * Internally calls generate() and converts result format */ generateText(options: TextGenerationOptions): Promise; /** * REDESIGNED INTERNAL GENERATION - NO CIRCULAR DEPENDENCIES * * This method implements a clean fallback chain: * 1. Initialize conversation memory if enabled * 2. Inject conversation history into prompt * 3. Try MCP-enhanced generation if available * 4. Fall back to direct provider generation * 5. Store conversation turn for future context */ private generateTextInternal; private executeGenerateTextInternalWithSpan; private initializeGenerateTextInternalContext; private runGenerateTextInternalFlow; private captureOriginalConversationMessagesForRecovery; private finalizeGenerateTextInternalResult; private handleGenerateTextInternalFailure; private tryRecoverGenerateTextOverflow; /** * Log generateTextInternal start with comprehensive analysis */ private logGenerateTextInternalStart; /** * Emit generation start events */ private emitGenerationStartEvents; /** * Initialize conversation memory for generation * Lazily initializes memory if needed from constructor flags */ private initializeConversationMemoryForGeneration; /** * Attempt MCP generation with retry logic */ private attemptMCPGeneration; /** * Non-retryable tool-error predicate shared by `performMCPGenerationRetries` * and `tryMCPGeneration`. Returns `true` when the error indicates the model * hallucinated a tool name or sent invalid arguments — retrying would * re-trigger the same deterministic failure with the same tool set. * * Belt-and-suspenders: prefers class-identity `.isInstance()` (stable across * Phase 5+ native substitution) but falls back to `error.name` and message * substring checks so cross-module-boundary errors (Jest, bundlers, wrapped * errors) are still caught. The name fallback covers both * `AI_InvalidToolInputError` (current v5/v6 SDK) and the legacy * `AI_InvalidToolArgumentsError` (v4). */ private static isNonRetryableToolError; /** * Perform MCP generation with retry logic */ private performMCPGenerationRetries; /** * Try MCP-enhanced generation (no fallback recursion) */ private tryMCPGeneration; private prepareMCPGenerationContext; private logMCPConversationSummary; private ensureMCPGenerationBudget; private compactMCPConversationForBudget; private generateWithMCPProvider; /** * Direct provider generation (no MCP, no recursion) */ private directProviderGeneration; /** * Create tool-aware system prompt that informs AI about available tools */ /** * Apply per-call tool filtering (whitelist/blacklist) to a ToolInfo array. * Used to filter the tool list before building the system prompt. */ private applyToolInfoFiltering; private createToolAwareSystemPrompt; /** * Execute tools if available through centralized registry * Simplified approach without domain detection - relies on tool registry */ private detectAndExecuteTools; /** * BACKWARD COMPATIBILITY: Legacy streamText method * Internally calls stream() and converts result format */ streamText(prompt: string, options?: Partial): Promise>; /** * Stream AI-generated content in real-time using the best available provider. * This method provides real-time streaming of AI responses with full MCP tool integration. * * @param options - Stream configuration options * @param options.input - Input configuration object * @param options.input.text - The text prompt to send to the AI (required) * @param options.provider - AI provider to use ('auto', 'openai', 'anthropic', etc.) * @param options.model - Specific model to use (e.g., 'gpt-4', 'claude-3-opus') * @param options.temperature - Randomness in response (0.0 = deterministic, 2.0 = very random) * @param options.maxTokens - Maximum tokens in response * @param options.systemPrompt - System message to set AI behavior * @param options.disableTools - Whether to disable MCP tool usage * @param options.enableAnalytics - Whether to include usage analytics * @param options.enableEvaluation - Whether to include response quality evaluation * @param options.context - Additional context for the request * @param options.evaluationDomain - Domain for specialized evaluation * * @returns Promise resolving to StreamResult with an async iterable stream * * @example * ```typescript * // Basic streaming usage * const result = await neurolink.stream({ * input: { text: "Tell me a story about space exploration" } * }); * * // Consume the stream * for await (const chunk of result.stream) { * process.stdout.write(chunk.content); * } * * // Advanced streaming with options * const result = await neurolink.stream({ * input: { text: "Explain machine learning" }, * provider: "openai", * model: "gpt-4", * temperature: 0.7, * enableAnalytics: true, * context: { domain: "education", audience: "beginners" } * }); * * // Access metadata and analytics * console.log(result.provider); * console.log(result.analytics?.usage); * ``` * * @throws {Error} When input text is missing or invalid * @throws {Error} When all providers fail to generate content * @throws {Error} When conversation memory operations fail (if enabled) */ stream(options: StreamOptions | DynamicOptions): Promise; /** * Curator P2-3 / Reviewer Finding #2: stream-fallback that also covers * errors thrown during async iteration (e.g. LiteLLM throwing inside * `createLiteLLMTransformedStream`). The standard * `runWithFallbackOrchestration` only catches errors thrown while the * `StreamResult` is being created — once we hand the iterator back to * the caller, errors raised during consumption used to bypass * `providerFallback` / `modelChain`. * * This wrapper runs the orchestration to get an initial StreamResult, * then wraps `result.stream` so that: * - chunks are forwarded transparently while consumption succeeds * - if iteration throws a model-access-denied error AND no chunks * have been yielded yet, we resolve the next fallback target, * emit `model.fallback`, and recurse * - if chunks were already yielded, the error propagates (mid-stream * recovery isn't safe — the consumer has half a response) */ private streamWithIterationFallback; private executeStreamRequest; private validateStreamRequestOptions; private maybeHandleWorkflowStreamRequest; private runStandardStreamRequest; /** * TTS Mode 2 synthesis helper for the stream() pipeline. * * m5 — extracted from runStandardStreamRequest so the surrounding generator * stays under the max-lines-per-function lint budget. Behaviour preserved * exactly: * - When Mode 2 is enabled (`tts.enabled && tts.useAiResponse`) AND the * model produced non-empty content: synthesises one final audio buffer * and returns it as an `audioChunk` for the caller to `yield`. Resolves * `ttsResolver` with the `TTSResult`. * - When Mode 2 is enabled but synthesis fails: logs a warning and resolves * `ttsResolver` with `undefined`. * - When Mode 2 is requested but skipped (empty content / wrong mode): * resolves `ttsResolver` with `undefined` early so callers awaiting * `result.audio` unblock before the surrounding `finally` cleanup * completes (Issue 7 latency micro-opt — the finally block also resolves * defensively, so this is a redundant early signal, not a coverage fix). */ private synthesizeStreamModeTwo; /** * Prepare stream options: initialize memory, MCP, retrieval, orchestration, * Ollama tool auto-disable, factory processing, and tool detection. */ private prepareStreamOptions; /** * Auto-disable tools for Ollama models that don't support them (stream mode). * Prevents overwhelming smaller models with massive tool descriptions in the system message. */ private autoDisableOllamaStreamTools; /** * Set up event listeners for stream event capture (tool calls, HITL, UI components). * Returns the shared event sequence array and a cleanup function to remove all listeners. */ private setupStreamEventListeners; /** * Handle fallback when the primary stream returns 0 chunks. * Yields chunks from a fallback provider and updates metadata accordingly. */ private handleStreamFallback; /** * Store conversation memory after stream consumption is complete (called from finally block). * Handles conversation memory storage in the background. */ private storeStreamConversationMemory; /** * Validate stream input with comprehensive error reporting */ private validateStreamInput; /** * Emit stream start events */ private emitStreamStartEvents; /** * Create MCP stream */ private createMCPStream; /** * Process stream result */ private processStreamResult; /** * Emit stream end events */ private emitStreamEndEvents; /** * Create stream response */ private createStreamResponse; /** * Handle stream error with fallback */ private handleStreamError; /** * Get the EventEmitter instance to listen to NeuroLink events for real-time monitoring and debugging. * This method provides access to the internal event system that emits events during AI generation, * tool execution, streaming, and other operations for comprehensive observability. * * @returns EventEmitter instance that emits various NeuroLink operation events * * @example * ```typescript * // Basic event listening setup * const neurolink = new NeuroLink(); * const emitter = neurolink.getEventEmitter(); * * // Listen to generation events * emitter.on('generation:start', (event) => { * console.log(`Generation started with provider: ${event.provider}`); * console.log(`Started at: ${new Date(event.timestamp)}`); * }); * * emitter.on('generation:end', (event) => { * console.log(`Generation completed in ${event.responseTime}ms`); * console.log(`Tools used: ${event.toolsUsed?.length || 0}`); * }); * * // Listen to streaming events * emitter.on('stream:start', (event) => { * console.log(`Streaming started with provider: ${event.provider}`); * }); * * emitter.on('stream:end', (event) => { * console.log(`Streaming completed in ${event.responseTime}ms`); * if (event.fallback) console.log('Used fallback streaming'); * }); * * // Listen to tool execution events * emitter.on('tool:start', (event) => { * console.log(`Tool execution started: ${event.toolName}`); * }); * * emitter.on('tool:end', (event) => { * console.log(`Tool ${event.toolName} ${event.success ? 'succeeded' : 'failed'}`); * console.log(`Execution time: ${event.responseTime}ms`); * }); * * // Listen to tool registration events * emitter.on('tools-register:start', (event) => { * console.log(`Registering tool: ${event.toolName}`); * }); * * emitter.on('tools-register:end', (event) => { * console.log(`Tool registration ${event.success ? 'succeeded' : 'failed'}: ${event.toolName}`); * }); * * // Listen to external MCP server events * emitter.on('externalMCP:serverConnected', (event) => { * console.log(`External MCP server connected: ${event.serverId}`); * console.log(`Tools available: ${event.toolCount || 0}`); * }); * * emitter.on('externalMCP:serverDisconnected', (event) => { * console.log(`External MCP server disconnected: ${event.serverId}`); * console.log(`Reason: ${event.reason || 'Unknown'}`); * }); * * emitter.on('externalMCP:toolDiscovered', (event) => { * console.log(`New tool discovered: ${event.toolName} from ${event.serverId}`); * }); * * // Advanced usage with error handling * emitter.on('error', (error) => { * console.error('NeuroLink error:', error); * }); * * // Clean up event listeners when done * function cleanup() { * emitter.removeAllListeners(); * } * * process.on('SIGINT', cleanup); * process.on('SIGTERM', cleanup); * ``` * * @example * ```typescript * // Advanced monitoring with metrics collection * const neurolink = new NeuroLink(); * const emitter = neurolink.getEventEmitter(); * const metrics = { * generations: 0, * totalResponseTime: 0, * toolExecutions: 0, * failures: 0 * }; * * // Collect performance metrics * emitter.on('generation:end', (event) => { * metrics.generations++; * metrics.totalResponseTime += event.responseTime; * metrics.toolExecutions += event.toolsUsed?.length || 0; * }); * * emitter.on('tool:end', (event) => { * if (!event.success) { * metrics.failures++; * } * }); * * // Log metrics every 10 seconds * setInterval(() => { * const avgResponseTime = metrics.generations > 0 * ? metrics.totalResponseTime / metrics.generations * : 0; * * console.log('NeuroLink Metrics:', { * totalGenerations: metrics.generations, * averageResponseTime: `${avgResponseTime.toFixed(2)}ms`, * totalToolExecutions: metrics.toolExecutions, * failureRate: `${((metrics.failures / (metrics.toolExecutions || 1)) * 100).toFixed(2)}%` * }); * }, 10000); * ``` * * **Available Events:** * * **Generation Events:** * - `generation:start` - Fired when text generation begins * - `{ provider: string, timestamp: number }` * - `generation:end` - Fired when text generation completes (or fails / is aborted) * - `{ provider: string, responseTime: number, toolsUsed?: string[], timestamp: number, success?: boolean, aborted?: boolean, error?: string }` * - `success` is `false` for both failures and client aborts; `aborted: true` * distinguishes the latter so consumers can route cancellations * differently from real errors. Pipeline B's metrics span maps * `aborted: true` events to `SpanStatus.WARNING` (not ERROR). * * **Streaming Events:** * - `stream:start` - Fired when streaming begins * - `{ provider: string, timestamp: number }` * - `stream:end` - Fired when streaming completes * - `{ provider: string, responseTime: number, fallback?: boolean }` * * **Tool Events:** * - `tool:start` - Fired when tool execution begins * - `{ toolName: string, timestamp: number }` * - `tool:end` - Fired when tool execution completes * - `{ toolName: string, responseTime: number, success: boolean, timestamp: number }` * - `tools-register:start` - Fired when tool registration begins * - `{ toolName: string, timestamp: number }` * - `tools-register:end` - Fired when tool registration completes * - `{ toolName: string, success: boolean, timestamp: number }` * * **External MCP Events:** * - `externalMCP:serverConnected` - Fired when external MCP server connects * - `{ serverId: string, toolCount?: number, timestamp: number }` * - `externalMCP:serverDisconnected` - Fired when external MCP server disconnects * - `{ serverId: string, reason?: string, timestamp: number }` * - `externalMCP:serverFailed` - Fired when external MCP server fails * - `{ serverId: string, error: string, timestamp: number }` * - `externalMCP:toolDiscovered` - Fired when external MCP tool is discovered * - `{ toolName: string, serverId: string, timestamp: number }` * - `externalMCP:toolRemoved` - Fired when external MCP tool is removed * - `{ toolName: string, serverId: string, timestamp: number }` * - `externalMCP:serverAdded` - Fired when external MCP server is added * - `{ serverId: string, config: MCPServerInfo, toolCount: number, timestamp: number }` * - `externalMCP:serverRemoved` - Fired when external MCP server is removed * - `{ serverId: string, timestamp: number }` * * **Error Events:** * - `error` - Fired when an error occurs * - `{ error: Error, context?: object }` * * @throws {Error} This method does not throw errors as it returns the internal EventEmitter * * @since 1.0.0 * @see {@link https://nodejs.org/api/events.html} Node.js EventEmitter documentation * @see {@link NeuroLink.generate} for events related to text generation * @see {@link NeuroLink.stream} for events related to streaming * @see {@link NeuroLink.executeTool} for events related to tool execution */ getEventEmitter(): TypedEventEmitter; /** * Curator P1-1: synchronous credential health check for a single provider. * * Drives a tiny real call against the provider (1-token completion or * `/models` listing depending on provider) to confirm the configured * credentials are valid. Useful at startup so a service can refuse to * boot if its primary provider's credentials are broken instead of * discovering the problem on first user request. * * @example * ```ts * const health = await neurolink.checkCredentials({ provider: "litellm" }); * if (health.status !== "ok") { * throw new Error(`provider not ready: ${health.detail}`); * } * ``` * * @param input - the provider to check * @returns `{ provider, status, detail }`. Possible status values: * - `"ok"` — credentials valid and provider reachable * - `"missing"` — required env / credentials not configured * - `"expired"` — credentials present but rejected (401/403) * - `"denied"` — credentials valid but team not whitelisted for any model * - `"network"` — provider unreachable (timeout, ECONNREFUSED, DNS) * - `"unknown"` — other error; consult `detail` */ checkCredentials(input: { provider: string; model?: string; }): Promise<{ provider: string; status: "ok" | "missing" | "expired" | "denied" | "network" | "unknown"; detail: string; }>; /** * Emit tool start event with execution tracking * @param toolName - Name of the tool being executed * @param input - Input parameters for the tool * @param startTime - Timestamp when execution started * @returns executionId for tracking this specific execution */ emitToolStart(toolName: string, input: unknown, startTime?: number): string; /** * Emit tool end event with execution summary * @param toolName - Name of the tool that finished * @param result - Result from the tool execution * @param error - Error message if execution failed * @param startTime - When execution started * @param endTime - When execution finished * @param executionId - Optional execution ID for tracking */ emitToolEnd(toolName: string, result?: unknown, error?: string, startTime?: number, endTime?: number, executionId?: string): void; /** * Get current tool execution contexts for stream metadata */ getCurrentToolExecutions(): ToolExecutionContext[]; /** * Get tool execution history */ getToolExecutionHistory(): ToolExecutionSummary[]; /** * Clear current stream tool executions (called at stream start) */ clearCurrentStreamExecutions(): void; /** * Register a custom tool that will be available to all AI providers * @param name - Unique name for the tool * @param tool - Tool in MCPExecutableTool format (unified MCP protocol type) */ registerTool(name: string, tool: MCPExecutableTool, options?: ToolRegistrationOptions): void; /** * Set the context that will be passed to tools during execution * This context will be merged with any runtime context passed by the AI model * @param context - Context object containing session info, tokens, shop data, etc. */ setToolContext(context: Record): void; /** * Get the current tool execution context * @returns Current context or undefined if not set */ getToolContext(): Record | undefined; /** * Clear the tool execution context */ clearToolContext(): void; /** * Register multiple tools at once - Supports both object and array formats * @param tools - Object mapping tool names to MCPExecutableTool format OR Array of tools with names * * Object format (existing): { toolName: MCPExecutableTool, ... } * Array format (Lighthouse compatible): [{ name: string, tool: MCPExecutableTool }, ...] */ registerTools(tools: Record | Array<{ name: string; tool: MCPExecutableTool; }>): void; /** * Unregister a custom tool * @param name - Name of the tool to remove * @returns true if the tool was removed, false if it didn't exist */ unregisterTool(name: string): boolean; /** * Register a global tool middleware that runs on every tool execution. * Middleware receives the tool, params, context, and a next() function. * @param middleware - The middleware function to register * @returns this (for chaining) */ useToolMiddleware(middleware: import("./types/index.js").ToolMiddleware): this; /** * Get all registered tool middlewares */ getToolMiddlewares(): import("./types/index.js").ToolMiddleware[]; /** * Flush any pending batched tool calls immediately */ flushToolBatch(): Promise; /** * Get the current MCP enhancements configuration */ getMCPEnhancementsConfig(): MCPEnhancementsConfig | undefined; /** * Update agentic loop report metadata for a conversation session. * Upserts a report entry by reportId — updates existing or adds new. * Only supported when using Redis conversation memory. * * @param sessionId The session identifier * @param report The agentic loop report metadata to upsert * @param userId Optional user identifier * @throws Error if conversation memory is not initialized or is not Redis-backed * * @example * ```typescript * await neurolink.updateAgenticLoopReport("session-123", { * reportId: "report-abc", * reportType: "META", * reportStatus: "INPROGRESS", * }); * ``` */ updateAgenticLoopReport(sessionId: string, report: import("./types/index.js").AgenticLoopReportMetadata, userId?: string): Promise; /** * Get all registered custom tools * @returns Map of tool names to MCPExecutableTool format */ getCustomTools(): Map; /** * Add an in-memory MCP server (from git diff) * Allows registration of pre-instantiated server objects * @param serverId - Unique identifier for the server * @param serverInfo - Server configuration */ addInMemoryMCPServer(serverId: string, serverInfo: MCPServerInfo): Promise; /** * Get all registered in-memory servers as a Map for ID-based lookup. * * This method is primarily used when you need O(1) lookup by server ID, * such as in `testMCPServer()` for checking if a specific server exists. * * @returns Map of server IDs to MCPServerInfo * @see {@link getInMemoryServerInfos} for array-based access (useful for iteration/spreading) */ getInMemoryServers(): Map; /** * Get in-memory servers as an array of MCPServerInfo. * * This method is the canonical source for in-memory server filtering. * It fetches from the centralized tool registry and filters servers * with the "in-memory" category. * * Use this method when you need to: * - Iterate over all in-memory servers * - Spread servers into another array (e.g., in `listMCPServers()`) * - Get a count of in-memory servers * * @returns Array of MCPServerInfo for in-memory servers * @see {@link getInMemoryServers} for Map-based access (useful for ID lookups) */ getInMemoryServerInfos(): MCPServerInfo[]; /** * Get auto-discovered servers as MCPServerInfo - ZERO conversion needed * @returns Array of MCPServerInfo */ getAutoDiscoveredServerInfos(): MCPServerInfo[]; /** * Execute a specific tool by name with robust error handling * Supports both custom tools and MCP server tools with timeout, retry, and circuit breaker patterns * @param toolName - Name of the tool to execute * @param params - Parameters to pass to the tool * @param options - Execution options including optional authentication context * @returns Tool execution result */ executeTool(toolName: string, params?: unknown, options?: { timeout?: number; maxRetries?: number; retryDelayMs?: number; /** Disable tool result caching for this call */ disableToolCache?: boolean; /** Bypass the request batcher for this call */ bypassBatcher?: boolean; authContext?: { userId?: string; sessionId?: string; user?: Record; [key: string]: unknown; }; }): Promise; private createToolExecutionContext; private executeToolWithSpan; private prepareToolExecutionState; private runPreparedToolExecution; private handleSuccessfulToolExecution; private handleFailedToolExecution; /** * Internal tool execution method with MCP enhancements wired in: * - ToolCache: check/store cached results for non-destructive tools * - ToolRouter: route to best server when same tool exists on multiple servers * - Annotations: skip cache for destructive tools, retry safe tools on failure * - Middleware: apply global middleware chain before execution */ private executeToolInternal; /** * Get tool annotations for execution decisions (cache, retry). * Checks cached tool list first, falls back to inference from tool name. */ private getToolAnnotationsForExecution; /** * Get all available tools including custom and in-memory ones * @returns Array of available tools with metadata */ private invalidateToolCache; getAllAvailableTools(): Promise; /** * Get comprehensive status of all AI providers * Primary method for provider health checking and diagnostics */ getProviderStatus(options?: { quiet?: boolean; }): Promise; /** * Test a specific AI provider's connectivity and authentication * @param providerName - Name of the provider to test * @returns Promise resolving to true if provider is working */ testProvider(providerName: string): Promise; /** * Internal method to test provider connection with minimal generation call */ private testProviderConnection; /** * Get the best available AI provider based on configuration and availability * @param requestedProvider - Optional preferred provider name * @returns Promise resolving to the best provider name */ getBestProvider(requestedProvider?: string): Promise; /** * Get list of all available AI provider names * @returns Array of supported provider names */ getAvailableProviders(): Promise; /** * Validate if a provider name is supported * @param providerName - Provider name to validate * @returns True if provider name is valid */ isValidProvider(providerName: string): Promise; /** * Get comprehensive MCP (Model Context Protocol) status information * @returns Promise resolving to MCP status details */ getMCPStatus(): Promise; /** * List all configured MCP servers with their status * @returns Promise resolving to array of MCP server information */ listMCPServers(): Promise; /** * Test connectivity to a specific MCP server * @param serverId - ID of the MCP server to test * @returns Promise resolving to true if server is reachable */ testMCPServer(serverId: string): Promise; /** * Check if a provider has the required environment variables configured * @param providerName - Name of the provider to check * @returns Promise resolving to true if provider has required env vars */ hasProviderEnvVars(providerName: string): Promise; /** * Perform comprehensive health check on a specific provider * @param providerName - Name of the provider to check * @param options - Health check options * @returns Promise resolving to detailed health status */ checkProviderHealth(providerName: string, options?: { timeout?: number; includeConnectivityTest?: boolean; includeModelValidation?: boolean; cacheResults?: boolean; }): Promise<{ provider: string; isHealthy: boolean; isConfigured: boolean; hasApiKey: boolean; lastChecked: Date; error?: string; warning?: string; responseTime?: number; configurationIssues: string[]; recommendations: string[]; }>; /** * Check health of all supported providers * @param options - Health check options * @returns Promise resolving to array of health statuses for all providers */ checkAllProvidersHealth(options?: { timeout?: number; includeConnectivityTest?: boolean; includeModelValidation?: boolean; cacheResults?: boolean; }): Promise>; /** * Get a summary of provider health across all supported providers * @returns Promise resolving to health summary statistics */ getProviderHealthSummary(): Promise<{ total: number; healthy: number; configured: number; hasIssues: number; healthyProviders: string[]; unhealthyProviders: string[]; recommendations: string[]; }>; /** * Clear provider health cache (useful for re-testing after configuration changes) * @param providerName - Optional specific provider to clear cache for */ clearProviderHealthCache(providerName?: string): Promise; /** * Get execution metrics for all tools * @returns Object with execution metrics for each tool */ getToolExecutionMetrics(): Record; }>; /** * NL-004: Set model alias/deprecation configuration. * Models in the alias map will be warned, redirected, or blocked based on their action. * @param config - Model alias configuration with aliases map */ setModelAliasConfig(config: import("./types/index.js").ModelAliasConfig): void; /** * Get circuit breaker status for all tools * @returns Object with circuit breaker status for each tool */ getToolCircuitBreakerStatus(): Record; /** * Reset circuit breaker for a specific tool * @param toolName - Name of the tool to reset circuit breaker for */ resetToolCircuitBreaker(toolName: string): void; /** * Clear all tool execution metrics */ clearToolExecutionMetrics(): void; /** * Get comprehensive tool health report * @returns Detailed health report for all tools */ getToolHealthReport(): Promise<{ totalTools: number; healthyTools: number; unhealthyTools: number; tools: Record; }; circuitBreaker: { state: "closed" | "open" | "half-open"; failureCount: number; }; issues: string[]; recommendations: string[]; }>; }>; /** * Initialize conversation memory if enabled (public method for explicit initialization) * This is useful for testing or when you want to ensure conversation memory is ready * @returns Promise resolving to true if initialization was successful, false otherwise */ ensureConversationMemoryInitialized(): Promise; /** * Get conversation memory statistics (public API) */ getConversationStats(): Promise; /** * Get complete conversation history for a specific session (public API) * @param sessionId - The session ID to retrieve history for * @returns Array of ChatMessage objects in chronological order, or empty array if session doesn't exist */ getConversationHistory(sessionId: string): Promise; /** * Clear conversation history for a specific session (public API) */ clearConversationSession(sessionId: string): Promise; /** * Clear all conversation history (public API) */ clearAllConversations(): Promise; /** * Store tool executions in conversation memory if enabled and Redis is configured * @param sessionId - Session identifier * @param userId - User identifier (optional) * @param toolCalls - Array of tool calls * @param toolResults - Array of tool results * @param currentTime - Date when the tool execution occurred (optional) * @returns Promise resolving when storage is complete */ storeToolExecutions(sessionId: string, userId: string | undefined, toolCalls: Array<{ toolCallId?: string; toolName?: string; args?: Record; [key: string]: unknown; }>, toolResults: Array<{ toolCallId?: string; result?: unknown; error?: string; [key: string]: unknown; }>, currentTime?: Date): Promise; /** * Check if tool execution storage is available * @returns boolean indicating if Redis storage is configured and available */ isToolExecutionStorageAvailable(): boolean; /** * Get the raw messages array for a session. * Returns the full messages list without context filtering or summarization. * @param sessionId - The session ID to retrieve messages for * @returns Array of ChatMessage objects, or empty array if session doesn't exist */ getSessionMessages(sessionId: string, userId?: string): Promise; /** * Replace the entire messages array for a session. * @param sessionId - The session ID to update * @param messages - The new messages array * @param userId - Optional user ID for scoped Redis key lookup */ setSessionMessages(sessionId: string, messages: ChatMessage[], userId?: string): Promise; /** * Modify the last assistant message in a session using a transformer function. * Convenience wrapper around getSessionMessages/setSessionMessages. * @param sessionId - The session ID to modify * @param transformer - Function that receives the last assistant message content and returns the modified content * @param userId - Optional user ID for scoped Redis key lookup * @returns true if a message was modified, false if no assistant message was found */ modifyLastAssistantMessage(sessionId: string, transformer: (content: string) => string, userId?: string): Promise; /** * Add an external MCP server * Automatically discovers and registers tools from the server * @param serverId - Unique identifier for the server * @param config - External MCP server configuration * @returns Operation result with server instance */ addExternalMCPServer(serverId: string, config: MCPServerInfo): Promise>; /** * Remove an external MCP server * Stops the server and removes all its tools * @param serverId - ID of the server to remove * @returns Operation result */ removeExternalMCPServer(serverId: string): Promise>; /** * List all external MCP servers * @returns Array of server health information */ listExternalMCPServers(): Array<{ serverId: string; status: string; toolCount: number; uptime: number; isHealthy: boolean; config: MCPServerInfo; }>; /** * Get external MCP server status * @param serverId - ID of the server * @returns Server instance or undefined if not found */ getExternalMCPServer(serverId: string): ExternalMCPServerInstance | undefined; /** * Execute a tool from an external MCP server * @param serverId - ID of the server * @param toolName - Name of the tool * @param parameters - Tool parameters * @param options - Execution options * @returns Tool execution result */ executeExternalMCPTool(serverId: string, toolName: string, parameters: JsonObject, options?: { timeout?: number; }): Promise; /** * Get all tools from external MCP servers * @returns Array of external tool information */ getExternalMCPTools(): ExternalMCPToolInfo[]; /** * Get tools from a specific external MCP server * @param serverId - ID of the server * @returns Array of tool information for the server */ getExternalMCPServerTools(serverId: string): ExternalMCPToolInfo[]; /** * Test connection to an external MCP server * @param config - Server configuration to test * @returns Test result with connection status */ testExternalMCPConnection(config: MCPServerInfo): Promise; /** * Get external MCP server manager statistics * @returns Statistics about external servers and tools */ getExternalMCPStatistics(): { totalServers: number; connectedServers: number; failedServers: number; totalTools: number; totalConnections: number; totalErrors: number; }; /** * Shutdown all external MCP servers * Called automatically on process exit */ shutdownExternalMCPServers(): Promise; /** * Get the global elicitation manager for interactive tool input * Elicitation allows tools to request additional information from users during execution * @returns The global ElicitationManager instance * @example * ```typescript * const elicitationManager = neurolink.getElicitationManager(); * * // Register a handler for confirmations * elicitationManager.registerHandler(async (request) => { * if (request.type === 'confirmation') { * const answer = await askUser(request.message); * return { confirmed: answer === 'yes' }; * } * }); * ``` */ getElicitationManager(): Promise; /** * Register an elicitation handler for interactive tool input * Handlers are called when tools need user input during execution * @param handler - Function to handle elicitation requests * @example * ```typescript * neurolink.registerElicitationHandler(async (request) => { * switch (request.type) { * case 'confirmation': * return { confirmed: await confirmWithUser(request.message) }; * case 'text': * return { value: await promptUser(request.message) }; * case 'select': * return { value: await selectFromOptions(request.options) }; * } * }); * ``` */ registerElicitationHandler(handler: (request: unknown) => Promise): Promise; /** * Get the multi-server manager for load balancing and coordination * Allows managing multiple MCP servers with failover and load balancing * @returns The global MultiServerManager instance * @example * ```typescript * const multiServer = neurolink.getMultiServerManager(); * * // Create a server group with load balancing * await multiServer.createServerGroup('ai-tools', { * servers: ['openai-server', 'anthropic-server'], * strategy: 'round-robin' * }); * ``` */ getMultiServerManager(): Promise; /** * Get the enhanced tool discovery service * Provides advanced search, filtering, and compatibility checking for tools * @returns EnhancedToolDiscovery instance * @example * ```typescript * const discovery = neurolink.getEnhancedToolDiscovery(); * * // Search for tools by criteria * const results = await discovery.searchTools({ * category: 'data-processing', * capabilities: ['streaming', 'batch'], * minReliability: 0.9 * }); * ``` */ getEnhancedToolDiscovery(): Promise; /** * Get the MCP registry client for discovering servers from registries * Supports multiple registry sources (official, community, custom) * @returns The global MCPRegistryClient instance * @example * ```typescript * const registryClient = neurolink.getMCPRegistryClient(); * * // Search for servers * const servers = await registryClient.searchServers({ * query: 'database', * categories: ['data', 'storage'] * }); * * // Get a well-known server config * const githubServer = registryClient.getWellKnownServer('github'); * ``` */ getMCPRegistryClient(): Promise; /** * Expose a NeuroLink agent as an MCP tool * This allows agents to be called by other systems via MCP * @param agent - The agent to expose (must include id, name, description, and execute) * @param options - Exposure configuration options (prefix, defaultAnnotations, etc.) * @returns The exposed tool definition * @example * ```typescript * const agent = { * id: 'my-agent', * name: 'My Agent', * description: 'An agent that processes data', * execute: async (params) => { ... } * }; * const tool = await neurolink.exposeAgentAsTool(agent, { * prefix: 'agent_' * }); * ``` */ exposeAgentAsTool(agent: { id: string; name: string; description: string; execute: (params: unknown, context?: unknown) => Promise; }, options?: { prefix?: string; includeMetadataInDescription?: boolean; wrapWithContext?: boolean; executionTimeout?: number; enableLogging?: boolean; }): Promise; /** * Expose a workflow as an MCP tool * This allows workflows to be called by other systems via MCP * @param workflow - The workflow to expose (must include id, name, description, and execute) * @param options - Exposure configuration options (prefix, defaultAnnotations, etc.) * @returns The exposed tool definition * @example * ```typescript * const workflow = { * id: 'data-pipeline', * name: 'Data Pipeline', * description: 'Runs the data processing pipeline', * execute: async (params) => { ... } * }; * const tool = await neurolink.exposeWorkflowAsTool(workflow, { * prefix: 'workflow_' * }); * ``` */ exposeWorkflowAsTool(workflow: { id: string; name: string; description: string; execute: (params: unknown, context?: unknown) => Promise; steps?: Array<{ id: string; name: string; description?: string; }>; }, options?: { prefix?: string; includeMetadataInDescription?: boolean; wrapWithContext?: boolean; executionTimeout?: number; enableLogging?: boolean; }): Promise; /** * Get the tool integration manager for middleware and elicitation * Provides advanced tool wrapping with confirmation, timeout, retry, etc. * @returns The global ToolIntegrationManager instance * @example * ```typescript * const integration = neurolink.getToolIntegrationManager(); * * // Register a tool with middleware * integration.registerTool(myTool, { * timeout: 30000, * retries: 3, * requireConfirmation: true * }); * ``` */ getToolIntegrationManager(): Promise; /** * Convert NeuroLink tools to MCP format * Useful for exposing local tools to external MCP clients * @param tools - Array of NeuroLink tool definitions * @param options - Conversion options * @returns Array of MCP-formatted tools * @example * ```typescript * const mcpTools = neurolink.convertToolsToMCPFormat([ * { name: 'myTool', description: 'Does something', execute: async () => {} } * ]); * ``` */ convertToolsToMCPFormat(tools: Array<{ name: string; description: string; execute?: (params: unknown) => unknown; }>, options?: { namespacePrefix?: string; }): Promise; /** * Convert MCP tools to NeuroLink format * Useful for importing tools from external MCP servers * @param tools - Array of MCP tool definitions * @param options - Conversion options * @returns Array of NeuroLink-formatted tools * @example * ```typescript * const neurolinkTools = neurolink.convertToolsFromMCPFormat(externalTools, { * removeNamespacePrefix: 'external_' * }); * ``` */ convertToolsFromMCPFormat(tools: Array<{ name: string; description: string; inputSchema?: unknown; }>, options?: { removeNamespacePrefix?: string; }): Promise; /** * Get tool annotations and safety information * Provides insights about tool behavior, safety levels, and retry-ability * @param toolName - Name of the tool to analyze * @returns Tool annotation summary * @example * ```typescript * const annotations = await neurolink.getToolAnnotations('deleteFile'); * // Returns: { destructive: true, requiresConfirmation: true, safeToRetry: false } * ``` */ getToolAnnotations(toolName: string): Promise<{ annotations: MCPToolAnnotations; summary: string; } | null>; /** * Convert external MCP tools to Vercel AI SDK tool format * This allows AI providers to use external tools directly */ private convertExternalMCPToolsToAISDKFormat; /** * Convert JSON Schema to AI SDK compatible format * For now, we'll skip schema validation and let the AI SDK handle parameters dynamically */ private convertJSONSchemaToAISDKFormat; /** * Unregister external MCP tools from a specific server */ private unregisterExternalMCPToolsFromRegistry; /** * Unregister a specific external MCP tool from the main registry */ private unregisterExternalMCPToolFromRegistry; /** * Lazily initialize conversation memory when needed * This is called the first time a generate or stream operation is performed */ private lazyInitializeConversationMemory; /** * Unregister all external MCP tools from the main registry */ private unregisterAllExternalMCPToolsFromRegistry; /** * Create an evaluation pipeline with the specified configuration or preset. * Pipelines orchestrate multiple scorers to evaluate AI responses comprehensively. * * @param configOrPreset - Pipeline configuration object or preset name * @returns Initialized evaluation pipeline * * @example Using a preset * ```typescript * const neurolink = new NeuroLink(); * const pipeline = await neurolink.createEvaluationPipeline('rag'); * const result = await pipeline.execute({ * query: 'What is the capital of France?', * response: 'Paris is the capital of France.', * context: ['France is a country in Europe. Paris is its capital.'] * }); * console.log(result.overallScore, result.passed); * ``` * * @example Using custom configuration * ```typescript * const pipeline = await neurolink.createEvaluationPipeline({ * name: 'custom-quality', * scorers: [ * { id: 'toxicity', config: { threshold: 0.9 } }, * { id: 'hallucination', config: { weight: 1.5 } }, * { id: 'answer-relevancy' } * ], * aggregation: { method: 'weighted' }, * passThreshold: 0.8 * }); * ``` */ createEvaluationPipeline(configOrPreset: import("./types/index.js").PipelineConfig | "safety" | "rag" | "quality" | "comprehensive" | "minimal" | "summarization" | "customerSupport" | "codeGeneration"): Promise; /** * Evaluate an AI response using the specified pipeline or scorers. * This is a convenience method that creates a pipeline and executes it in one call. * * @param input - Scorer input containing query, response, and optional context * @param options - Evaluation options including pipeline preset or custom scorers * @returns Evaluation pipeline result with scores and pass/fail status * * @example Using a preset * ```typescript * const neurolink = new NeuroLink(); * const result = await neurolink.evaluate( * { * query: 'Explain quantum computing', * response: 'Quantum computing uses qubits...' * }, * { pipeline: 'quality' } * ); * console.log(`Score: ${result.overallScore}, Passed: ${result.passed}`); * ``` * * @example Using specific scorers * ```typescript * const result = await neurolink.evaluate( * { * query: 'What causes rain?', * response: 'Rain is caused by water vapor...', * context: ['The water cycle involves evaporation...'] * }, * { scorers: ['hallucination', 'faithfulness', 'answer-relevancy'] } * ); * ``` * * @example Full RAG evaluation * ```typescript * const result = await neurolink.evaluate( * { * query: 'Who wrote Hamlet?', * response: 'Shakespeare wrote Hamlet in 1600.', * context: ['William Shakespeare wrote Hamlet around 1600-1601.'], * groundTruth: 'William Shakespeare' * }, * { pipeline: 'rag' } * ); * ``` */ evaluate(input: import("./types/index.js").ScorerInput, options?: { /** Pipeline preset to use */ pipeline?: "safety" | "rag" | "quality" | "comprehensive" | "minimal" | "summarization" | "customerSupport" | "codeGeneration"; /** Specific scorers to use (alternative to pipeline) */ scorers?: string[]; /** Pass threshold override (0-1) */ passThreshold?: number; /** Execution mode */ executionMode?: "parallel" | "sequential"; /** Correlation ID for tracing */ correlationId?: string; /** Overall evaluation timeout in milliseconds */ timeoutMs?: number; }): Promise; /** * Score a response using a single scorer. * Useful for quick, targeted evaluations without the overhead of a full pipeline. * * @param scorerId - The ID of the scorer to use (e.g., 'toxicity', 'hallucination') * @param input - Scorer input containing query, response, and optional context * @param config - Optional scorer configuration overrides * @returns Score result with value, reasoning, and pass/fail status * * @example Basic scoring * ```typescript * const neurolink = new NeuroLink(); * const result = await neurolink.score('toxicity', { * query: '', * response: 'This is a helpful response about cooking recipes.' * }); * console.log(`Toxicity Score: ${result.score}/10, Passed: ${result.passed}`); * ``` * * @example Hallucination detection * ```typescript * const result = await neurolink.score('hallucination', { * query: 'What year was the Eiffel Tower built?', * response: 'The Eiffel Tower was built in 1889.', * context: ['The Eiffel Tower was constructed from 1887-1889.'] * }); * console.log(`Score: ${result.score}, Reasoning: ${result.reasoning}`); * ``` * * @example With custom threshold * ```typescript * const result = await neurolink.score( * 'faithfulness', * { * query: 'Summarize the article', * response: 'The article discusses...', * context: ['Article content here...'] * }, * { threshold: 0.85, weight: 1.5 } * ); * ``` */ score(scorerId: string, input: import("./types/index.js").ScorerInput, config?: import("./types/index.js").ScorerConfig): Promise; /** * Get a list of all available scorers and their metadata. * Useful for discovering what evaluation capabilities are available. * * @param options - Filter options * @returns Array of scorer metadata * * @example List all scorers * ```typescript * const neurolink = new NeuroLink(); * const scorers = await neurolink.getAvailableScorers(); * for (const scorer of scorers) { * console.log(`${scorer.id}: ${scorer.description} (${scorer.type})`); * } * ``` * * @example Filter by category * ```typescript * const safetyScorers = await neurolink.getAvailableScorers({ * category: 'safety' * }); * console.log('Safety scorers:', safetyScorers.map(s => s.id)); * ``` * * @example Filter by type * ```typescript * const ruleBasedScorers = await neurolink.getAvailableScorers({ * type: 'rule' * }); * ``` */ getAvailableScorers(options?: { /** Filter by category */ category?: import("./types/index.js").ScorerCategory; /** Filter by type */ type?: import("./types/index.js").ScorerType; }): Promise; /** * Get a list of available evaluation pipeline presets. * Presets are pre-configured pipelines for common evaluation scenarios. * * @returns Array of preset names * * @example * ```typescript * const neurolink = new NeuroLink(); * const presets = await neurolink.getEvaluationPresets(); * console.log('Available presets:', presets); * // Output: ['safety', 'rag', 'quality', 'comprehensive', 'minimal', ...] * ``` */ getEvaluationPresets(): Promise; /** * Get details of a specific evaluation preset. * * @param presetName - Name of the preset * @returns Pipeline configuration for the preset * * @example * ```typescript * const neurolink = new NeuroLink(); * const ragPreset = await neurolink.getEvaluationPreset('rag'); * console.log('RAG preset scorers:', ragPreset.scorers.map(s => s.id)); * console.log('Pass threshold:', ragPreset.passThreshold); * ``` */ getEvaluationPreset(presetName: "safety" | "rag" | "quality" | "comprehensive" | "minimal" | "summarization" | "customerSupport" | "codeGeneration"): Promise; /** * Dispose of all resources and cleanup connections * Call this method when done using the NeuroLink instance to prevent resource leaks * Especially important in test environments where multiple instances are created */ dispose(): Promise; /** * Get the tool registry instance * Used internally by server adapters for tool management * @returns The MCPToolRegistry instance */ getToolRegistry(): MCPToolRegistry; /** * Manually trigger context compaction for a session. * Runs the full 4-stage compaction pipeline. */ compactSession(sessionId: string, config?: CompactionConfig): Promise; /** * Get context usage statistics for a session. * Returns token counts, usage ratio, and breakdown by category. */ getContextStats(sessionId: string, provider?: string, model?: string): Promise<{ estimatedInputTokens: number; availableInputTokens: number; usageRatio: number; shouldCompact: boolean; messageCount: number; } | null>; /** * Check if a session needs compaction. */ needsCompaction(sessionId: string, provider?: string, model?: string): boolean; /** * Set the authentication provider for the NeuroLink instance * * @param config - Auth provider or configuration to create one */ setAuthProvider(config: NeuroLinkAuthConfig): Promise; private initializeAuthProviderFromConfig; /** * Get the currently configured authentication provider */ getAuthProvider(): AuthProvider | undefined; /** * Lazily initialize the auth provider from pendingAuthConfig. * Called on first use (generate/stream with auth token) to avoid * async work in the synchronous constructor. */ private ensureAuthProvider; /** * Set the current authentication context for request handling. * * Delegates to the global AuthContextHolder so that auth state is NOT * stored as an instance field (which would leak between concurrent requests * sharing the same NeuroLink singleton). Prefer `runWithAuthContext()` from * `authContext.ts` for proper request-scoped context via AsyncLocalStorage. * * @param context - The authenticated user context */ setAuthContext(context: AuthenticatedContext): Promise; /** * Get the current authentication context. * * Checks AsyncLocalStorage first, then falls back to the global holder. */ getAuthContext(): Promise; /** * Clear the current authentication context */ clearAuthContext(): Promise; /** * Get the external server manager instance * Used internally by server adapters for external MCP server management * @returns The ExternalServerManager instance */ getExternalServerManager(): ExternalServerManager; private buildResolutionContext; /** * Resolve dynamic arguments in GenerateOptions, mutating the options in place. * Only resolves fields that are functions; static values pass through unchanged. */ private resolveDynamicOptions; private resolveDynamicFields; } export declare const neurolink: NeuroLink; export default neurolink;