@juspay/neurolink 9.25.2 → 9.26.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.
Files changed (61) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/adapters/providerImageAdapter.d.ts +3 -27
  3. package/dist/adapters/providerImageAdapter.js +9 -199
  4. package/dist/agent/directTools.d.ts +35 -3
  5. package/dist/agent/directTools.js +122 -0
  6. package/dist/cli/commands/config.d.ts +6 -6
  7. package/dist/context/contextCompactor.d.ts +1 -2
  8. package/dist/context/contextCompactor.js +7 -1
  9. package/dist/context/prompts/summarizationPrompt.d.ts +3 -3
  10. package/dist/context/prompts/summarizationPrompt.js +16 -9
  11. package/dist/context/stages/structuredSummarizer.d.ts +2 -2
  12. package/dist/context/stages/structuredSummarizer.js +80 -30
  13. package/dist/lib/adapters/providerImageAdapter.d.ts +3 -27
  14. package/dist/lib/adapters/providerImageAdapter.js +9 -199
  15. package/dist/lib/agent/directTools.d.ts +33 -1
  16. package/dist/lib/agent/directTools.js +122 -0
  17. package/dist/lib/context/contextCompactor.d.ts +1 -2
  18. package/dist/lib/context/contextCompactor.js +7 -1
  19. package/dist/lib/context/prompts/summarizationPrompt.d.ts +3 -3
  20. package/dist/lib/context/prompts/summarizationPrompt.js +16 -9
  21. package/dist/lib/context/stages/structuredSummarizer.d.ts +2 -2
  22. package/dist/lib/context/stages/structuredSummarizer.js +80 -30
  23. package/dist/lib/mcp/servers/agent/directToolsServer.js +2 -0
  24. package/dist/lib/mcp/toolRegistry.d.ts +8 -0
  25. package/dist/lib/mcp/toolRegistry.js +20 -0
  26. package/dist/lib/neurolink.d.ts +10 -0
  27. package/dist/lib/neurolink.js +281 -17
  28. package/dist/lib/providers/googleAiStudio.js +13 -7
  29. package/dist/lib/types/configTypes.d.ts +3 -0
  30. package/dist/lib/types/contextTypes.d.ts +5 -2
  31. package/dist/lib/types/contextTypes.js +8 -8
  32. package/dist/lib/types/generateTypes.d.ts +25 -0
  33. package/dist/lib/types/modelTypes.d.ts +2 -2
  34. package/dist/lib/utils/messageBuilder.js +2 -0
  35. package/dist/lib/utils/modelAliasResolver.d.ts +17 -0
  36. package/dist/lib/utils/modelAliasResolver.js +55 -0
  37. package/dist/lib/utils/pdfProcessor.d.ts +1 -1
  38. package/dist/lib/utils/pdfProcessor.js +7 -7
  39. package/dist/lib/utils/toolUtils.d.ts +8 -0
  40. package/dist/lib/utils/toolUtils.js +15 -0
  41. package/dist/lib/workflow/config.d.ts +24 -24
  42. package/dist/mcp/servers/agent/directToolsServer.js +2 -0
  43. package/dist/mcp/toolRegistry.d.ts +8 -0
  44. package/dist/mcp/toolRegistry.js +20 -0
  45. package/dist/neurolink.d.ts +10 -0
  46. package/dist/neurolink.js +281 -17
  47. package/dist/providers/googleAiStudio.js +13 -7
  48. package/dist/server/utils/validation.d.ts +2 -2
  49. package/dist/types/configTypes.d.ts +3 -0
  50. package/dist/types/contextTypes.d.ts +5 -2
  51. package/dist/types/contextTypes.js +8 -8
  52. package/dist/types/generateTypes.d.ts +25 -0
  53. package/dist/utils/messageBuilder.js +2 -0
  54. package/dist/utils/modelAliasResolver.d.ts +17 -0
  55. package/dist/utils/modelAliasResolver.js +54 -0
  56. package/dist/utils/pdfProcessor.d.ts +1 -1
  57. package/dist/utils/pdfProcessor.js +7 -7
  58. package/dist/utils/toolUtils.d.ts +8 -0
  59. package/dist/utils/toolUtils.js +15 -0
  60. package/dist/workflow/config.d.ts +82 -82
  61. package/package.json +1 -1
@@ -6,9 +6,18 @@ import { tool } from "ai";
6
6
  import { z } from "zod";
7
7
  import * as fs from "fs";
8
8
  import * as path from "path";
9
+ import { execFile } from "child_process";
9
10
  import { logger } from "../utils/logger.js";
10
11
  import { VertexAI } from "@google-cloud/vertexai";
11
12
  import { CSVProcessor } from "../utils/csvProcessor.js";
13
+ import { shouldEnableBashTool } from "../utils/toolUtils.js";
14
+ const MAX_OUTPUT_BYTES = 102400; // 100KB
15
+ function truncateOutput(output) {
16
+ if (output.length > MAX_OUTPUT_BYTES) {
17
+ return (output.slice(0, MAX_OUTPUT_BYTES) + "\n... [output truncated at 100KB]");
18
+ }
19
+ return output;
20
+ }
12
21
  // Runtime Google Search tool creation - bypasses TypeScript strict typing
13
22
  function createGoogleSearchTools() {
14
23
  const searchTool = {};
@@ -534,6 +543,9 @@ export const directAgentTools = {
534
543
  }
535
544
  },
536
545
  }),
546
+ // NOTE: executeBashCommand was moved to a separate opt-in export (bashTool) for security.
547
+ // It is only included in directAgentTools when NEUROLINK_ENABLE_BASH_TOOL=true or
548
+ // toolConfig.enableBashTool is explicitly set to true. See shouldEnableBashTool() in toolUtils.ts.
537
549
  websearchGrounding: tool({
538
550
  description: "Search the web for current information using Google Search grounding. Returns raw search data for AI processing.",
539
551
  parameters: z.object({
@@ -657,6 +669,116 @@ export const directAgentTools = {
657
669
  },
658
670
  }),
659
671
  };
672
+ /**
673
+ * Bash command execution tool - exported separately for opt-in use.
674
+ *
675
+ * SECURITY: This tool is NOT included in directAgentTools by default.
676
+ * It must be explicitly enabled via:
677
+ * - Environment variable: NEUROLINK_ENABLE_BASH_TOOL=true
678
+ * - Config: toolConfig.enableBashTool = true
679
+ *
680
+ * Import this directly when you need bash execution capabilities:
681
+ * import { bashTool } from '../agent/directTools.js';
682
+ */
683
+ export const bashTool = tool({
684
+ description: "Execute a bash/shell command and return stdout, stderr, and exit code. Supports full shell syntax including pipes, redirects, and variable expansion. Requires HITL confirmation when enabled.",
685
+ parameters: z.object({
686
+ command: z
687
+ .string()
688
+ .describe("The shell command to execute (supports pipes, redirects, etc.)"),
689
+ timeout: z
690
+ .number()
691
+ .optional()
692
+ .default(30000)
693
+ .describe("Timeout in milliseconds (default: 30000, max: 120000)"),
694
+ cwd: z
695
+ .string()
696
+ .optional()
697
+ .describe("Working directory (defaults to process.cwd())"),
698
+ }),
699
+ execute: async ({ command, timeout = 30000, cwd }) => {
700
+ try {
701
+ const effectiveTimeout = Math.min(Math.max(timeout, 100), 120000);
702
+ const resolvedCwd = cwd ? path.resolve(cwd) : process.cwd();
703
+ const currentCwd = process.cwd();
704
+ // Verify cwd exists before resolving symlinks
705
+ if (!fs.existsSync(resolvedCwd) ||
706
+ !fs.statSync(resolvedCwd).isDirectory()) {
707
+ return {
708
+ success: false,
709
+ code: -1,
710
+ stdout: "",
711
+ stderr: "",
712
+ error: `Directory does not exist: ${resolvedCwd}`,
713
+ };
714
+ }
715
+ // Security: resolve symlinks and prevent execution outside current directory
716
+ try {
717
+ const realCwd = fs.realpathSync(currentCwd);
718
+ const realResolvedCwd = fs.realpathSync(resolvedCwd);
719
+ if (!realResolvedCwd.startsWith(realCwd)) {
720
+ return {
721
+ success: false,
722
+ code: -1,
723
+ stdout: "",
724
+ stderr: "",
725
+ error: "Access denied: Cannot execute commands outside current directory",
726
+ };
727
+ }
728
+ }
729
+ catch {
730
+ return {
731
+ success: false,
732
+ code: -1,
733
+ stdout: "",
734
+ stderr: "",
735
+ error: "Access denied: Cannot resolve directory path",
736
+ };
737
+ }
738
+ // Use /bin/bash -c to support full shell syntax (pipes, redirects, etc.)
739
+ return await new Promise((resolve) => {
740
+ execFile("/bin/bash", ["-c", command], {
741
+ timeout: effectiveTimeout,
742
+ cwd: resolvedCwd,
743
+ maxBuffer: MAX_OUTPUT_BYTES,
744
+ }, (error, stdout, stderr) => {
745
+ if (error) {
746
+ const exitCode = typeof error.code === "number" ? error.code : 1;
747
+ resolve({
748
+ success: false,
749
+ code: exitCode,
750
+ stdout: truncateOutput(stdout || ""),
751
+ stderr: truncateOutput(stderr || error.message),
752
+ error: error.killed ? "Command timed out" : error.message,
753
+ });
754
+ }
755
+ else {
756
+ resolve({
757
+ success: true,
758
+ code: 0,
759
+ stdout: truncateOutput(stdout),
760
+ stderr: truncateOutput(stderr),
761
+ });
762
+ }
763
+ });
764
+ });
765
+ }
766
+ catch (error) {
767
+ return {
768
+ success: false,
769
+ code: -1,
770
+ stdout: "",
771
+ stderr: "",
772
+ error: error instanceof Error ? error.message : String(error),
773
+ };
774
+ }
775
+ },
776
+ });
777
+ // Conditionally inject executeBashCommand into directAgentTools when opted in.
778
+ // This ensures the tool is only available to SDK consumers who explicitly enable it.
779
+ if (shouldEnableBashTool()) {
780
+ directAgentTools.executeBashCommand = bashTool;
781
+ }
660
782
  // eslint-disable-next-line no-redeclare
661
783
  export function getToolsForCategory(category = "all") {
662
784
  switch (category) {
@@ -10,8 +10,7 @@
10
10
  */
11
11
  import type { ChatMessage, ConversationMemoryConfig } from "../types/conversation.js";
12
12
  import type { CompactionResult, CompactionConfig } from "../types/contextTypes.js";
13
- export type { CompactionResult, CompactionConfig, } from "../types/contextTypes.js";
14
- export type CompactionStage = "prune" | "deduplicate" | "summarize" | "truncate";
13
+ export type { CompactionConfig, CompactionResult, CompactionStage, } from "../types/contextTypes.js";
15
14
  export declare class ContextCompactor {
16
15
  private config;
17
16
  constructor(config?: CompactionConfig);
@@ -15,8 +15,8 @@ import { SpanSerializer, SpanType, SpanStatus, } from "../observability/index.js
15
15
  import { getMetricsAggregator } from "../observability/index.js";
16
16
  import { pruneToolOutputs } from "./stages/toolOutputPruner.js";
17
17
  import { deduplicateFileReads } from "./stages/fileReadDeduplicator.js";
18
- import { summarizeMessages } from "./stages/structuredSummarizer.js";
19
18
  import { truncateWithSlidingWindow } from "./stages/slidingWindowTruncator.js";
19
+ import { summarizeMessages } from "./stages/structuredSummarizer.js";
20
20
  const DEFAULT_CONFIG = {
21
21
  enablePrune: true,
22
22
  enableDeduplicate: true,
@@ -106,6 +106,7 @@ export class ContextCompactor {
106
106
  model: this.config.summarizationModel,
107
107
  keepRecentRatio: this.config.keepRecentRatio,
108
108
  memoryConfig,
109
+ targetTokens,
109
110
  }), 120_000, "LLM summarization timed out after 120s");
110
111
  if (summarizeResult.summarized) {
111
112
  currentMessages = summarizeResult.messages;
@@ -146,6 +147,11 @@ export class ContextCompactor {
146
147
  const stageTokensBefore = estimateMessagesTokens(currentMessages, provider);
147
148
  const truncResult = truncateWithSlidingWindow(currentMessages, {
148
149
  fraction: this.config.truncationFraction,
150
+ currentTokens: stageTokensBefore,
151
+ targetTokens: targetTokens,
152
+ provider: provider,
153
+ adaptiveBuffer: 0.15,
154
+ maxIterations: 3,
149
155
  });
150
156
  if (truncResult.truncated) {
151
157
  currentMessages = truncResult.messages;
@@ -1,12 +1,12 @@
1
1
  /**
2
2
  * Summarization Prompt Builder
3
3
  *
4
- * Builds prompts for summarizing conversation context into a 9-section structure.
4
+ * Builds prompts for summarizing conversation context into a 10-section structure.
5
5
  * Supports both initial summarization and incremental merging with existing summaries.
6
6
  */
7
7
  import type { SummarizationPromptOptions } from "../../types/contextTypes.js";
8
8
  export type { SummarizationPromptOptions } from "../../types/contextTypes.js";
9
- declare const NINE_SECTIONS: string[];
9
+ declare const SUMMARY_SECTIONS: string[];
10
10
  /**
11
11
  * Builds a summarization prompt based on the provided options.
12
12
  *
@@ -14,4 +14,4 @@ declare const NINE_SECTIONS: string[];
14
14
  * @returns The constructed prompt string
15
15
  */
16
16
  export declare function buildSummarizationPrompt(options: SummarizationPromptOptions): string;
17
- export { NINE_SECTIONS };
17
+ export { SUMMARY_SECTIONS };
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * Summarization Prompt Builder
3
3
  *
4
- * Builds prompts for summarizing conversation context into a 9-section structure.
4
+ * Builds prompts for summarizing conversation context into a 10-section structure.
5
5
  * Supports both initial summarization and incremental merging with existing summaries.
6
6
  */
7
- const NINE_SECTIONS = [
7
+ const SUMMARY_SECTIONS = [
8
8
  "Primary Request and Intent",
9
9
  "Key Technical Concepts",
10
10
  "Files and Code Sections",
@@ -14,6 +14,7 @@ const NINE_SECTIONS = [
14
14
  "Current Work",
15
15
  "Next Step",
16
16
  "Required Files",
17
+ "Constraints and Established Rules",
17
18
  ];
18
19
  function buildFileContextSection(filesRead, filesModified) {
19
20
  const hasFiles = (filesRead && filesRead.length > 0) ||
@@ -38,7 +39,7 @@ function buildFileContextSection(filesRead, filesModified) {
38
39
  }
39
40
  function buildInitialPrompt(options) {
40
41
  const fileContext = buildFileContextSection(options.filesRead, options.filesModified);
41
- return `You are a context summarization assistant. Your task is to analyze the conversation and create a structured summary following a 9-section format.
42
+ return `You are a context summarization assistant. Your task is to analyze the conversation and create a structured summary following a 10-section format.
42
43
 
43
44
  Create a summary with the following sections:
44
45
 
@@ -67,7 +68,12 @@ What is being actively worked on right now?
67
68
  What is the immediate next action to take?
68
69
 
69
70
  ### 9. Required Files
70
- What files will need to be accessed or modified to continue?${fileContext}
71
+ What files will need to be accessed or modified to continue?
72
+
73
+ ### 10. Constraints and Established Rules
74
+ What user-imposed constraints, behavioral directives, coding standards, agreed-upon decisions, or established rules must persist across the conversation? Include any "always do X", "never do Y", naming conventions, architectural patterns, or preferences the user has stated.${fileContext}
75
+
76
+ IMPORTANT: Section 10 (Constraints and Established Rules) must ALWAYS be preserved in full. User constraints and established agreements are never "no longer relevant" — they remain in effect for the entire session unless the user explicitly revokes them.
71
77
 
72
78
  Analyze the conversation thoroughly and fill in each section with relevant information. If a section is not applicable, write "N/A" for that section.`;
73
79
  }
@@ -80,18 +86,19 @@ Existing Summary:
80
86
  ${options.previousSummary}
81
87
  ---
82
88
 
83
- Update sections with new information while preserving important context from the existing summary. Maintain the same 9-section structure.
89
+ Update sections with new information while preserving important context from the existing summary. Maintain the same 10-section structure.
84
90
 
85
91
  Instructions:
86
92
  1. Review the existing summary above
87
93
  2. Analyze the new conversation content
88
94
  3. MERGE the new information into the appropriate sections
89
95
  4. Update sections with relevant new information
90
- 5. Remove information that is no longer relevant
96
+ 5. Remove information that is no longer relevant EXCEPT for Section 10 (Constraints and Established Rules) — user constraints and established agreements must ALWAYS be preserved unless the user explicitly revoked them
91
97
  6. Keep the summary concise but comprehensive
92
- 7. Maintain the 9-section format${fileContext}
98
+ 7. Maintain the 10-section format
99
+ 8. Always carry forward ALL entries from Section 10 of the existing summary, adding any new constraints found in the new content${fileContext}
93
100
 
94
- Output the updated summary following the same 9-section structure.`;
101
+ Output the updated summary following the same 10-section structure.`;
95
102
  }
96
103
  /**
97
104
  * Builds a summarization prompt based on the provided options.
@@ -107,5 +114,5 @@ export function buildSummarizationPrompt(options) {
107
114
  }
108
115
  return buildInitialPrompt(options);
109
116
  }
110
- export { NINE_SECTIONS };
117
+ export { SUMMARY_SECTIONS };
111
118
  //# sourceMappingURL=summarizationPrompt.js.map
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * Stage 3: Structured LLM Summarization
3
3
  *
4
- * Uses the structured 9-section prompt to summarize older messages
4
+ * Uses the structured 10-section prompt to summarize older messages
5
5
  * while preserving recent ones.
6
6
  */
7
- import type { ChatMessage } from "../../types/conversation.js";
8
7
  import type { SummarizeConfig, SummarizeResult } from "../../types/contextTypes.js";
8
+ import type { ChatMessage } from "../../types/conversation.js";
9
9
  export type { SummarizeConfig, SummarizeResult, } from "../../types/contextTypes.js";
10
10
  export declare function summarizeMessages(messages: ChatMessage[], config?: SummarizeConfig): Promise<SummarizeResult>;
@@ -1,19 +1,59 @@
1
1
  /**
2
2
  * Stage 3: Structured LLM Summarization
3
3
  *
4
- * Uses the structured 9-section prompt to summarize older messages
4
+ * Uses the structured 10-section prompt to summarize older messages
5
5
  * while preserving recent ones.
6
6
  */
7
- import { generateSummary } from "../../utils/conversationMemory.js";
8
7
  import { randomUUID } from "crypto";
8
+ import { generateSummary } from "../../utils/conversationMemory.js";
9
+ import { estimateTokens } from "../../utils/tokenEstimation.js";
10
+ import { logger } from "../../utils/logger.js";
11
+ /**
12
+ * Find the split index using token counting — walk backward from the end,
13
+ * accumulating token counts until we've reserved `targetRecentTokens` worth
14
+ * of recent content. Everything before the split index gets summarized.
15
+ */
16
+ function findSplitIndexByTokens(messages, targetRecentTokens, provider) {
17
+ let recentTokens = 0;
18
+ let splitIndex = messages.length;
19
+ for (let i = messages.length - 1; i >= 0; i--) {
20
+ const content = typeof messages[i].content === "string"
21
+ ? messages[i].content
22
+ : JSON.stringify(messages[i].content);
23
+ const msgTokens = estimateTokens(content, provider);
24
+ if (recentTokens + msgTokens > targetRecentTokens) {
25
+ splitIndex = i + 1;
26
+ break;
27
+ }
28
+ recentTokens += msgTokens;
29
+ }
30
+ // Ensure at least one message is summarized
31
+ return Math.max(1, splitIndex);
32
+ }
9
33
  export async function summarizeMessages(messages, config) {
10
34
  const keepRecentRatio = config?.keepRecentRatio ?? 0.3;
11
35
  if (messages.length <= 4) {
12
36
  return { summarized: false, messages };
13
37
  }
14
- // Keep the most recent messages unsummarized
15
- const keepCount = Math.max(4, Math.ceil(messages.length * keepRecentRatio));
16
- const splitIndex = messages.length - keepCount;
38
+ // Determine split point: prefer token-based when a target budget is available,
39
+ // fall back to message-count-based split for backward compatibility.
40
+ let splitIndex;
41
+ if (config?.targetTokens && config.targetTokens > 0) {
42
+ // Keep `keepRecentRatio` fraction of the target budget as recent context
43
+ const targetRecentTokens = Math.floor(config.targetTokens * keepRecentRatio);
44
+ // NOTE: config.provider is the summarization provider, not the generation
45
+ // provider. Ideally we'd use the generation/budget provider for accurate
46
+ // token estimation, but SummarizeConfig doesn't carry a separate
47
+ // budgetProvider field. This is a known design limitation.
48
+ splitIndex = findSplitIndexByTokens(messages, targetRecentTokens, config.provider);
49
+ }
50
+ else {
51
+ // Legacy: message-count-based split
52
+ const keepCount = Math.max(4, Math.ceil(messages.length * keepRecentRatio));
53
+ splitIndex = messages.length - keepCount;
54
+ }
55
+ // Clamp so at least the last message is always preserved (never summarize everything)
56
+ splitIndex = Math.min(splitIndex, messages.length - 1);
17
57
  if (splitIndex <= 0) {
18
58
  return { summarized: false, messages };
19
59
  }
@@ -21,30 +61,40 @@ export async function summarizeMessages(messages, config) {
21
61
  const recentMessages = messages.slice(splitIndex);
22
62
  // Find previous summary if exists
23
63
  const previousSummary = messagesToSummarize.find((m) => m.metadata?.isSummary)?.content;
24
- // Use memory config for summarization if available
25
- if (config?.memoryConfig) {
26
- const summaryText = await generateSummary(messagesToSummarize, config.memoryConfig, "[ContextCompactor]", previousSummary);
27
- if (!summaryText) {
28
- return { summarized: false, messages };
29
- }
30
- const summaryMessage = {
31
- id: `summary-${randomUUID()}`,
32
- role: "user",
33
- content: `[Previous conversation summary]:\n\n${summaryText}`,
34
- timestamp: new Date().toISOString(),
35
- metadata: {
36
- isSummary: true,
37
- summarizesFrom: messagesToSummarize[0]?.id,
38
- summarizesTo: messagesToSummarize[messagesToSummarize.length - 1]?.id,
39
- },
40
- };
41
- return {
42
- summarized: true,
43
- messages: [summaryMessage, ...recentMessages],
44
- summaryText,
45
- };
46
- }
47
- // Without memory config, we can't call LLM
48
- return { summarized: false, messages };
64
+ // Build effective memory config: use provided memoryConfig, or construct from provider/model
65
+ const effectiveMemoryConfig = config?.memoryConfig ? { ...config.memoryConfig } : {};
66
+ // Fill in summarization provider/model from compactor config if not already set
67
+ if (!effectiveMemoryConfig.summarizationProvider && config?.provider) {
68
+ effectiveMemoryConfig.summarizationProvider = config.provider;
69
+ }
70
+ if (!effectiveMemoryConfig.summarizationModel && config?.model) {
71
+ effectiveMemoryConfig.summarizationModel = config.model;
72
+ }
73
+ // Only skip if there's genuinely no provider available
74
+ if (!effectiveMemoryConfig.summarizationProvider &&
75
+ !effectiveMemoryConfig.summarizationModel) {
76
+ logger.debug("[ContextCompactor] Stage 3 skipped: no summarization provider or model available");
77
+ return { summarized: false, messages };
78
+ }
79
+ const summaryText = await generateSummary(messagesToSummarize, effectiveMemoryConfig, "[ContextCompactor]", previousSummary);
80
+ if (!summaryText) {
81
+ return { summarized: false, messages };
82
+ }
83
+ const summaryMessage = {
84
+ id: `summary-${randomUUID()}`,
85
+ role: "user",
86
+ content: `[Previous conversation summary]:\n\n${summaryText}`,
87
+ timestamp: new Date().toISOString(),
88
+ metadata: {
89
+ isSummary: true,
90
+ summarizesFrom: messagesToSummarize[0]?.id,
91
+ summarizesTo: messagesToSummarize[messagesToSummarize.length - 1]?.id,
92
+ },
93
+ };
94
+ return {
95
+ summarized: true,
96
+ messages: [summaryMessage, ...recentMessages],
97
+ summaryText,
98
+ };
49
99
  }
50
100
  //# sourceMappingURL=structuredSummarizer.js.map
@@ -143,6 +143,8 @@ function getToolCategory(toolName) {
143
143
  return "filesystem";
144
144
  case "websearchGrounding":
145
145
  return "search";
146
+ case "executeBashCommand":
147
+ return "system";
146
148
  default:
147
149
  return "utility";
148
150
  }
@@ -103,6 +103,14 @@ export declare class MCPToolRegistry extends MCPRegistry {
103
103
  * Get tools by category
104
104
  */
105
105
  getToolsByCategory(category: string): ToolInfo[];
106
+ /**
107
+ * NL-001: Get available tools, filtering out those with OPEN circuit breakers.
108
+ * Returns both the filtered tools and the list of unavailable tool names.
109
+ */
110
+ getAvailableTools(circuitBreakers: Map<string, import("../utils/errorHandling.js").CircuitBreaker>): {
111
+ tools: ToolInfo[];
112
+ unavailableTools: string[];
113
+ };
106
114
  /**
107
115
  * Check if tool exists
108
116
  */
@@ -565,6 +565,26 @@ export class MCPToolRegistry extends MCPRegistry {
565
565
  }
566
566
  return Array.from(uniqueTools.values());
567
567
  }
568
+ /**
569
+ * NL-001: Get available tools, filtering out those with OPEN circuit breakers.
570
+ * Returns both the filtered tools and the list of unavailable tool names.
571
+ */
572
+ getAvailableTools(circuitBreakers) {
573
+ const allTools = Array.from(this.tools.values());
574
+ const unavailableTools = [];
575
+ const tools = [];
576
+ for (const tool of allTools) {
577
+ const breakerKey = `${tool.serverId || "unknown"}.${tool.name}`;
578
+ const breaker = circuitBreakers.get(breakerKey);
579
+ if (breaker && breaker.getState() === "open") {
580
+ unavailableTools.push(tool.name);
581
+ }
582
+ else {
583
+ tools.push(tool);
584
+ }
585
+ }
586
+ return { tools, unavailableTools };
587
+ }
568
588
  /**
569
589
  * Check if tool exists
570
590
  */
@@ -32,6 +32,10 @@ export declare class NeuroLink {
32
32
  private externalServerManager;
33
33
  private toolCache;
34
34
  private readonly toolCacheDuration;
35
+ private modelAliasConfig?;
36
+ private lastCompactionMessageCount;
37
+ /** Extract sessionId from options context for compaction watermark keying */
38
+ private getCompactionSessionId;
35
39
  private toolCircuitBreakers;
36
40
  private toolExecutionMetrics;
37
41
  private currentStreamToolExecutions;
@@ -1140,6 +1144,12 @@ export declare class NeuroLink {
1140
1144
  averageExecutionTime: number;
1141
1145
  lastExecutionTime: number;
1142
1146
  }>;
1147
+ /**
1148
+ * NL-004: Set model alias/deprecation configuration.
1149
+ * Models in the alias map will be warned, redirected, or blocked based on their action.
1150
+ * @param config - Model alias configuration with aliases map
1151
+ */
1152
+ setModelAliasConfig(config: import("./types/generateTypes.js").ModelAliasConfig): void;
1143
1153
  /**
1144
1154
  * Get circuit breaker status for all tools
1145
1155
  * @returns Object with circuit breaker status for each tool