diff --git a/docs/api/classes/NeuroLink.md b/docs/api/classes/NeuroLink.md index 874ef42aa..903988424 100644 --- a/docs/api/classes/NeuroLink.md +++ b/docs/api/classes/NeuroLink.md @@ -14,7 +14,7 @@ Defined in: [neurolink.ts:610](https://github.com/juspay/neurolink/blob/release/ > **new NeuroLink**(`config?`): `NeuroLink` -Defined in: [neurolink.ts:1255](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L1255) +Defined in: [neurolink.ts:1272](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L1272) #### Parameters @@ -32,7 +32,7 @@ Defined in: [neurolink.ts:1255](https://github.com/juspay/neurolink/blob/release > `optional` **conversationMemory?**: `ConversationMemoryManager` \| `RedisConversationMemoryManager` \| `null` -Defined in: [neurolink.ts:713](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L713) +Defined in: [neurolink.ts:730](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L730) ## Accessors @@ -42,7 +42,7 @@ Defined in: [neurolink.ts:713](https://github.com/juspay/neurolink/blob/release/ > **get** **tasks**(): `TaskManager` -Defined in: [neurolink.ts:1416](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L1416) +Defined in: [neurolink.ts:1433](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L1433) TaskManager — scheduled and self-running tasks. Lazy-initialized on first access. Configurable via constructor `tasks` option. @@ -61,7 +61,7 @@ lazily inside TaskManager on first operation. > **generate**(`optionsOrPrompt`): `Promise`\<[`GenerateResult`](../type-aliases/GenerateResult.md)\> -Defined in: [neurolink.ts:4278](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L4278) +Defined in: [neurolink.ts:4295](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L4295) Generate AI response with comprehensive feature support. @@ -191,7 +191,7 @@ When HITL approval is denied > **getSkillsManager**(): [`SkillsManager`](SkillsManager.md) \| `null` -Defined in: [neurolink.ts:2258](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L2258) +Defined in: [neurolink.ts:2275](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L2275) Programmatic access to the skills subsystem (search/list/get/mutations). Returns null when skills are not configured or failed to initialize. @@ -206,7 +206,7 @@ Returns null when skills are not configured or failed to initialize. > **getObservabilityConfig**(): [`ObservabilityConfig`](../type-aliases/ObservabilityConfig.md) \| `undefined` -Defined in: [neurolink.ts:3490](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L3490) +Defined in: [neurolink.ts:3507](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L3507) Get observability configuration @@ -220,7 +220,7 @@ Get observability configuration > **isTelemetryEnabled**(): `boolean` -Defined in: [neurolink.ts:3498](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L3498) +Defined in: [neurolink.ts:3515](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L3515) Check if Langfuse telemetry is enabled Centralized utility to avoid duplication across providers @@ -235,7 +235,7 @@ Centralized utility to avoid duplication across providers > **getTelemetryStatus**(): `object` -Defined in: [neurolink.ts:3510](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L3510) +Defined in: [neurolink.ts:3527](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L3527) Get comprehensive telemetry status including Langfuse, OTel, and exporter health @@ -289,7 +289,7 @@ Get comprehensive telemetry status including Langfuse, OTel, and exporter health > **getMetrics**(): [`MetricsSummary`](../type-aliases/MetricsSummary.md) -Defined in: [neurolink.ts:3565](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L3565) +Defined in: [neurolink.ts:3582](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L3582) Get aggregated observability metrics (latency, tokens, cost, success rate) @@ -303,7 +303,7 @@ Get aggregated observability metrics (latency, tokens, cost, success rate) > **getSpans**(): [`SpanData`](../type-aliases/SpanData.md)[] -Defined in: [neurolink.ts:3572](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L3572) +Defined in: [neurolink.ts:3589](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L3589) Get all recorded spans @@ -317,7 +317,7 @@ Get all recorded spans > **getTraces**(): [`TraceView`](../type-aliases/TraceView.md)[] -Defined in: [neurolink.ts:3579](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L3579) +Defined in: [neurolink.ts:3596](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L3596) Get traces (spans grouped by traceId with parent-child hierarchy) @@ -331,7 +331,7 @@ Get traces (spans grouped by traceId with parent-child hierarchy) > **resetMetrics**(): `void` -Defined in: [neurolink.ts:3586](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L3586) +Defined in: [neurolink.ts:3603](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L3603) Reset all collected metrics and spans @@ -345,7 +345,7 @@ Reset all collected metrics and spans > **recordMetricsSpan**(`span`): `void` -Defined in: [neurolink.ts:3593](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L3593) +Defined in: [neurolink.ts:3610](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L3610) Record a span for metrics tracking @@ -365,7 +365,7 @@ Record a span for metrics tracking > **getProviderMetrics**(`options?`): `Promise`\<[`ProviderMetricsResult`](../type-aliases/ProviderMetricsResult.md)\> -Defined in: [neurolink.ts:3604](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L3604) +Defined in: [neurolink.ts:3621](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L3621) Get provider metrics analysis Retrieves aggregated performance, token usage, latency, and success rates per provider. @@ -390,7 +390,7 @@ Comprehensive provider metrics result > **getCostAnalysis**(`options?`): `Promise`\<[`CostAnalysisResult`](../type-aliases/CostAnalysisResult.md)\> -Defined in: [neurolink.ts:3619](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L3619) +Defined in: [neurolink.ts:3636](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L3636) Get cost analysis breakdown Analyzes AI generation costs across requested groups and provides future projections. @@ -415,7 +415,7 @@ Detailed cost analysis breakdown > **getTeamAnalytics**(`options?`): `Promise`\<[`TeamAnalyticsResult`](../type-aliases/TeamAnalyticsResult.md)\> -Defined in: [neurolink.ts:3632](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L3632) +Defined in: [neurolink.ts:3649](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L3649) Get team-wide usage analytics Retrieves request counts, unique active users, provider breakdown, and quality scoring. @@ -440,7 +440,7 @@ Comprehensive team analytics report > **initializeLangfuseObservability**(): `Promise`\<`void`\> -Defined in: [neurolink.ts:3674](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L3674) +Defined in: [neurolink.ts:3691](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L3691) Public method to initialize Langfuse observability This method can be called externally to ensure Langfuse is properly initialized @@ -455,7 +455,7 @@ This method can be called externally to ensure Langfuse is properly initialized > **shutdown**(): `Promise`\<`void`\> -Defined in: [neurolink.ts:3704](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L3704) +Defined in: [neurolink.ts:3721](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L3721) Gracefully shutdown NeuroLink and all MCP connections @@ -469,7 +469,7 @@ Gracefully shutdown NeuroLink and all MCP connections > **generateText**(`options`): `Promise`\<[`TextGenerationResult`](../type-aliases/TextGenerationResult.md)\> -Defined in: [neurolink.ts:6358](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L6358) +Defined in: [neurolink.ts:6379](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L6379) BACKWARD COMPATIBILITY: Legacy generateText method Internally calls generate() and converts result format @@ -490,7 +490,7 @@ Internally calls generate() and converts result format > **streamText**(`prompt`, `options?`): `Promise`\<`AsyncIterable`\<`string`, `any`, `any`\>\> -Defined in: [neurolink.ts:8730](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L8730) +Defined in: [neurolink.ts:8751](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L8751) BACKWARD COMPATIBILITY: Legacy streamText method Internally calls stream() and converts result format @@ -515,7 +515,7 @@ Internally calls stream() and converts result format > **stream**(`options`): `Promise`\<[`StreamResult`](../type-aliases/StreamResult.md)\> -Defined in: [neurolink.ts:8813](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L8813) +Defined in: [neurolink.ts:8834](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L8834) 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. @@ -588,7 +588,7 @@ When conversation memory operations fail (if enabled) > **setToolRoutingServers**(`servers`): `void` -Defined in: [neurolink.ts:9703](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L9703) +Defined in: [neurolink.ts:9726](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L9726) Supplies (or replaces) the pre-call tool routing server catalog. @@ -613,7 +613,7 @@ alone does not activate it. > **getKnowledgeStatus**(): [`KnowledgeEngineStatus`](../type-aliases/KnowledgeEngineStatus.md) \| `null` -Defined in: [neurolink.ts:9721](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L9721) +Defined in: [neurolink.ts:9744](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L9744) Knowledge-grounding engine health (null when it was not configured). @@ -627,7 +627,7 @@ Knowledge-grounding engine health (null when it was not configured). > **getEventEmitter**(): `TypedEventEmitter`\<[`NeuroLinkEvents`](../type-aliases/NeuroLinkEvents.md)\> -Defined in: [neurolink.ts:12132](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12132) +Defined in: [neurolink.ts:12159](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12159) 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, @@ -833,7 +833,7 @@ This method does not throw errors as it returns the internal EventEmitter > **getToolDedupConfig**(): [`ToolDedupConfig`](../type-aliases/ToolDedupConfig.md) \| `undefined` -Defined in: [neurolink.ts:12148](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12148) +Defined in: [neurolink.ts:12175](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12175) Returns the instance-level tool-dedup configuration, or `undefined` when toolDedup was not provided at construction time. @@ -856,7 +856,7 @@ parameter through the full call stack. > **getToolsConfig**(): [`ToolConfig`](../type-aliases/ToolConfig.md) \| `undefined` -Defined in: [neurolink.ts:12159](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12159) +Defined in: [neurolink.ts:12186](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12186) Returns the instance-level `tools` config (master switch, include/exclude lists, discovery mode), or `undefined` when not provided at construction. @@ -874,7 +874,7 @@ instance policy with per-call options on every generate/stream call. > **getDiscoveryPins**(`sessionKey`): `ReadonlySet`\<`string`\> -Defined in: [neurolink.ts:12170](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12170) +Defined in: [neurolink.ts:12197](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12197) Tools discovered via `search_tools` for a session (`tools.discovery` mode). Pinned tools are sent in full on every subsequent call of that @@ -898,7 +898,7 @@ are never the ones evicted at the session cap. > **pinDiscoveredTools**(`sessionKey`, `toolNames`): `void` -Defined in: [neurolink.ts:12187](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12187) +Defined in: [neurolink.ts:12214](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12214) Pin discovered tools to a session (called by the `search_tools` meta-tool on hydration). Append-only within a session; the map is @@ -924,7 +924,7 @@ bounded by evicting the least-recently-used session past 1000 sessions. > **checkCredentials**(`input`): `Promise`\<\{ `provider`: `string`; `status`: `"network"` \| `"expired"` \| `"unknown"` \| `"ok"` \| `"missing"` \| `"denied"`; `detail`: `string`; \}\> -Defined in: [neurolink.ts:12232](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12232) +Defined in: [neurolink.ts:12259](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12259) Curator P1-1: synchronous credential health check for a single provider. @@ -976,7 +976,7 @@ if (health.status !== "ok") { > **emitToolStart**(`toolName`, `input`, `startTime?`): `string` -Defined in: [neurolink.ts:12311](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12311) +Defined in: [neurolink.ts:12338](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12338) Emit tool start event with execution tracking @@ -1012,7 +1012,7 @@ executionId for tracking this specific execution > **emitToolEnd**(`toolName`, `result?`, `error?`, `startTime?`, `endTime?`, `executionId?`): `void` -Defined in: [neurolink.ts:12362](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12362) +Defined in: [neurolink.ts:12389](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12389) Emit tool end event with execution summary @@ -1064,7 +1064,7 @@ Optional execution ID for tracking > **getCurrentToolExecutions**(): [`ToolExecutionContext`](../type-aliases/ToolExecutionContext.md)[] -Defined in: [neurolink.ts:12443](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12443) +Defined in: [neurolink.ts:12470](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12470) Get current tool execution contexts for stream metadata @@ -1078,7 +1078,7 @@ Get current tool execution contexts for stream metadata > **getToolExecutionHistory**(): [`ToolExecutionSummary`](../type-aliases/ToolExecutionSummary.md)[] -Defined in: [neurolink.ts:12450](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12450) +Defined in: [neurolink.ts:12477](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12477) Get tool execution history @@ -1092,7 +1092,7 @@ Get tool execution history > **clearCurrentStreamExecutions**(): `void` -Defined in: [neurolink.ts:12457](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12457) +Defined in: [neurolink.ts:12484](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12484) Clear current stream tool executions (called at stream start) @@ -1106,7 +1106,7 @@ Clear current stream tool executions (called at stream start) > **registerTool**(`name`, `tool`, `options?`): `void` -Defined in: [neurolink.ts:12473](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12473) +Defined in: [neurolink.ts:12500](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12500) Register a custom tool that will be available to all AI providers @@ -1152,7 +1152,7 @@ Tool in MCPExecutableTool format (unified MCP protocol type) > **setToolContext**(`context`): `void` -Defined in: [neurolink.ts:12614](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12614) +Defined in: [neurolink.ts:12641](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12641) 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 @@ -1175,7 +1175,7 @@ Context object containing session info, tokens, shop data, etc. > **getToolContext**(): `Record`\<`string`, `unknown`\> \| `undefined` -Defined in: [neurolink.ts:12629](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12629) +Defined in: [neurolink.ts:12656](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12656) Get the current tool execution context @@ -1191,7 +1191,7 @@ Current context or undefined if not set > **clearToolContext**(): `void` -Defined in: [neurolink.ts:12638](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12638) +Defined in: [neurolink.ts:12665](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12665) Clear the tool execution context @@ -1205,7 +1205,7 @@ Clear the tool execution context > **registerTools**(`tools`): `void` -Defined in: [neurolink.ts:12650](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12650) +Defined in: [neurolink.ts:12677](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12677) Register multiple tools at once - Supports both object and array formats @@ -1230,7 +1230,7 @@ Array format (Lighthouse compatible): [{ name: string, tool: MCPExecutableTool } > **unregisterTool**(`name`): `boolean` -Defined in: [neurolink.ts:12673](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12673) +Defined in: [neurolink.ts:12700](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12700) Unregister a custom tool @@ -1254,7 +1254,7 @@ true if the tool was removed, false if it didn't exist > **useToolMiddleware**(`middleware`): `this` -Defined in: [neurolink.ts:12691](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12691) +Defined in: [neurolink.ts:12718](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12718) Register a global tool middleware that runs on every tool execution. Middleware receives the tool, params, context, and a next() function. @@ -1279,7 +1279,7 @@ this (for chaining) > **getToolMiddlewares**(): [`ToolMiddleware`](../type-aliases/ToolMiddleware.md)[] -Defined in: [neurolink.ts:12704](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12704) +Defined in: [neurolink.ts:12731](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12731) Get all registered tool middlewares @@ -1293,7 +1293,7 @@ Get all registered tool middlewares > **flushToolBatch**(): `Promise`\<`void`\> -Defined in: [neurolink.ts:12711](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12711) +Defined in: [neurolink.ts:12738](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12738) Flush any pending batched tool calls immediately @@ -1307,7 +1307,7 @@ Flush any pending batched tool calls immediately > **getMCPEnhancementsConfig**(): [`MCPEnhancementsConfig`](../type-aliases/MCPEnhancementsConfig.md) \| `undefined` -Defined in: [neurolink.ts:12720](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12720) +Defined in: [neurolink.ts:12747](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12747) Get the current MCP enhancements configuration @@ -1321,7 +1321,7 @@ Get the current MCP enhancements configuration > **updateAgenticLoopReport**(`sessionId`, `report`, `userId?`): `Promise`\<`void`\> -Defined in: [neurolink.ts:12743](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12743) +Defined in: [neurolink.ts:12770](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12770) Update agentic loop report metadata for a conversation session. Upserts a report entry by reportId — updates existing or adds new. @@ -1371,7 +1371,7 @@ await neurolink.updateAgenticLoopReport("session-123", { > **getCustomTools**(): `Map`\<`string`, \{ `name`: `string`; `description`: `string`; `inputSchema?`: `object`; `execute?`: (`params`, `context?`) => `unknown`; \}\> -Defined in: [neurolink.ts:12779](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12779) +Defined in: [neurolink.ts:12806](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12806) Get all registered custom tools @@ -1387,7 +1387,7 @@ Map of tool names to MCPExecutableTool format > **addInMemoryMCPServer**(`serverId`, `serverInfo`): `Promise`\<`void`\> -Defined in: [neurolink.ts:12917](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12917) +Defined in: [neurolink.ts:12944](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12944) Add an in-memory MCP server (from git diff) Allows registration of pre-instantiated server objects @@ -1416,7 +1416,7 @@ Server configuration > **getInMemoryServers**(): `Map`\<`string`, [`MCPServerInfo`](../type-aliases/MCPServerInfo.md)\> -Defined in: [neurolink.ts:12961](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12961) +Defined in: [neurolink.ts:12988](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12988) Get all registered in-memory servers as a Map for ID-based lookup. @@ -1439,7 +1439,7 @@ Map of server IDs to MCPServerInfo > **getInMemoryServerInfos**(): [`MCPServerInfo`](../type-aliases/MCPServerInfo.md)[] -Defined in: [neurolink.ts:12988](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L12988) +Defined in: [neurolink.ts:13015](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L13015) Get in-memory servers as an array of MCPServerInfo. @@ -1469,7 +1469,7 @@ Array of MCPServerInfo for in-memory servers > **getAutoDiscoveredServerInfos**(): [`MCPServerInfo`](../type-aliases/MCPServerInfo.md)[] -Defined in: [neurolink.ts:13004](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L13004) +Defined in: [neurolink.ts:13031](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L13031) Get auto-discovered servers as MCPServerInfo - ZERO conversion needed @@ -1485,7 +1485,7 @@ Array of MCPServerInfo > **executeTool**\<`T`\>(`toolName`, `params?`, `options?`): `Promise`\<`T`\> -Defined in: [neurolink.ts:13016](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L13016) +Defined in: [neurolink.ts:13043](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L13043) 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 @@ -1566,7 +1566,7 @@ Tool execution result > **getAllAvailableTools**(): `Promise`\<[`ToolInfo`](../type-aliases/ToolInfo.md)[]\> -Defined in: [neurolink.ts:14020](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L14020) +Defined in: [neurolink.ts:14073](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L14073) ##### Returns @@ -1578,7 +1578,7 @@ Defined in: [neurolink.ts:14020](https://github.com/juspay/neurolink/blob/releas > **getProviderStatus**(`options?`): `Promise`\<[`ProviderStatus`](../type-aliases/ProviderStatus.md)[]\> -Defined in: [neurolink.ts:14202](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L14202) +Defined in: [neurolink.ts:14255](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L14255) Get comprehensive status of all AI providers Primary method for provider health checking and diagnostics @@ -1601,7 +1601,7 @@ Primary method for provider health checking and diagnostics > **testProvider**(`providerName`): `Promise`\<`boolean`\> -Defined in: [neurolink.ts:14383](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L14383) +Defined in: [neurolink.ts:14436](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L14436) Test a specific AI provider's connectivity and authentication @@ -1625,7 +1625,7 @@ Promise resolving to true if provider is working > **getBestProvider**(`requestedProvider?`): `Promise`\<`string`\> -Defined in: [neurolink.ts:14415](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L14415) +Defined in: [neurolink.ts:14468](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L14468) Get the best available AI provider based on configuration and availability @@ -1649,7 +1649,7 @@ Promise resolving to the best provider name > **getAvailableProviders**(): `Promise`\<`string`[]\> -Defined in: [neurolink.ts:14424](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L14424) +Defined in: [neurolink.ts:14477](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L14477) Get list of all available AI provider names @@ -1665,7 +1665,7 @@ Array of supported provider names > **isValidProvider**(`providerName`): `Promise`\<`boolean`\> -Defined in: [neurolink.ts:14434](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L14434) +Defined in: [neurolink.ts:14487](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L14487) Validate if a provider name is supported @@ -1689,7 +1689,7 @@ True if provider name is valid > **getMCPStatus**(): `Promise`\<[`MCPStatus`](../type-aliases/MCPStatus.md)\> -Defined in: [neurolink.ts:14447](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L14447) +Defined in: [neurolink.ts:14500](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L14500) Get comprehensive MCP (Model Context Protocol) status information @@ -1705,7 +1705,7 @@ Promise resolving to MCP status details > **listMCPServers**(): `Promise`\<[`MCPServerInfo`](../type-aliases/MCPServerInfo.md)[]\> -Defined in: [neurolink.ts:14517](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L14517) +Defined in: [neurolink.ts:14570](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L14570) List all configured MCP servers with their status @@ -1721,7 +1721,7 @@ Promise resolving to array of MCP server information > **testMCPServer**(`serverId`): `Promise`\<`boolean`\> -Defined in: [neurolink.ts:14532](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L14532) +Defined in: [neurolink.ts:14585](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L14585) Test connectivity to a specific MCP server @@ -1745,7 +1745,7 @@ Promise resolving to true if server is reachable > **hasProviderEnvVars**(`providerName`): `Promise`\<`boolean`\> -Defined in: [neurolink.ts:14573](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L14573) +Defined in: [neurolink.ts:14626](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L14626) Check if a provider has the required environment variables configured @@ -1769,7 +1769,7 @@ Promise resolving to true if provider has required env vars > **checkProviderHealth**(`providerName`, `options?`): `Promise`\<\{ `provider`: `string`; `isHealthy`: `boolean`; `isConfigured`: `boolean`; `hasApiKey`: `boolean`; `lastChecked`: `Date`; `error?`: `string`; `warning?`: `string`; `responseTime?`: `number`; `configurationIssues`: `string`[]; `recommendations`: `string`[]; \}\> -Defined in: [neurolink.ts:14599](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L14599) +Defined in: [neurolink.ts:14652](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L14652) Perform comprehensive health check on a specific provider @@ -1813,7 +1813,7 @@ Promise resolving to detailed health status > **checkAllProvidersHealth**(`options?`): `Promise`\<`object`[]\> -Defined in: [neurolink.ts:14645](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L14645) +Defined in: [neurolink.ts:14698](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L14698) Check health of all supported providers @@ -1851,7 +1851,7 @@ Promise resolving to array of health statuses for all providers > **getProviderHealthSummary**(): `Promise`\<\{ `total`: `number`; `healthy`: `number`; `configured`: `number`; `hasIssues`: `number`; `healthyProviders`: `string`[]; `unhealthyProviders`: `string`[]; `recommendations`: `string`[]; \}\> -Defined in: [neurolink.ts:14689](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L14689) +Defined in: [neurolink.ts:14742](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L14742) Get a summary of provider health across all supported providers @@ -1867,7 +1867,7 @@ Promise resolving to health summary statistics > **clearProviderHealthCache**(`providerName?`): `Promise`\<`void`\> -Defined in: [neurolink.ts:14736](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L14736) +Defined in: [neurolink.ts:14789](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L14789) Clear provider health cache (useful for re-testing after configuration changes) @@ -1889,7 +1889,7 @@ Optional specific provider to clear cache for > **getToolExecutionMetrics**(): `Record`\<`string`, \{ `totalExecutions`: `number`; `successfulExecutions`: `number`; `failedExecutions`: `number`; `successRate`: `number`; `averageExecutionTime`: `number`; `lastExecutionTime`: `number`; `errorCategories`: `Record`\<`string`, `number`\>; \}\> -Defined in: [neurolink.ts:14747](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L14747) +Defined in: [neurolink.ts:14800](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L14800) Get execution metrics for all tools @@ -1905,7 +1905,7 @@ Object with execution metrics for each tool > **setModelAliasConfig**(`config`): `void` -Defined in: [neurolink.ts:14791](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L14791) +Defined in: [neurolink.ts:14844](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L14844) NL-004: Set model alias/deprecation configuration. Models in the alias map will be warned, redirected, or blocked based on their action. @@ -1928,7 +1928,7 @@ Model alias configuration with aliases map > **getToolCircuitBreakerStatus**(): `Record`\<`string`, \{ `state`: `"closed"` \| `"open"` \| `"half-open"`; `failureCount`: `number`; `isHealthy`: `boolean`; \}\> -Defined in: [neurolink.ts:14804](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L14804) +Defined in: [neurolink.ts:14857](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L14857) Get circuit breaker status for all tools @@ -1944,7 +1944,7 @@ Object with circuit breaker status for each tool > **resetToolCircuitBreaker**(`toolName`): `void` -Defined in: [neurolink.ts:14839](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L14839) +Defined in: [neurolink.ts:14892](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L14892) Reset circuit breaker for a specific tool @@ -1966,7 +1966,7 @@ Name of the tool to reset circuit breaker for > **clearToolExecutionMetrics**(): `void` -Defined in: [neurolink.ts:14856](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L14856) +Defined in: [neurolink.ts:14909](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L14909) Clear all tool execution metrics @@ -1980,7 +1980,7 @@ Clear all tool execution metrics > **getToolHealthReport**(): `Promise`\<\{ `totalTools`: `number`; `healthyTools`: `number`; `unhealthyTools`: `number`; `tools`: `Record`\<`string`, \{ `name`: `string`; `isHealthy`: `boolean`; `metrics`: \{ `totalExecutions`: `number`; `successRate`: `number`; `averageExecutionTime`: `number`; `lastExecutionTime`: `number`; `errorCategories`: `Record`\<`string`, `number`\>; \}; `circuitBreaker`: \{ `state`: `"closed"` \| `"open"` \| `"half-open"`; `failureCount`: `number`; \}; `issues`: `string`[]; `recommendations`: `string`[]; \}\>; \}\> -Defined in: [neurolink.ts:14865](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L14865) +Defined in: [neurolink.ts:14918](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L14918) Get comprehensive tool health report @@ -1996,7 +1996,7 @@ Detailed health report for all tools > **ensureConversationMemoryInitialized**(): `Promise`\<`boolean`\> -Defined in: [neurolink.ts:15020](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L15020) +Defined in: [neurolink.ts:15073](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L15073) 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 @@ -2013,7 +2013,7 @@ Promise resolving to true if initialization was successful, false otherwise > **getConversationStats**(): `Promise`\<[`ConversationMemoryStats`](../type-aliases/ConversationMemoryStats.md)\> -Defined in: [neurolink.ts:15040](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L15040) +Defined in: [neurolink.ts:15093](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L15093) Get conversation memory statistics (public API) @@ -2027,7 +2027,7 @@ Get conversation memory statistics (public API) > **getConversationHistory**(`sessionId`): `Promise`\<[`ChatMessage`](../type-aliases/ChatMessage.md)[]\> -Defined in: [neurolink.ts:15067](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L15067) +Defined in: [neurolink.ts:15120](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L15120) Get complete conversation history for a specific session (public API) @@ -2051,7 +2051,7 @@ Array of ChatMessage objects in chronological order, or empty array if session d > **clearConversationSession**(`sessionId`): `Promise`\<`boolean`\> -Defined in: [neurolink.ts:15123](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L15123) +Defined in: [neurolink.ts:15176](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L15176) Clear conversation history for a specific session (public API) @@ -2071,7 +2071,7 @@ Clear conversation history for a specific session (public API) > **clearAllConversations**(): `Promise`\<`void`\> -Defined in: [neurolink.ts:15149](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L15149) +Defined in: [neurolink.ts:15202](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L15202) Clear all conversation history (public API) @@ -2085,7 +2085,7 @@ Clear all conversation history (public API) > **listSessions**(`userId?`): `Promise`\<[`SessionListItem`](../type-aliases/SessionListItem.md)[]\> -Defined in: [neurolink.ts:15177](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L15177) +Defined in: [neurolink.ts:15230](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L15230) List all conversation sessions with metadata (public API) @@ -2109,7 +2109,7 @@ Array of session list items with metadata > **exportSession**(`sessionId`, `options?`): `Promise`\<[`SessionExport`](../type-aliases/SessionExport.md) \| `null`\> -Defined in: [neurolink.ts:15226](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L15226) +Defined in: [neurolink.ts:15279](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L15279) Export a single session with full history and metadata (public API) @@ -2145,7 +2145,7 @@ Session export object with full history > **exportAllSessions**(`userId?`, `options?`): `Promise`\<[`SessionExport`](../type-aliases/SessionExport.md)[]\> -Defined in: [neurolink.ts:15311](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L15311) +Defined in: [neurolink.ts:15364](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L15364) Export all sessions for a user (public API) @@ -2181,7 +2181,7 @@ Array of session exports > **storeToolExecutions**(`sessionId`, `userId`, `toolCalls`, `toolResults`, `currentTime?`): `Promise`\<`void`\> -Defined in: [neurolink.ts:15375](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L15375) +Defined in: [neurolink.ts:15428](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L15428) Store tool executions in conversation memory if enabled and Redis is configured @@ -2229,7 +2229,7 @@ Promise resolving when storage is complete > **isToolExecutionStorageAvailable**(): `boolean` -Defined in: [neurolink.ts:15445](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L15445) +Defined in: [neurolink.ts:15498](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L15498) Check if tool execution storage is available. @@ -2250,7 +2250,7 @@ whether the active memory backend can persist tool executions > **getSessionMessages**(`sessionId`, `userId?`): `Promise`\<[`ChatMessage`](../type-aliases/ChatMessage.md)[]\> -Defined in: [neurolink.ts:15455](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L15455) +Defined in: [neurolink.ts:15508](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L15508) Get the raw messages array for a session. Returns the full messages list without context filtering or summarization. @@ -2279,7 +2279,7 @@ Array of ChatMessage objects, or empty array if session doesn't exist > **setSessionMessages**(`sessionId`, `messages`, `userId?`): `Promise`\<`void`\> -Defined in: [neurolink.ts:15496](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L15496) +Defined in: [neurolink.ts:15549](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L15549) Replace the entire messages array for a session. @@ -2313,7 +2313,7 @@ Optional user ID for scoped Redis key lookup > **modifyLastAssistantMessage**(`sessionId`, `transformer`, `userId?`): `Promise`\<`boolean`\> -Defined in: [neurolink.ts:15544](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L15544) +Defined in: [neurolink.ts:15597](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L15597) Modify the last assistant message in a session using a transformer function. Convenience wrapper around getSessionMessages/setSessionMessages. @@ -2350,7 +2350,7 @@ true if a message was modified, false if no assistant message was found > **addExternalMCPServer**(`serverId`, `config`): `Promise`\<[`ExternalMCPOperationResult`](../type-aliases/ExternalMCPOperationResult.md)\<[`ExternalMCPServerInstance`](../type-aliases/ExternalMCPServerInstance.md)\>\> -Defined in: [neurolink.ts:15575](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L15575) +Defined in: [neurolink.ts:15628](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L15628) Add an external MCP server Automatically discovers and registers tools from the server @@ -2381,7 +2381,7 @@ Operation result with server instance > **removeExternalMCPServer**(`serverId`): `Promise`\<[`ExternalMCPOperationResult`](../type-aliases/ExternalMCPOperationResult.md)\<`void`\>\> -Defined in: [neurolink.ts:15662](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L15662) +Defined in: [neurolink.ts:15715](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L15715) Remove an external MCP server Stops the server and removes all its tools @@ -2406,7 +2406,7 @@ Operation result > **listExternalMCPServers**(): `object`[] -Defined in: [neurolink.ts:15714](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L15714) +Defined in: [neurolink.ts:15767](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L15767) List all external MCP servers @@ -2422,7 +2422,7 @@ Array of server health information > **getExternalMCPServer**(`serverId`): [`ExternalMCPServerInstance`](../type-aliases/ExternalMCPServerInstance.md) \| `undefined` -Defined in: [neurolink.ts:15743](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L15743) +Defined in: [neurolink.ts:15796](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L15796) Get external MCP server status @@ -2446,7 +2446,7 @@ Server instance or undefined if not found > **executeExternalMCPTool**(`serverId`, `toolName`, `parameters`, `options?`): `Promise`\<`unknown`\> -Defined in: [neurolink.ts:15757](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L15757) +Defined in: [neurolink.ts:15810](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L15810) Execute a tool from an external MCP server @@ -2490,7 +2490,7 @@ Tool execution result > **getExternalMCPTools**(): [`ExternalMCPToolInfo`](../type-aliases/ExternalMCPToolInfo.md)[] -Defined in: [neurolink.ts:15854](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L15854) +Defined in: [neurolink.ts:15922](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L15922) Get all tools from external MCP servers @@ -2506,7 +2506,7 @@ Array of external tool information > **getExternalMCPServerTools**(`serverId`): [`ExternalMCPToolInfo`](../type-aliases/ExternalMCPToolInfo.md)[] -Defined in: [neurolink.ts:15863](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L15863) +Defined in: [neurolink.ts:15931](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L15931) Get tools from a specific external MCP server @@ -2530,7 +2530,7 @@ Array of tool information for the server > **testExternalMCPConnection**(`config`): `Promise`\<[`BatchOperationResult`](../type-aliases/BatchOperationResult.md)\> -Defined in: [neurolink.ts:15872](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L15872) +Defined in: [neurolink.ts:15940](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L15940) Test connection to an external MCP server @@ -2554,7 +2554,7 @@ Test result with connection status > **getExternalMCPStatistics**(): `object` -Defined in: [neurolink.ts:15900](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L15900) +Defined in: [neurolink.ts:15968](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L15968) Get external MCP server manager statistics @@ -2594,7 +2594,7 @@ Statistics about external servers and tools > **shutdownExternalMCPServers**(): `Promise`\<`void`\> -Defined in: [neurolink.ts:15915](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L15915) +Defined in: [neurolink.ts:15983](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L15983) Shutdown all external MCP servers Called automatically on process exit @@ -2609,7 +2609,7 @@ Called automatically on process exit > **getElicitationManager**(): `Promise`\<`any`\> -Defined in: [neurolink.ts:15953](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L15953) +Defined in: [neurolink.ts:16021](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L16021) Get the global elicitation manager for interactive tool input Elicitation allows tools to request additional information from users during execution @@ -2640,7 +2640,7 @@ elicitationManager.registerHandler(async (request) => { > **registerElicitationHandler**(`handler`): `Promise`\<`void`\> -Defined in: [neurolink.ts:15981](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L15981) +Defined in: [neurolink.ts:16049](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L16049) Register an elicitation handler for interactive tool input Handlers are called when tools need user input during execution @@ -2678,7 +2678,7 @@ neurolink.registerElicitationHandler(async (request) => { > **getMultiServerManager**(): `Promise`\<`any`\> -Defined in: [neurolink.ts:16004](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L16004) +Defined in: [neurolink.ts:16072](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L16072) Get the multi-server manager for load balancing and coordination Allows managing multiple MCP servers with failover and load balancing @@ -2707,7 +2707,7 @@ await multiServer.createServerGroup("ai-tools", { > **getEnhancedToolDiscovery**(): `Promise`\<`any`\> -Defined in: [neurolink.ts:16029](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L16029) +Defined in: [neurolink.ts:16097](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L16097) Get the enhanced tool discovery service Provides advanced search, filtering, and compatibility checking for tools @@ -2737,7 +2737,7 @@ const results = await discovery.searchTools({ > **getMCPRegistryClient**(): `Promise`\<`any`\> -Defined in: [neurolink.ts:16056](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L16056) +Defined in: [neurolink.ts:16124](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L16124) Get the MCP registry client for discovering servers from registries Supports multiple registry sources (official, community, custom) @@ -2769,7 +2769,7 @@ const githubServer = registryClient.getWellKnownServer("github"); > **exposeAgentAsTool**(`agent`, `options?`): `Promise`\<[`ExposureResult`](../type-aliases/ExposureResult.md)\> -Defined in: [neurolink.ts:16084](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L16084) +Defined in: [neurolink.ts:16152](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L16152) Expose a NeuroLink agent as an MCP tool This allows agents to be called by other systems via MCP @@ -2846,7 +2846,7 @@ const tool = await neurolink.exposeAgentAsTool(agent, { > **exposeWorkflowAsTool**(`workflow`, `options?`): `Promise`\<[`ExposureResult`](../type-aliases/ExposureResult.md)\> -Defined in: [neurolink.ts:16125](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L16125) +Defined in: [neurolink.ts:16193](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L16193) Expose a workflow as an MCP tool This allows workflows to be called by other systems via MCP @@ -2927,7 +2927,7 @@ const tool = await neurolink.exposeWorkflowAsTool(workflow, { > **getToolIntegrationManager**(): `Promise`\<`any`\> -Defined in: [neurolink.ts:16164](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L16164) +Defined in: [neurolink.ts:16232](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L16232) Get the tool integration manager for middleware and elicitation Provides advanced tool wrapping with confirmation, timeout, retry, etc. @@ -2957,7 +2957,7 @@ integration.registerTool(myTool, { > **convertToolsToMCPFormat**(`tools`, `options?`): `Promise`\<`any`\> -Defined in: [neurolink.ts:16186](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L16186) +Defined in: [neurolink.ts:16254](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L16254) Convert NeuroLink tools to MCP format Useful for exposing local tools to external MCP clients @@ -2998,7 +2998,7 @@ const mcpTools = neurolink.convertToolsToMCPFormat([ > **convertToolsFromMCPFormat**(`tools`, `options?`): `Promise`\<`any`\> -Defined in: [neurolink.ts:16225](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L16225) +Defined in: [neurolink.ts:16293](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L16293) Convert MCP tools to NeuroLink format Useful for importing tools from external MCP servers @@ -3039,7 +3039,7 @@ const neurolinkTools = neurolink.convertToolsFromMCPFormat(externalTools, { > **getToolAnnotations**(`toolName`): `Promise`\<\{ `annotations`: [`MCPToolAnnotations`](../type-aliases/MCPToolAnnotations.md); `summary`: `string`; \} \| `null`\> -Defined in: [neurolink.ts:16248](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L16248) +Defined in: [neurolink.ts:16316](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L16316) Get tool annotations and safety information Provides insights about tool behavior, safety levels, and retry-ability @@ -3071,7 +3071,7 @@ const annotations = await neurolink.getToolAnnotations("deleteFile"); > **createEvaluationPipeline**(`configOrPreset`): `Promise`\<[`EvaluationPipeline`](EvaluationPipeline.md)\> -Defined in: [neurolink.ts:16487](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L16487) +Defined in: [neurolink.ts:16555](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L16555) Create an evaluation pipeline with the specified configuration or preset. Pipelines orchestrate multiple scorers to evaluate AI responses comprehensively. @@ -3122,7 +3122,7 @@ const pipeline = await neurolink.createEvaluationPipeline({ > **evaluate**(`input`, `options?`): `Promise`\<[`PipelineResult`](../type-aliases/PipelineResult.md)\> -Defined in: [neurolink.ts:16579](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L16579) +Defined in: [neurolink.ts:16647](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L16647) 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. @@ -3224,7 +3224,7 @@ const result = await neurolink.evaluate( > **score**(`scorerId`, `input`, `config?`): `Promise`\<[`ScoreResult`](../type-aliases/ScoreResult.md)\> -Defined in: [neurolink.ts:16717](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L16717) +Defined in: [neurolink.ts:16785](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L16785) Score a response using a single scorer. Useful for quick, targeted evaluations without the overhead of a full pipeline. @@ -3293,7 +3293,7 @@ const result = await neurolink.score( > **getAvailableScorers**(`options?`): `Promise`\<[`ScorerMetadata`](../type-aliases/ScorerMetadata.md)[]\> -Defined in: [neurolink.ts:16803](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L16803) +Defined in: [neurolink.ts:16871](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L16871) Get a list of all available scorers and their metadata. Useful for discovering what evaluation capabilities are available. @@ -3354,7 +3354,7 @@ const ruleBasedScorers = await neurolink.getAvailableScorers({ > **getEvaluationPresets**(): `Promise`\<`string`[]\> -Defined in: [neurolink.ts:16849](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L16849) +Defined in: [neurolink.ts:16917](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L16917) Get a list of available evaluation pipeline presets. Presets are pre-configured pipelines for common evaluation scenarios. @@ -3380,7 +3380,7 @@ console.log("Available presets:", presets); > **getEvaluationPreset**(`presetName`): `Promise`\<[`PipelineConfig`](../type-aliases/PipelineConfig.md)\> -Defined in: [neurolink.ts:16872](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L16872) +Defined in: [neurolink.ts:16940](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L16940) Get details of a specific evaluation preset. @@ -3416,7 +3416,7 @@ console.log("Pass threshold:", ragPreset.passThreshold); > **createAgent**(`definition`): `Promise`\<[`Agent`](Agent.md)\> -Defined in: [neurolink.ts:16922](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L16922) +Defined in: [neurolink.ts:16990](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L16990) Create an Agent instance for multi-agent orchestration. @@ -3468,7 +3468,7 @@ const result = await researcher.execute("Find recent AI breakthroughs"); > **createNetwork**(`config`): `Promise`\<[`AgentNetwork`](AgentNetwork.md)\> -Defined in: [neurolink.ts:16984](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L16984) +Defined in: [neurolink.ts:17052](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L17052) Create an AgentNetwork for multi-agent orchestration. @@ -3542,7 +3542,7 @@ const result = await network.execute({ > **createWorkerInstance**(`options?`): `NeuroLink` -Defined in: [neurolink.ts:17016](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L17016) +Defined in: [neurolink.ts:17084](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L17084) Create a worker-mode NeuroLink instance for sub-agent execution. @@ -3582,7 +3582,7 @@ A new worker-mode NeuroLink instance > **runIsolatedAgent**(`definition`, `input`, `options?`): `Promise`\<[`AgentRunOutcome`](../type-aliases/AgentRunOutcome.md)\> -Defined in: [neurolink.ts:17105](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L17105) +Defined in: [neurolink.ts:17173](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L17173) Run an isolated sub-agent: a worker instance (see [createWorkerInstance](#createworkerinstance)) executes a tool-using research pass under @@ -3632,7 +3632,7 @@ The run outcome > **continueAgent**(`handle`, `guidance?`): `Promise`\<[`AgentRunOutcome`](../type-aliases/AgentRunOutcome.md)\> -Defined in: [neurolink.ts:17124](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L17124) +Defined in: [neurolink.ts:17192](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L17192) Resume a leashed isolated-agent run by handle. `guidance`, when given, is appended as a user turn before the next leg — the supervisor's @@ -3665,7 +3665,7 @@ The next leg's outcome (or the final outcome) > **stopAgent**(`handle`): `Promise`\<[`AgentRunOutcome`](../type-aliases/AgentRunOutcome.md)\> -Defined in: [neurolink.ts:17140](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L17140) +Defined in: [neurolink.ts:17208](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L17208) Stop a leashed isolated-agent run: dispose its worker and return the final outcome (mechanical digest over everything gathered so far). @@ -3690,7 +3690,7 @@ The final outcome > **registerAgentTool**(`definition`, `options?`): `Promise`\<\{ `name`: `string`; \}\> -Defined in: [neurolink.ts:17158](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L17158) +Defined in: [neurolink.ts:17226](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L17226) Register an isolated agent as a delegation tool on THIS instance, so its existing generate() loop can delegate — no second router generate. @@ -3728,7 +3728,7 @@ The registered tool name > **executeNetwork**(`network`, `input`, `options?`): `Promise`\<[`NetworkExecutionResult`](../type-aliases/NetworkExecutionResult.md)\> -Defined in: [neurolink.ts:17180](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L17180) +Defined in: [neurolink.ts:17248](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L17248) Execute an agent network with the given input. @@ -3773,7 +3773,7 @@ Network execution result with content, trace, and usage > **streamNetwork**(`network`, `input`, `options?`): `AsyncIterable`\<[`NetworkStreamChunk`](../type-aliases/NetworkStreamChunk.md)\> -Defined in: [neurolink.ts:17204](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L17204) +Defined in: [neurolink.ts:17272](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L17272) Stream agent network execution with real-time events. @@ -3817,7 +3817,7 @@ Async iterable of network stream chunks > **createOrchestrator**(`config?`): `Promise`\<[`NetworkOrchestrator`](NetworkOrchestrator.md)\> -Defined in: [neurolink.ts:17228](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L17228) +Defined in: [neurolink.ts:17296](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L17296) Create a NetworkOrchestrator for managing multiple agent networks. @@ -3845,7 +3845,7 @@ A new NetworkOrchestrator instance > **createCoordinator**(`config?`): `Promise`\<[`AgentCoordinator`](AgentCoordinator.md)\> -Defined in: [neurolink.ts:17247](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L17247) +Defined in: [neurolink.ts:17315](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L17315) Create an AgentCoordinator for managing agent coordination strategies. @@ -3873,7 +3873,7 @@ A new AgentCoordinator instance > **createMessageBus**(`config?`): `Promise`\<[`MessageBus`](MessageBus.md)\> -Defined in: [neurolink.ts:17265](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L17265) +Defined in: [neurolink.ts:17333](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L17333) Create a MessageBus for inter-agent communication. @@ -3901,7 +3901,7 @@ A new MessageBus instance > **dispose**(): `Promise`\<`void`\> -Defined in: [neurolink.ts:17280](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L17280) +Defined in: [neurolink.ts:17348](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L17348) Dispose of all resources and cleanup connections Call this method when done using the NeuroLink instance to prevent resource leaks @@ -3917,7 +3917,7 @@ Especially important in test environments where multiple instances are created > **getToolRegistry**(): [`MCPToolRegistry`](MCPToolRegistry.md) -Defined in: [neurolink.ts:17467](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L17467) +Defined in: [neurolink.ts:17535](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L17535) Get the tool registry instance Used internally by server adapters for tool management @@ -3934,7 +3934,7 @@ The MCPToolRegistry instance > **compactSession**(`sessionId`, `config?`): `Promise`\<[`CompactionResult`](../type-aliases/CompactionResult.md) \| `null`\> -Defined in: [neurolink.ts:17475](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L17475) +Defined in: [neurolink.ts:17543](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L17543) Manually trigger context compaction for a session. Runs the full 4-stage compaction pipeline. @@ -3959,7 +3959,7 @@ Runs the full 4-stage compaction pipeline. > **getContextStats**(`sessionId`, `provider?`, `model?`): `Promise`\<\{ `estimatedInputTokens`: `number`; `availableInputTokens`: `number`; `usageRatio`: `number`; `shouldCompact`: `boolean`; `messageCount`: `number`; \} \| `null`\> -Defined in: [neurolink.ts:17526](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L17526) +Defined in: [neurolink.ts:17594](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L17594) Get context usage statistics for a session. Returns token counts, usage ratio, and breakdown by category. @@ -3988,7 +3988,7 @@ Returns token counts, usage ratio, and breakdown by category. > **needsCompaction**(`sessionId`, `provider?`, `model?`): `boolean` -Defined in: [neurolink.ts:17568](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L17568) +Defined in: [neurolink.ts:17636](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L17636) Check if a session needs compaction. @@ -4016,7 +4016,7 @@ Check if a session needs compaction. > **setAuthProvider**(`config`): `Promise`\<`void`\> -Defined in: [neurolink.ts:17605](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L17605) +Defined in: [neurolink.ts:17673](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L17673) Set the authentication provider for the NeuroLink instance @@ -4038,7 +4038,7 @@ Auth provider or configuration to create one > **getAuthProvider**(): [`AuthProvider`](../type-aliases/AuthProvider.md) \| `undefined` -Defined in: [neurolink.ts:17653](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L17653) +Defined in: [neurolink.ts:17721](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L17721) Get the currently configured authentication provider @@ -4052,7 +4052,7 @@ Get the currently configured authentication provider > **setAuthContext**(`context`): `Promise`\<`void`\> -Defined in: [neurolink.ts:17694](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L17694) +Defined in: [neurolink.ts:17762](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L17762) Set the current authentication context for request handling. @@ -4079,7 +4079,7 @@ The authenticated user context > **getAuthContext**(): `Promise`\<[`AuthenticatedContext`](../type-aliases/AuthenticatedContext.md) \| `undefined`\> -Defined in: [neurolink.ts:17709](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L17709) +Defined in: [neurolink.ts:17777](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L17777) Get the current authentication context. @@ -4095,7 +4095,7 @@ Checks AsyncLocalStorage first, then falls back to the global holder. > **clearAuthContext**(): `Promise`\<`void`\> -Defined in: [neurolink.ts:17717](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L17717) +Defined in: [neurolink.ts:17785](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L17785) Clear the current authentication context @@ -4109,7 +4109,7 @@ Clear the current authentication context > **getExternalServerManager**(): [`ExternalServerManager`](ExternalServerManager.md) -Defined in: [neurolink.ts:17731](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L17731) +Defined in: [neurolink.ts:17799](https://github.com/juspay/neurolink/blob/release/src/lib/neurolink.ts#L17799) Get the external server manager instance Used internally by server adapters for external MCP server management diff --git a/src/lib/neurolink.ts b/src/lib/neurolink.ts index 577102585..b723f8466 100644 --- a/src/lib/neurolink.ts +++ b/src/lib/neurolink.ts @@ -657,6 +657,23 @@ export class NeuroLink { /** Artifact store for externalized MCP tool outputs (set when strategy=externalize). */ private mcpArtifactStore?: ArtifactStore; private _disableToolCacheForCurrentRequest = false; + /** + * (toolName + args) keys already served during the CURRENT request. + * A repeat occurrence within one request bypasses the tool-result cache: + * when the model deliberately re-calls a tool with identical args in the + * same turn (a counter, a poll, "check status again"), it wants fresh + * state — serving the memoized first result silently freezes stateful + * tools (observed live: a 5-round counter loop executed once). Cross- + * request dedup — BZ-664's actual goal — is untouched: the first + * occurrence in a request may still be served from cache. Request-scoped + * like _disableToolCacheForCurrentRequest above (assigned a fresh Set at + * request start so the router's save/restore-by-reference pattern works). + */ + private _toolCacheKeysServedThisRequest = new Set(); + /** True only while a generate()/stream() turn is executing — the + * repeat-call cache bypass applies inside a turn; direct executeTool + * calls keep full BZ-664 cache semantics. */ + private _generationTurnActive = false; private mcpEnhancementsConfig?: MCPEnhancementsConfig; // Enhanced error handling support @@ -4728,6 +4745,8 @@ Current user's request: ${currentInput}`; throw error; } finally { this._disableToolCacheForCurrentRequest = false; + this._toolCacheKeysServedThisRequest = new Set(); + this._generationTurnActive = false; generateSpan.end(); } } @@ -4759,6 +4778,8 @@ Current user's request: ${currentInput}`; options.model = resolveModel(options.model, this.modelAliasConfig); this._disableToolCacheForCurrentRequest = !!options.disableToolCache; + this._toolCacheKeysServedThisRequest = new Set(); + this._generationTurnActive = true; generateSpan.setAttribute( "neurolink.provider", @@ -9060,6 +9081,8 @@ Current user's request: ${currentInput}`; const streamIsRoot = !trace.getSpan(context.active()); const spanStartTime = Date.now(); this._disableToolCacheForCurrentRequest = !!options.disableToolCache; + this._toolCacheKeysServedThisRequest = new Set(); + this._generationTurnActive = true; try { options.model = resolveModel(options.model, this.modelAliasConfig); @@ -9876,6 +9899,8 @@ Current user's request: ${currentInput}`; throw error; } finally { self._disableToolCacheForCurrentRequest = false; + self._toolCacheKeysServedThisRequest = new Set(); + self._generationTurnActive = false; params.streamSpan.setAttribute( "neurolink.response_time_ms", Date.now() - params.spanStartTime, @@ -10267,6 +10292,8 @@ Current user's request: ${currentInput}`; } self._disableToolCacheForCurrentRequest = false; + self._toolCacheKeysServedThisRequest = new Set(); + self._generationTurnActive = false; cleanupListeners(); streamSpan.setAttribute( @@ -13702,6 +13729,19 @@ Current user's request: ${currentInput}`; * - Annotations: skip cache for destructive tools, retry safe tools on failure * - Middleware: apply global middleware chain before execution */ + private toolCacheRepeatKey( + toolName: string, + params: unknown, + ): string | undefined { + try { + return `${toolName}:${JSON.stringify(params) ?? ""}`; + } catch { + // Unserializable args (circular refs) — no repeat tracking; the + // ToolResultCache's own keying handles (or rejects) them as before. + return undefined; + } + } + private async executeToolInternal( toolName: string, params: unknown, @@ -13739,12 +13779,25 @@ Current user's request: ${currentInput}`; __ctx: options.authContext ?? this.toolExecutionContext, } : params; - if (isCacheEnabled && toolResultCache) { + const repeatKey = this._generationTurnActive + ? this.toolCacheRepeatKey(toolName, cacheParams) + : undefined; + const isRepeatCallThisRequest = + repeatKey !== undefined && + this._toolCacheKeysServedThisRequest.has(repeatKey); + if (repeatKey !== undefined) { + this._toolCacheKeysServedThisRequest.add(repeatKey); + } + if (isCacheEnabled && toolResultCache && !isRepeatCallThisRequest) { const cached = toolResultCache.getCachedResult(toolName, cacheParams); if (cached !== undefined) { logger.debug(`[${functionTag}] Cache HIT for tool: ${toolName}`); return cached as T; } + } else if (isRepeatCallThisRequest) { + logger.debug( + `[${functionTag}] Repeat call within this request — bypassing tool cache for: ${toolName}`, + ); } // === MCP ENHANCEMENT: Middleware chain wrapper === @@ -15784,7 +15837,22 @@ Current user's request: ${currentInput}`; ? { __ctx: this.toolExecutionContext } : {}), }; - if (cacheEnabled && this.mcpToolResultCache) { + // Same repeat-within-request bypass as executeToolInternal: a model + // re-calling the identical tool+args in one turn wants fresh state. + const externalRepeatKey = this._generationTurnActive + ? this.toolCacheRepeatKey(toolName, cacheKeyArgs) + : undefined; + const isExternalRepeatThisRequest = + externalRepeatKey !== undefined && + this._toolCacheKeysServedThisRequest.has(externalRepeatKey); + if (externalRepeatKey !== undefined) { + this._toolCacheKeysServedThisRequest.add(externalRepeatKey); + } + if ( + cacheEnabled && + this.mcpToolResultCache && + !isExternalRepeatThisRequest + ) { const cached = this.mcpToolResultCache.getCachedResult( toolName, cacheKeyArgs, diff --git a/src/lib/utils/messageBuilder.ts b/src/lib/utils/messageBuilder.ts index 83e754480..a16c36423 100644 --- a/src/lib/utils/messageBuilder.ts +++ b/src/lib/utils/messageBuilder.ts @@ -2783,104 +2783,181 @@ async function convertMultimodalToProviderFormat( }), ); } else { - // Provider doesn't support native PDF - convert PDF pages to images - // This enables PDF processing for providers like Mistral, Ollama that support images but not PDFs - logger.info( - `[PDF→Image] Provider ${provider} doesn't support native PDF. Converting ${pdfFiles.length} PDF(s) to images...`, + // No native PDF support: inline the PDF's text layer, clearly labeled per + // file. Image-only conversion sent content a text-only backend can never + // read — observed live as the model flatly claiming no file was attached + // — and for proxy providers (litellm/openrouter) supportsVision() is a + // pass-through, so vision cannot be trusted to carry the content either. + // Text is therefore always included (primary for text-only backends, + // extra grounding otherwise); page images are appended below only when + // the provider may actually see them. A PDF with no text layer (pure + // scan) gets an explicit note rather than silence, so the model + // acknowledges an unreadable attachment instead of denying it exists. + const providerCanSeeImages = ProviderImageAdapter.supportsVision( + provider, + model, ); - for (const pdf of pdfFiles) { + const name = safeBasename(pdf.filename); try { - const effectiveMaxPages = pdf.maxPages ?? PDF_LIMITS.DEFAULT_MAX_PAGES; - const conversionResult = await PDFImageConverter.convertToImages( - pdf.buffer, - { - // #297: this is the only PDF→image call the product actually makes, - // and it used to hardcode scale 2.0 — silently overriding the - // lowered PDF_LIMITS.DEFAULT_SCALE and keeping the memory cost the - // issue reports (a 100-page render at 2.0 is ~776MB; 1.5 is ~44% - // fewer pixels per page). Callers can raise it back per request. - scale: pdf.scale ?? PDF_LIMITS.DEFAULT_SCALE, - // Page ceiling guards token overflow; also now caller-adjustable - // rather than a constant nothing could reach. - maxPages: effectiveMaxPages, - ...(pdf.password ? { password: pdf.password } : {}), // #258 - ...(pdf.maxCanvasPixels - ? { maxCanvasPixels: pdf.maxCanvasPixels } - : {}), // #260 - }, - ); - - // The renderer stops at maxPages, so a longer document is silently - // truncated — say so rather than letting the model answer from a - // partial document as though it had the whole thing. - // - // Keyed on the cap being reached, not on pdf.pageCount: that field is - // null whenever `input.content` omits `metadata.pages`, which is the - // common case, so a page-count comparison would simply never fire - // there. Reaching the cap is also unambiguous — a short count caused by - // per-page render failures (#294 isolates those into `errors`) would - // otherwise be misreported as a maxPages truncation. - if (conversionResult.pageCount >= effectiveMaxPages) { - logger.warn( - `[PDF→Image] ${safeBasename(pdf.filename)} hit the ${effectiveMaxPages}-page ` + - `conversion limit. Any pages beyond that were not sent — the model may be ` + - `answering from a partial document. Raise pdfOptions.maxPages or split the file.`, - ); + const { PDFParse } = await import("pdf-parse"); + const parser = new PDFParse({ + data: new Uint8Array(pdf.buffer), + ...(pdf.password ? { password: pdf.password } : {}), // #258 + }); + try { + const extracted = await parser.getText(); + const pdfText = (extracted?.text ?? "").trim(); + if (pdfText.length > 0) { + content.push({ + type: "text" as const, + text: `\n[Attached PDF: ${name}]\n${pdfText}\n[End of PDF: ${name}]`, + }); + logger.info( + `[PDF→Text] ✅ Extracted text for non-vision provider ${provider}: ${name} (${pdfText.length} chars)`, + ); + } else { + content.push({ + type: "text" as const, + text: `\n[Attached PDF: ${name} — no extractable text layer (likely a scanned document); its contents are unavailable to this text-only model.]`, + }); + logger.warn( + `[PDF→Text] ${name} has no text layer; provider ${provider} cannot see images — content unavailable`, + ); + } + } finally { + await parser.destroy?.(); } - if (conversionResult.errors && conversionResult.errors.length > 0) { - logger.warn( - `[PDF→Image] ${safeBasename(pdf.filename)}: ${conversionResult.errors.length} page(s) ` + - `failed to render and were omitted (page ${conversionResult.errors.map((e) => e.page).join(", ")}).`, - ); + } catch (error) { + const errorMessage = + error instanceof Error ? error.message : String(error); + logger.error(`[PDF→Text] ❌ Failed to parse ${name}: ${errorMessage}`); + // #258: password errors are actionable and must surface. pdf-parse + // raises pdf.js's PasswordException (not our typed PDF_PASSWORD_* + // codes), so detect by name/message shape. When the provider can see + // images, defer the throw to the image-conversion path below — it + // raises the canonical typed error with the "supply the password" + // guidance callers and tests rely on. + const isPasswordError = + (error as { name?: string })?.name === "PasswordException" || + /password/i.test(errorMessage); + if (isPasswordError) { + if (!providerCanSeeImages) { + throw error; + } + // Image branch will produce the canonical typed password error. + continue; } + content.push({ + type: "text" as const, + text: `\n[Attached PDF: ${name} — could not be parsed (${errorMessage}); its contents are unavailable.]`, + }); + } + } + // Page images in addition to the text, for providers that may actually + // see them (vision models, and proxies whose upstream might). + if (providerCanSeeImages) { + logger.info( + `[PDF→Image] Provider ${provider} doesn't support native PDF. Converting ${pdfFiles.length} PDF(s) to images...`, + ); - logger.info( - `[PDF→Image] ✅ Converted ${pdf.filename}: ${conversionResult.pageCount} page(s) → images`, - ); + for (const pdf of pdfFiles) { + try { + const effectiveMaxPages = + pdf.maxPages ?? PDF_LIMITS.DEFAULT_MAX_PAGES; + const conversionResult = await PDFImageConverter.convertToImages( + pdf.buffer, + { + // #297: this is the only PDF→image call the product actually makes, + // and it used to hardcode scale 2.0 — silently overriding the + // lowered PDF_LIMITS.DEFAULT_SCALE and keeping the memory cost the + // issue reports (a 100-page render at 2.0 is ~776MB; 1.5 is ~44% + // fewer pixels per page). Callers can raise it back per request. + scale: pdf.scale ?? PDF_LIMITS.DEFAULT_SCALE, + // Page ceiling guards token overflow; also now caller-adjustable + // rather than a constant nothing could reach. + maxPages: effectiveMaxPages, + ...(pdf.password ? { password: pdf.password } : {}), // #258 + ...(pdf.maxCanvasPixels + ? { maxCanvasPixels: pdf.maxCanvasPixels } + : {}), // #260 + }, + ); - // Add each page as an ImagePart (raw base64, not data: URI — see SSRF note above) - conversionResult.images.forEach((base64Image, pageIndex) => { - content.push({ - type: "image" as const, - image: base64Image, - mimeType: "image/png", - } as ImagePart); + // The renderer stops at maxPages, so a longer document is silently + // truncated — say so rather than letting the model answer from a + // partial document as though it had the whole thing. + // + // Keyed on the cap being reached, not on pdf.pageCount: that field is + // null whenever `input.content` omits `metadata.pages`, which is the + // common case, so a page-count comparison would simply never fire + // there. Reaching the cap is also unambiguous — a short count caused by + // per-page render failures (#294 isolates those into `errors`) would + // otherwise be misreported as a maxPages truncation. + if (conversionResult.pageCount >= effectiveMaxPages) { + logger.warn( + `[PDF→Image] ${safeBasename(pdf.filename)} hit the ${effectiveMaxPages}-page ` + + `conversion limit. Any pages beyond that were not sent — the model may be ` + + `answering from a partial document. Raise pdfOptions.maxPages or split the file.`, + ); + } + if (conversionResult.errors && conversionResult.errors.length > 0) { + logger.warn( + `[PDF→Image] ${safeBasename(pdf.filename)}: ${conversionResult.errors.length} page(s) ` + + `failed to render and were omitted (page ${conversionResult.errors.map((e) => e.page).join(", ")}).`, + ); + } - logger.debug( - `[PDF→Image] Added page ${pageIndex + 1}/${conversionResult.pageCount} of ${pdf.filename}`, + logger.info( + `[PDF→Image] ✅ Converted ${pdf.filename}: ${conversionResult.pageCount} page(s) → images`, ); - }); - // Log any warnings from conversion - if (conversionResult.warnings) { - conversionResult.warnings.forEach((warning) => { - logger.warn(`[PDF→Image] ${warning}`); + // Add each page as an ImagePart (raw base64, not data: URI — see SSRF note above) + conversionResult.images.forEach((base64Image, pageIndex) => { + content.push({ + type: "image" as const, + image: base64Image, + mimeType: "image/png", + } as ImagePart); + + logger.debug( + `[PDF→Image] Added page ${pageIndex + 1}/${conversionResult.pageCount} of ${pdf.filename}`, + ); }); - } - } catch (error) { - const errorMessage = - error instanceof Error ? error.message : String(error); - logger.error( - `[PDF→Image] ❌ Failed to convert ${pdf.filename}: ${errorMessage}`, - ); - // #258: password errors are already actionable typed errors — re-throw - // them unwrapped so the "supply a password" guidance isn't buried. - const code = (error as { code?: string })?.code; - if ( - code === "PDF_PASSWORD_REQUIRED" || - code === "PDF_INCORRECT_PASSWORD" - ) { - throw error; - } + // Log any warnings from conversion + if (conversionResult.warnings) { + conversionResult.warnings.forEach((warning) => { + logger.warn(`[PDF→Image] ${warning}`); + }); + } + } catch (error) { + const errorMessage = + error instanceof Error ? error.message : String(error); + logger.error( + `[PDF→Image] ❌ Failed to convert ${pdf.filename}: ${errorMessage}`, + ); - // Re-throw so the user knows PDF processing failed - throw new Error( - `PDF to image conversion failed for ${pdf.filename}: ${errorMessage}. ` + - `Provider ${provider} doesn't support native PDFs and image conversion failed.`, - { cause: error }, - ); + // #258: password errors are already actionable typed errors — re-throw + // them unwrapped so the "supply a password" guidance isn't buried. + const code = (error as { code?: string })?.code; + if ( + code === "PDF_PASSWORD_REQUIRED" || + code === "PDF_INCORRECT_PASSWORD" + ) { + throw error; + } + + // Re-throw so the user knows PDF processing failed. The inlined + // text layer above does NOT soften this: conversion failures + // include caller mistakes (e.g. an invalid maxCanvasPixels, #260) + // that must surface rather than be silently downgraded. + throw new Error( + `PDF to image conversion failed for ${pdf.filename}: ${errorMessage}. ` + + `Provider ${provider} doesn't support native PDFs and image conversion failed.`, + { cause: error }, + ); + } } } } diff --git a/src/lib/utils/transformationUtils.ts b/src/lib/utils/transformationUtils.ts index 7a44d78ed..fee8c72c7 100644 --- a/src/lib/utils/transformationUtils.ts +++ b/src/lib/utils/transformationUtils.ts @@ -253,6 +253,11 @@ export function transformToolExecutionsForMCP( executionTime: number; success: boolean; serverId?: string; + params?: unknown; + output?: unknown; + startedAt?: number; + isError?: boolean; + error?: string; }> { if (!toolExecutions || !Array.isArray(toolExecutions)) { return []; @@ -327,11 +332,38 @@ export function transformToolExecutionsForMCP( undefined; } + // Pass the execution payload through instead of discarding it. This + // transform used to keep only {toolName, executionTime, success, + // serverId}; toToolExecutionRecords() downstream then found no + // input/output on the entries and emitted params:{} with + // resultText:"undefined" for every tool execution on the MCP path — + // even when the source entry was a full record with real args and a + // real result. Field names chosen to match what + // toToolExecutionRecords() reads (input/params, output/result/ + // resultText, startedAt, isError). + const params = + teRecord.params ?? teRecord.input ?? teRecord.args ?? undefined; + const output = + teRecord.output ?? + teRecord.result ?? + teRecord.response ?? + (typeof teRecord.resultText === "string" + ? teRecord.resultText + : undefined); return { toolName: toolName, executionTime: executionTime, success: success, serverId: serverId, + ...(params !== undefined ? { params } : {}), + ...(output !== undefined ? { output } : {}), + ...(typeof teRecord.startedAt === "number" + ? { startedAt: teRecord.startedAt } + : {}), + ...(teRecord.isError !== undefined + ? { isError: teRecord.isError === true } + : { isError: !success }), + ...(typeof teRecord.error === "string" ? { error: teRecord.error } : {}), }; }); }