@juspay/neurolink 9.74.0 → 9.76.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,10 @@
1
1
  import { NeuroLink } from "../neurolink.js";
2
- import type { ConversationMemoryConfig, LoopSessionState, SessionVariableValue } from "../types/index.js";
2
+ import type { ConversationMemoryConfig, LoopSessionState, SessionVariableValue, ToolRoutingConfig } from "../types/index.js";
3
3
  export declare class GlobalSessionManager {
4
4
  private static instance;
5
5
  private loopSession;
6
+ /** Optional tool-routing config set by CLI handlers before SDK construction. */
7
+ private _toolRoutingConfig;
6
8
  static getInstance(): GlobalSessionManager;
7
9
  setLoopSession(config?: ConversationMemoryConfig): string;
8
10
  /**
@@ -33,6 +35,13 @@ export declare class GlobalSessionManager {
33
35
  updateSessionId(newSessionId: string): void;
34
36
  getLoopSession(): LoopSessionState | null;
35
37
  clearLoopSession(): void;
38
+ /**
39
+ * Store a tool-routing config to be injected at SDK construction time.
40
+ * Call this BEFORE `getOrCreateNeuroLink()` inside a command handler.
41
+ * When a loop session is already active the config is ignored (the instance
42
+ * already exists).
43
+ */
44
+ setToolRoutingConfig(config: ToolRoutingConfig): void;
36
45
  getOrCreateNeuroLink(): NeuroLink;
37
46
  getCurrentSessionId(): string | undefined;
38
47
  setSessionVariable(key: string, value: SessionVariableValue): void;
@@ -31,6 +31,8 @@ function buildMcpOutputLimitsFromEnv() {
31
31
  export class GlobalSessionManager {
32
32
  static instance;
33
33
  loopSession = null;
34
+ /** Optional tool-routing config set by CLI handlers before SDK construction. */
35
+ _toolRoutingConfig = undefined;
34
36
  static getInstance() {
35
37
  if (!GlobalSessionManager.instance) {
36
38
  GlobalSessionManager.instance = new GlobalSessionManager();
@@ -127,6 +129,18 @@ export class GlobalSessionManager {
127
129
  this.loopSession = null;
128
130
  }
129
131
  }
132
+ /**
133
+ * Store a tool-routing config to be injected at SDK construction time.
134
+ * Call this BEFORE `getOrCreateNeuroLink()` inside a command handler.
135
+ * When a loop session is already active the config is ignored (the instance
136
+ * already exists).
137
+ */
138
+ setToolRoutingConfig(config) {
139
+ if (this.hasActiveSession()) {
140
+ return;
141
+ }
142
+ this._toolRoutingConfig = config;
143
+ }
130
144
  getOrCreateNeuroLink() {
131
145
  const session = this.getLoopSession();
132
146
  if (session) {
@@ -142,6 +156,10 @@ export class GlobalSessionManager {
142
156
  if (mcpOutputLimits) {
143
157
  options.mcp = { outputLimits: mcpOutputLimits };
144
158
  }
159
+ if (this._toolRoutingConfig) {
160
+ options.toolRouting = this._toolRoutingConfig;
161
+ this._toolRoutingConfig = undefined;
162
+ }
145
163
  return new NeuroLink(Object.keys(options).length ? options : undefined);
146
164
  }
147
165
  getCurrentSessionId() {
@@ -45,7 +45,7 @@ export type BaseCommandArgs = {
45
45
  /**
46
46
  * Generate command arguments
47
47
  */
48
- export type GenerateCommandArgs = BaseCommandArgs & {
48
+ export type GenerateCommandArgs = BaseCommandArgs & CliToolRoutingFlags & {
49
49
  /** Input text or prompt */
50
50
  input?: string;
51
51
  /** AI provider to use */
@@ -110,7 +110,7 @@ export type GenerateCommandArgs = BaseCommandArgs & {
110
110
  /**
111
111
  * Stream command arguments
112
112
  */
113
- export type StreamCommandArgs = BaseCommandArgs & {
113
+ export type StreamCommandArgs = BaseCommandArgs & CliToolRoutingFlags & {
114
114
  /** Input text or prompt */
115
115
  input?: string;
116
116
  /** AI provider to use */
@@ -137,7 +137,7 @@ export type StreamCommandArgs = BaseCommandArgs & {
137
137
  /**
138
138
  * Batch command arguments
139
139
  */
140
- export type BatchCommandArgs = BaseCommandArgs & {
140
+ export type BatchCommandArgs = BaseCommandArgs & CliToolRoutingFlags & {
141
141
  /** Input file path */
142
142
  file?: string;
143
143
  /** AI provider to use */
@@ -1500,3 +1500,29 @@ export type CliServeFlatRoute = {
1500
1500
  description?: string;
1501
1501
  group: string;
1502
1502
  };
1503
+ /**
1504
+ * Raw CLI flag shape for the tool-routing family of options.
1505
+ * Keys are camelCase as yargs delivers them after parsing kebab-case aliases.
1506
+ */
1507
+ export type CliToolRoutingFlags = {
1508
+ /** Master enable switch (--tool-routing). */
1509
+ toolRouting?: boolean;
1510
+ /** Router LLM hard timeout in ms (--tool-routing-timeout). */
1511
+ toolRoutingTimeout?: number;
1512
+ /** Router LLM provider override (--tool-routing-router-provider). */
1513
+ toolRoutingRouterProvider?: string;
1514
+ /** Router LLM model override (--tool-routing-router-model). */
1515
+ toolRoutingRouterModel?: string;
1516
+ /** Router LLM region override (--tool-routing-router-region). */
1517
+ toolRoutingRouterRegion?: string;
1518
+ /**
1519
+ * Server ids that are always kept and never offered to the router
1520
+ * (--tool-routing-always-include, repeatable).
1521
+ */
1522
+ toolRoutingAlwaysInclude?: string[];
1523
+ /**
1524
+ * Path to a JSON file OR inline JSON array of server descriptors
1525
+ * (--tool-routing-servers).
1526
+ */
1527
+ toolRoutingServers?: string;
1528
+ };
@@ -9,7 +9,6 @@ import type { ConversationMemoryConfig } from "./conversation.js";
9
9
  import type { ObservabilityConfig } from "./observability.js";
10
10
  import type { AuthProvider, AuthProviderType, AuthProviderConfig, Auth0Config, ClerkConfig, FirebaseConfig, SupabaseConfig, WorkOSConfig, BetterAuthConfig, JWTConfig, OAuth2Config, CognitoConfig, KeycloakConfig, AuthenticatedContext } from "./auth.js";
11
11
  import type { NeurolinkCredentials } from "./providers.js";
12
- import type { ToolRoutingConfig } from "./toolRouting.js";
13
12
  /**
14
13
  * Main NeuroLink configuration type
15
14
  */
@@ -74,6 +73,19 @@ export type NeurolinkConstructorConfig = {
74
73
  * any router failure. See {@link ToolRoutingConfig}.
75
74
  */
76
75
  toolRouting?: ToolRoutingConfig;
76
+ /**
77
+ * Opt-in tool-signature deduplication. When enabled, tools whose
78
+ * canonical signatures are sufficiently similar (Jaccard ≥ threshold) are
79
+ * collapsed to a single representative before being sent to the model,
80
+ * reducing token cost and model confusion caused by near-identical tools.
81
+ *
82
+ * Disabled by default — enabling this changes nothing unless you
83
+ * explicitly set `enabled: true`. Always fails open: any error in the
84
+ * dedup pass returns the original tool set unchanged.
85
+ *
86
+ * See {@link ToolDedupConfig}.
87
+ */
88
+ toolDedup?: ToolDedupConfig;
77
89
  };
78
90
  /**
79
91
  * Configuration for MCP enhancement modules wired into generate()/stream() paths.
@@ -338,7 +350,7 @@ export type ConfigUpdateOptions = {
338
350
  */
339
351
  export declare const DEFAULT_CONFIG: NeuroLinkConfig;
340
352
  import { TOOL_TIMEOUTS, BACKOFF_CONFIG, PERFORMANCE_PROFILES, PROVIDER_OPERATION_CONFIGS, MCP_OPERATION_CONFIGS } from "../constants/index.js";
341
- import type { ToolMiddleware, CacheStrategy, RoutingStrategy } from "./index.js";
353
+ import type { ToolMiddleware, CacheStrategy, RoutingStrategy, ToolDedupConfig, ToolRoutingConfig } from "./index.js";
342
354
  import type { ModelAliasConfig } from "./generate.js";
343
355
  /** Timeout category keys from TOOL_TIMEOUTS. */
344
356
  export type TimeoutCategory = keyof typeof TOOL_TIMEOUTS;
@@ -50,6 +50,7 @@ export * from "./stream.js";
50
50
  export * from "./subscription.js";
51
51
  export * from "./task.js";
52
52
  export * from "./taskClassification.js";
53
+ export * from "./toolDedup.js";
53
54
  export * from "./toolRouting.js";
54
55
  export * from "./tools.js";
55
56
  export * from "./voice.js";
@@ -51,6 +51,7 @@ export * from "./stream.js";
51
51
  export * from "./subscription.js";
52
52
  export * from "./task.js";
53
53
  export * from "./taskClassification.js";
54
+ export * from "./toolDedup.js";
54
55
  export * from "./toolRouting.js";
55
56
  export * from "./tools.js";
56
57
  export * from "./voice.js";
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Tool signature deduplication types.
3
+ *
4
+ * When many MCP servers are registered, it is common for tools from different
5
+ * servers to be functionally identical — same purpose, same parameters, only a
6
+ * slightly different name or description phrasing. Sending all of them to the
7
+ * model wastes tokens and can confuse the model into picking the wrong variant.
8
+ *
9
+ * The dedup pass is OPT-IN and FAIL-OPEN. When disabled (the default) the
10
+ * tool set is returned byte-for-byte unchanged. Any error in the dedup logic
11
+ * also returns the original tool set.
12
+ */
13
+ /** Configuration for the opt-in tool-signature deduplication pass. */
14
+ export type ToolDedupConfig = {
15
+ /**
16
+ * Master switch. Dedup runs only when `true`.
17
+ * Default: `false` (disabled — no change in behaviour).
18
+ */
19
+ enabled?: boolean;
20
+ /**
21
+ * Jaccard similarity threshold in [0, 1]. Pairs of tools whose token-set
22
+ * Jaccard similarity over their canonical signatures meets or exceeds this
23
+ * value are treated as near-duplicates; only one representative per cluster
24
+ * (the first in stable input order) is forwarded to the model.
25
+ *
26
+ * Default: `0.9`
27
+ */
28
+ threshold?: number;
29
+ };
30
+ /** Record produced for each tool collapsed by the dedup pass. */
31
+ export type ToolDedupRemoved = {
32
+ /** Name of the tool that was collapsed. */
33
+ name: string;
34
+ /** Name of the representative tool that this one was collapsed into. */
35
+ duplicateOf: string;
36
+ /** Similarity score that triggered the collapse (in [0, 1]). */
37
+ similarity: number;
38
+ };
39
+ /** Return type of `dedupeTools()`. */
40
+ export type ToolDedupResult<T extends Record<string, unknown>> = {
41
+ /** Deduplicated tool set (or original set when dedup is disabled/errored). */
42
+ tools: T;
43
+ /** Tools that were removed along with the reason. Empty when dedup is off. */
44
+ removed: ToolDedupRemoved[];
45
+ };
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Tool signature deduplication types.
3
+ *
4
+ * When many MCP servers are registered, it is common for tools from different
5
+ * servers to be functionally identical — same purpose, same parameters, only a
6
+ * slightly different name or description phrasing. Sending all of them to the
7
+ * model wastes tokens and can confuse the model into picking the wrong variant.
8
+ *
9
+ * The dedup pass is OPT-IN and FAIL-OPEN. When disabled (the default) the
10
+ * tool set is returned byte-for-byte unchanged. Any error in the dedup logic
11
+ * also returns the original tool set.
12
+ */
13
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@juspay/neurolink",
3
- "version": "9.74.0",
3
+ "version": "9.76.0",
4
4
  "packageManager": "pnpm@10.15.1",
5
5
  "description": "Universal AI Development Platform with working MCP integration, multi-provider support, voice (TTS/STT/realtime), and professional CLI. 58+ external MCP servers discoverable, multimodal file processing, RAG pipelines. Build, test, and deploy AI applications with 21+ providers: OpenAI, Anthropic, Google AI Studio, Google Vertex, AWS Bedrock, Azure OpenAI, Mistral, LiteLLM, SageMaker, Hugging Face, Ollama, OpenAI-compatible, OpenRouter, DeepSeek, NVIDIA NIM, LM Studio, llama.cpp, plus voice (OpenAI TTS, ElevenLabs, Deepgram, Azure Speech).",
6
6
  "author": {
@@ -118,11 +118,15 @@
118
118
  "test:autoresearch": "npx tsx test/continuous-test-suite-autoresearch.ts",
119
119
  "test:autoresearch:redis": "npx tsx test/continuous-test-suite-autoresearch-redis.ts",
120
120
  "test:envguard": "npx tsx test/helpers/envGuard.test.ts",
121
+ "test:tool-routing-cli:vitest": "pnpm exec vitest run test/toolRoutingCli.test.ts",
122
+ "test:tool-routing-cli": "pnpm run test:tool-routing-cli:vitest && npx tsx test/continuous-test-suite-tool-routing-cli.ts",
123
+ "test:tool-dedup:vitest": "pnpm exec vitest run test/toolDedup.test.ts",
124
+ "test:tool-dedup": "pnpm run test:tool-dedup:vitest && npx tsx test/continuous-test-suite-tool-dedup.ts",
121
125
  "test:ci": "pnpm run test && pnpm run test:client && pnpm run test:hitl",
122
126
  "// CI tier — fast, no live AI calls, safe for every commit": "",
123
127
  "test:unit:vitest": "pnpm exec vitest run test/toolRouting.test.ts",
124
128
  "test:tool-routing": "pnpm run test:unit:vitest && npx tsx test/continuous-test-suite-tool-routing.ts",
125
- "test:unit": "pnpm run test:envguard && pnpm run test:bugfixes && pnpm run test:mcp:infra && pnpm run test:mcp:bash && pnpm run test:mcp:limits && pnpm run test:mcp:spans && pnpm run test:autoresearch:redis && pnpm run test:unit:vitest",
129
+ "test:unit": "pnpm run test:envguard && pnpm run test:bugfixes && pnpm run test:mcp:infra && pnpm run test:mcp:bash && pnpm run test:mcp:limits && pnpm run test:mcp:spans && pnpm run test:autoresearch:redis && pnpm run test:unit:vitest && pnpm run test:tool-routing-cli:vitest && pnpm run test:tool-dedup:vitest",
126
130
  "// CI tier — live providers, runs only when API keys are present (test:credentials and test:dynamic make real provider calls when keys are set, so they live here, not in test:unit)": "",
127
131
  "test:live": "pnpm run test:providers && pnpm run test:mcp:http && pnpm run test:mcp:sdk && pnpm run test:mcp:cli && pnpm run test:observability && pnpm run test:context && pnpm run test:memory && pnpm run test:tool-reliability && pnpm run test:evaluation && pnpm run test:autoresearch && pnpm run test:credentials && pnpm run test:dynamic",
128
132
  "// CI tier — product output (image/video/TTS/PPT) — costs $$ per run": "",