@juspay/neurolink 7.36.0 → 7.37.1
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.
- package/CHANGELOG.md +12 -0
- package/dist/cli/commands/config.d.ts +18 -18
- package/dist/cli/factories/commandFactory.d.ts +24 -0
- package/dist/cli/factories/commandFactory.js +297 -245
- package/dist/config/taskClassificationConfig.d.ts +51 -0
- package/dist/config/taskClassificationConfig.js +148 -0
- package/dist/core/baseProvider.d.ts +40 -3
- package/dist/core/baseProvider.js +689 -352
- package/dist/core/constants.d.ts +2 -30
- package/dist/core/constants.js +15 -43
- package/dist/factories/providerFactory.js +23 -6
- package/dist/index.d.ts +3 -2
- package/dist/index.js +4 -3
- package/dist/lib/config/taskClassificationConfig.d.ts +51 -0
- package/dist/lib/config/taskClassificationConfig.js +148 -0
- package/dist/lib/core/baseProvider.d.ts +40 -3
- package/dist/lib/core/baseProvider.js +689 -352
- package/dist/lib/core/constants.d.ts +2 -30
- package/dist/lib/core/constants.js +15 -43
- package/dist/lib/factories/providerFactory.js +23 -6
- package/dist/lib/index.d.ts +3 -2
- package/dist/lib/index.js +4 -3
- package/dist/lib/mcp/externalServerManager.js +2 -2
- package/dist/lib/mcp/registry.js +2 -2
- package/dist/lib/mcp/servers/agent/directToolsServer.js +19 -10
- package/dist/lib/mcp/toolRegistry.js +4 -8
- package/dist/lib/neurolink.d.ts +82 -27
- package/dist/lib/neurolink.js +672 -713
- package/dist/lib/providers/amazonBedrock.js +2 -2
- package/dist/lib/providers/googleVertex.d.ts +3 -23
- package/dist/lib/providers/googleVertex.js +14 -342
- package/dist/lib/providers/openAI.d.ts +23 -0
- package/dist/lib/providers/openAI.js +313 -6
- package/dist/lib/providers/sagemaker/language-model.d.ts +2 -2
- package/dist/lib/sdk/toolRegistration.js +18 -1
- package/dist/lib/types/common.d.ts +98 -0
- package/dist/lib/types/index.d.ts +2 -0
- package/dist/lib/types/index.js +2 -0
- package/dist/lib/types/streamTypes.d.ts +13 -6
- package/dist/lib/types/taskClassificationTypes.d.ts +52 -0
- package/dist/lib/types/taskClassificationTypes.js +5 -0
- package/dist/lib/types/typeAliases.d.ts +3 -2
- package/dist/lib/utils/modelRouter.d.ts +107 -0
- package/dist/lib/utils/modelRouter.js +292 -0
- package/dist/lib/utils/parameterValidation.js +6 -25
- package/dist/lib/utils/promptRedaction.d.ts +29 -0
- package/dist/lib/utils/promptRedaction.js +62 -0
- package/dist/lib/utils/schemaConversion.d.ts +14 -0
- package/dist/lib/utils/schemaConversion.js +140 -0
- package/dist/lib/utils/taskClassificationUtils.d.ts +55 -0
- package/dist/lib/utils/taskClassificationUtils.js +149 -0
- package/dist/lib/utils/taskClassifier.d.ts +23 -0
- package/dist/lib/utils/taskClassifier.js +94 -0
- package/dist/lib/utils/transformationUtils.js +143 -5
- package/dist/mcp/externalServerManager.js +2 -2
- package/dist/mcp/registry.js +2 -2
- package/dist/mcp/servers/agent/directToolsServer.js +19 -10
- package/dist/mcp/toolRegistry.js +4 -8
- package/dist/neurolink.d.ts +82 -27
- package/dist/neurolink.js +672 -713
- package/dist/providers/amazonBedrock.js +2 -2
- package/dist/providers/googleVertex.d.ts +3 -23
- package/dist/providers/googleVertex.js +14 -342
- package/dist/providers/openAI.d.ts +23 -0
- package/dist/providers/openAI.js +313 -6
- package/dist/providers/sagemaker/language-model.d.ts +2 -2
- package/dist/sdk/toolRegistration.js +18 -1
- package/dist/types/common.d.ts +98 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.js +2 -0
- package/dist/types/streamTypes.d.ts +13 -6
- package/dist/types/taskClassificationTypes.d.ts +52 -0
- package/dist/types/taskClassificationTypes.js +5 -0
- package/dist/types/typeAliases.d.ts +3 -2
- package/dist/utils/modelRouter.d.ts +107 -0
- package/dist/utils/modelRouter.js +292 -0
- package/dist/utils/parameterValidation.js +6 -25
- package/dist/utils/promptRedaction.d.ts +29 -0
- package/dist/utils/promptRedaction.js +62 -0
- package/dist/utils/schemaConversion.d.ts +14 -0
- package/dist/utils/schemaConversion.js +140 -0
- package/dist/utils/taskClassificationUtils.d.ts +55 -0
- package/dist/utils/taskClassificationUtils.js +149 -0
- package/dist/utils/taskClassifier.d.ts +23 -0
- package/dist/utils/taskClassifier.js +94 -0
- package/dist/utils/transformationUtils.js +143 -5
- package/package.json +3 -2
@@ -0,0 +1,140 @@
|
|
1
|
+
import { zodToJsonSchema } from "zod-to-json-schema";
|
2
|
+
import { jsonSchemaToZod } from "json-schema-to-zod";
|
3
|
+
import { z } from "zod";
|
4
|
+
import { logger } from "./logger.js";
|
5
|
+
/**
|
6
|
+
* Convert Zod schema to JSON Schema format for Claude AI
|
7
|
+
*/
|
8
|
+
export function convertZodToJsonSchema(zodSchema) {
|
9
|
+
try {
|
10
|
+
// Use a type assertion that bypasses the infinite recursion check
|
11
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
12
|
+
const jsonSchema = zodToJsonSchema(zodSchema, {
|
13
|
+
name: "ToolParameters",
|
14
|
+
target: "jsonSchema7",
|
15
|
+
errorMessages: true,
|
16
|
+
});
|
17
|
+
// CRITICAL FIX: Ensure schema always has a proper type field for Google Vertex AI
|
18
|
+
if (!jsonSchema.type) {
|
19
|
+
// Default to "object" type if not specified, as most tool schemas are objects
|
20
|
+
jsonSchema.type = "object";
|
21
|
+
// If no properties, ensure it's at least an empty object schema
|
22
|
+
if (!jsonSchema.properties) {
|
23
|
+
jsonSchema.properties = {};
|
24
|
+
}
|
25
|
+
logger.info(`[SCHEMA-TYPE-FIX] Added missing type field to JSON Schema`, {
|
26
|
+
originalType: undefined,
|
27
|
+
fixedType: jsonSchema.type,
|
28
|
+
hasProperties: !!jsonSchema.properties,
|
29
|
+
addedEmptyProperties: !jsonSchema.properties,
|
30
|
+
});
|
31
|
+
}
|
32
|
+
logger.debug("Converted Zod schema to JSON Schema", {
|
33
|
+
hasProperties: !!jsonSchema.properties,
|
34
|
+
propertiesCount: Object.keys(jsonSchema.properties || {}).length,
|
35
|
+
schemaType: jsonSchema.type,
|
36
|
+
hasTypeField: !!jsonSchema.type,
|
37
|
+
});
|
38
|
+
return jsonSchema;
|
39
|
+
}
|
40
|
+
catch (error) {
|
41
|
+
logger.warn("Failed to convert Zod schema to JSON Schema", {
|
42
|
+
error: error instanceof Error ? error.message : String(error),
|
43
|
+
});
|
44
|
+
// Return a valid empty object schema instead of empty object
|
45
|
+
return {
|
46
|
+
type: "object",
|
47
|
+
properties: {},
|
48
|
+
};
|
49
|
+
}
|
50
|
+
}
|
51
|
+
/**
|
52
|
+
* Check if a value is a Zod schema
|
53
|
+
*/
|
54
|
+
export function isZodSchema(value) {
|
55
|
+
return !!(value &&
|
56
|
+
typeof value === "object" &&
|
57
|
+
"_def" in value &&
|
58
|
+
typeof value.parse === "function");
|
59
|
+
}
|
60
|
+
/**
|
61
|
+
* Convert JSON Schema to Zod schema format using official json-schema-to-zod library
|
62
|
+
* This ensures complete preservation of all schema structure and validation rules
|
63
|
+
*/
|
64
|
+
export function convertJsonSchemaToZod(jsonSchema) {
|
65
|
+
const startTime = Date.now();
|
66
|
+
try {
|
67
|
+
// Handle empty or invalid schemas
|
68
|
+
if (!jsonSchema || typeof jsonSchema !== "object") {
|
69
|
+
logger.debug("🔍 [SCHEMA-CONVERSION] Invalid or empty JSON schema, using fallback");
|
70
|
+
return z.object({}).passthrough();
|
71
|
+
}
|
72
|
+
// Log detailed input schema for debugging
|
73
|
+
logger.debug("🔍 [SCHEMA-CONVERSION] ===== STARTING OFFICIAL LIBRARY CONVERSION =====");
|
74
|
+
logger.debug("🔍 [SCHEMA-CONVERSION] Input JSON Schema:", {
|
75
|
+
type: jsonSchema.type,
|
76
|
+
hasProperties: !!jsonSchema.properties,
|
77
|
+
propertiesCount: jsonSchema.properties
|
78
|
+
? Object.keys(jsonSchema.properties).length
|
79
|
+
: 0,
|
80
|
+
requiredCount: Array.isArray(jsonSchema.required)
|
81
|
+
? jsonSchema.required.length
|
82
|
+
: 0,
|
83
|
+
required: jsonSchema.required,
|
84
|
+
sampleProperties: jsonSchema.properties
|
85
|
+
? Object.keys(jsonSchema.properties).slice(0, 5)
|
86
|
+
: [],
|
87
|
+
});
|
88
|
+
// Use official library to convert JSON Schema to Zod code
|
89
|
+
const zodCodeResult = jsonSchemaToZod(jsonSchema, {
|
90
|
+
module: "esm",
|
91
|
+
name: "schema",
|
92
|
+
});
|
93
|
+
logger.debug("🔍 [SCHEMA-CONVERSION] Generated Zod code:", {
|
94
|
+
codeLength: zodCodeResult.length,
|
95
|
+
codePreview: zodCodeResult.substring(0, 200) + "...",
|
96
|
+
});
|
97
|
+
// Extract the actual Zod schema expression from the generated code
|
98
|
+
// Generated code looks like: "import { z } from "zod"\n\nexport const schema = z.object({...})\n"
|
99
|
+
const schemaMatch = zodCodeResult.match(/export const schema = (z\..+?)(?:\n|$)/s);
|
100
|
+
if (!schemaMatch) {
|
101
|
+
throw new Error("Could not extract Zod schema from generated code");
|
102
|
+
}
|
103
|
+
const schemaExpression = schemaMatch[1].trim();
|
104
|
+
logger.debug("🔍 [SCHEMA-CONVERSION] Extracted schema expression:", {
|
105
|
+
expression: schemaExpression.substring(0, 300) + "...",
|
106
|
+
});
|
107
|
+
// Use Function constructor instead of eval for better scope control
|
108
|
+
const createZodSchema = new Function("z", `return ${schemaExpression}`);
|
109
|
+
const zodSchema = createZodSchema(z);
|
110
|
+
const conversionTime = Date.now() - startTime;
|
111
|
+
logger.debug("🔍 [SCHEMA-CONVERSION] ===== CONVERSION SUCCESSFUL =====", {
|
112
|
+
inputType: jsonSchema.type,
|
113
|
+
propertiesCount: jsonSchema.properties
|
114
|
+
? Object.keys(jsonSchema.properties).length
|
115
|
+
: 0,
|
116
|
+
requiredCount: Array.isArray(jsonSchema.required)
|
117
|
+
? jsonSchema.required.length
|
118
|
+
: 0,
|
119
|
+
conversionSuccess: true,
|
120
|
+
conversionTimeMs: conversionTime,
|
121
|
+
libraryUsed: "json-schema-to-zod-official",
|
122
|
+
zodSchemaType: zodSchema?.constructor?.name || "unknown",
|
123
|
+
});
|
124
|
+
return zodSchema;
|
125
|
+
}
|
126
|
+
catch (error) {
|
127
|
+
const conversionTime = Date.now() - startTime;
|
128
|
+
logger.warn("🚨 [SCHEMA-CONVERSION] Official library conversion failed, using passthrough fallback", {
|
129
|
+
error: error instanceof Error ? error.message : String(error),
|
130
|
+
errorType: error instanceof Error ? error.constructor.name : typeof error,
|
131
|
+
inputSchemaType: jsonSchema?.type,
|
132
|
+
inputSchemaKeys: jsonSchema && typeof jsonSchema === "object"
|
133
|
+
? Object.keys(jsonSchema)
|
134
|
+
: [],
|
135
|
+
conversionTimeMs: conversionTime,
|
136
|
+
libraryUsed: "json-schema-to-zod-official-FAILED",
|
137
|
+
});
|
138
|
+
return z.object({}).passthrough();
|
139
|
+
}
|
140
|
+
}
|
@@ -0,0 +1,55 @@
|
|
1
|
+
/**
|
2
|
+
* Task Classification Utility Functions
|
3
|
+
* Helper functions for analyzing prompts and calculating scores
|
4
|
+
*/
|
5
|
+
import type { ClassificationScores } from "../types/taskClassificationTypes.js";
|
6
|
+
/**
|
7
|
+
* Analyze prompt length and apply scoring bonuses
|
8
|
+
*/
|
9
|
+
export declare function analyzeLengthFactors(prompt: string, reasons: string[]): {
|
10
|
+
fastScore: number;
|
11
|
+
reasoningScore: number;
|
12
|
+
};
|
13
|
+
/**
|
14
|
+
* Check prompt against fast task patterns
|
15
|
+
*/
|
16
|
+
export declare function checkFastPatterns(normalizedPrompt: string, reasons: string[]): number;
|
17
|
+
/**
|
18
|
+
* Check prompt against reasoning task patterns
|
19
|
+
*/
|
20
|
+
export declare function checkReasoningPatterns(normalizedPrompt: string, reasons: string[]): number;
|
21
|
+
/**
|
22
|
+
* Analyze keyword matches in the prompt
|
23
|
+
*/
|
24
|
+
export declare function analyzeKeywords(normalizedPrompt: string, reasons: string[]): {
|
25
|
+
fastScore: number;
|
26
|
+
reasoningScore: number;
|
27
|
+
};
|
28
|
+
/**
|
29
|
+
* Analyze question complexity
|
30
|
+
*/
|
31
|
+
export declare function analyzeQuestionComplexity(prompt: string, reasons: string[]): number;
|
32
|
+
/**
|
33
|
+
* Analyze prompt structure and punctuation
|
34
|
+
*/
|
35
|
+
export declare function analyzePromptStructure(prompt: string, reasons: string[]): number;
|
36
|
+
/**
|
37
|
+
* Analyze domain-specific indicators
|
38
|
+
*/
|
39
|
+
export declare function analyzeDomainIndicators(normalizedPrompt: string, prompt: string, reasons: string[]): {
|
40
|
+
fastScore: number;
|
41
|
+
reasoningScore: number;
|
42
|
+
};
|
43
|
+
/**
|
44
|
+
* Calculate final confidence score
|
45
|
+
*/
|
46
|
+
export declare function calculateConfidence(fastScore: number, reasoningScore: number): number;
|
47
|
+
/**
|
48
|
+
* Determine task type based on scores
|
49
|
+
*/
|
50
|
+
export declare function determineTaskType(fastScore: number, reasoningScore: number): "fast" | "reasoning";
|
51
|
+
/**
|
52
|
+
* Comprehensive prompt analysis
|
53
|
+
* Runs all analysis functions and returns combined scores
|
54
|
+
*/
|
55
|
+
export declare function analyzePrompt(prompt: string): ClassificationScores;
|
@@ -0,0 +1,149 @@
|
|
1
|
+
/**
|
2
|
+
* Task Classification Utility Functions
|
3
|
+
* Helper functions for analyzing prompts and calculating scores
|
4
|
+
*/
|
5
|
+
import { FAST_PATTERNS, REASONING_PATTERNS, FAST_KEYWORDS, REASONING_KEYWORDS, SCORING_WEIGHTS, CLASSIFICATION_THRESHOLDS, DOMAIN_PATTERNS, } from "../config/taskClassificationConfig.js";
|
6
|
+
/**
|
7
|
+
* Analyze prompt length and apply scoring bonuses
|
8
|
+
*/
|
9
|
+
export function analyzeLengthFactors(prompt, reasons) {
|
10
|
+
let fastScore = 0;
|
11
|
+
let reasoningScore = 0;
|
12
|
+
if (prompt.length < CLASSIFICATION_THRESHOLDS.SHORT_PROMPT_LENGTH) {
|
13
|
+
fastScore += SCORING_WEIGHTS.SHORT_PROMPT_BONUS;
|
14
|
+
reasons.push("short prompt");
|
15
|
+
}
|
16
|
+
else if (prompt.length > CLASSIFICATION_THRESHOLDS.LONG_PROMPT_LENGTH) {
|
17
|
+
reasoningScore += SCORING_WEIGHTS.LONG_PROMPT_BONUS;
|
18
|
+
reasons.push("detailed prompt");
|
19
|
+
}
|
20
|
+
return { fastScore, reasoningScore };
|
21
|
+
}
|
22
|
+
/**
|
23
|
+
* Check prompt against fast task patterns
|
24
|
+
*/
|
25
|
+
export function checkFastPatterns(normalizedPrompt, reasons) {
|
26
|
+
for (const pattern of FAST_PATTERNS) {
|
27
|
+
if (pattern.test(normalizedPrompt)) {
|
28
|
+
reasons.push("fast pattern match");
|
29
|
+
return SCORING_WEIGHTS.PATTERN_MATCH_SCORE;
|
30
|
+
}
|
31
|
+
}
|
32
|
+
return 0;
|
33
|
+
}
|
34
|
+
/**
|
35
|
+
* Check prompt against reasoning task patterns
|
36
|
+
*/
|
37
|
+
export function checkReasoningPatterns(normalizedPrompt, reasons) {
|
38
|
+
for (const pattern of REASONING_PATTERNS) {
|
39
|
+
if (pattern.test(normalizedPrompt)) {
|
40
|
+
reasons.push("reasoning pattern match");
|
41
|
+
return SCORING_WEIGHTS.PATTERN_MATCH_SCORE;
|
42
|
+
}
|
43
|
+
}
|
44
|
+
return 0;
|
45
|
+
}
|
46
|
+
/**
|
47
|
+
* Analyze keyword matches in the prompt
|
48
|
+
*/
|
49
|
+
export function analyzeKeywords(normalizedPrompt, reasons) {
|
50
|
+
const fastKeywordMatches = FAST_KEYWORDS.filter((keyword) => normalizedPrompt.includes(keyword)).length;
|
51
|
+
const reasoningKeywordMatches = REASONING_KEYWORDS.filter((keyword) => normalizedPrompt.includes(keyword)).length;
|
52
|
+
const fastScore = fastKeywordMatches * SCORING_WEIGHTS.KEYWORD_MATCH_SCORE;
|
53
|
+
const reasoningScore = reasoningKeywordMatches * SCORING_WEIGHTS.KEYWORD_MATCH_SCORE;
|
54
|
+
if (fastKeywordMatches > 0) {
|
55
|
+
reasons.push(`${fastKeywordMatches} fast keywords`);
|
56
|
+
}
|
57
|
+
if (reasoningKeywordMatches > 0) {
|
58
|
+
reasons.push(`${reasoningKeywordMatches} reasoning keywords`);
|
59
|
+
}
|
60
|
+
return { fastScore, reasoningScore };
|
61
|
+
}
|
62
|
+
/**
|
63
|
+
* Analyze question complexity
|
64
|
+
*/
|
65
|
+
export function analyzeQuestionComplexity(prompt, reasons) {
|
66
|
+
const questionMarks = (prompt.match(/\?/g) || []).length;
|
67
|
+
if (questionMarks > 1) {
|
68
|
+
reasons.push("multiple questions");
|
69
|
+
return SCORING_WEIGHTS.MULTIPLE_QUESTIONS_BONUS;
|
70
|
+
}
|
71
|
+
return 0;
|
72
|
+
}
|
73
|
+
/**
|
74
|
+
* Analyze prompt structure and punctuation
|
75
|
+
*/
|
76
|
+
export function analyzePromptStructure(prompt, reasons) {
|
77
|
+
const sentences = prompt.split(/[.!?]+/).filter((s) => s.trim().length > 0);
|
78
|
+
if (sentences.length > 3) {
|
79
|
+
reasons.push("multi-sentence structure");
|
80
|
+
return SCORING_WEIGHTS.MULTI_SENTENCE_BONUS;
|
81
|
+
}
|
82
|
+
return 0;
|
83
|
+
}
|
84
|
+
/**
|
85
|
+
* Analyze domain-specific indicators
|
86
|
+
*/
|
87
|
+
export function analyzeDomainIndicators(normalizedPrompt, prompt, reasons) {
|
88
|
+
let fastScore = 0;
|
89
|
+
let reasoningScore = 0;
|
90
|
+
// Check for technical domain
|
91
|
+
if (DOMAIN_PATTERNS.TECHNICAL.test(normalizedPrompt)) {
|
92
|
+
reasoningScore += SCORING_WEIGHTS.TECHNICAL_DOMAIN_BONUS;
|
93
|
+
reasons.push("technical domain");
|
94
|
+
}
|
95
|
+
// Check for simple definition requests
|
96
|
+
if (DOMAIN_PATTERNS.SIMPLE_DEFINITION.test(normalizedPrompt) &&
|
97
|
+
prompt.length < CLASSIFICATION_THRESHOLDS.SIMPLE_DEFINITION_LENGTH) {
|
98
|
+
fastScore += SCORING_WEIGHTS.SIMPLE_DEFINITION_BONUS;
|
99
|
+
reasons.push("simple definition request");
|
100
|
+
}
|
101
|
+
return { fastScore, reasoningScore };
|
102
|
+
}
|
103
|
+
/**
|
104
|
+
* Calculate final confidence score
|
105
|
+
*/
|
106
|
+
export function calculateConfidence(fastScore, reasoningScore) {
|
107
|
+
const totalScore = fastScore + reasoningScore;
|
108
|
+
if (totalScore === 0) {
|
109
|
+
return CLASSIFICATION_THRESHOLDS.DEFAULT_CONFIDENCE;
|
110
|
+
}
|
111
|
+
const rawConfidence = Math.max(fastScore, reasoningScore) / totalScore;
|
112
|
+
return Math.max(CLASSIFICATION_THRESHOLDS.MIN_CONFIDENCE, Math.min(CLASSIFICATION_THRESHOLDS.MAX_CONFIDENCE, rawConfidence));
|
113
|
+
}
|
114
|
+
/**
|
115
|
+
* Determine task type based on scores
|
116
|
+
*/
|
117
|
+
export function determineTaskType(fastScore, reasoningScore) {
|
118
|
+
return fastScore >= reasoningScore ? "fast" : "reasoning";
|
119
|
+
}
|
120
|
+
/**
|
121
|
+
* Comprehensive prompt analysis
|
122
|
+
* Runs all analysis functions and returns combined scores
|
123
|
+
*/
|
124
|
+
export function analyzePrompt(prompt) {
|
125
|
+
const normalizedPrompt = prompt.toLowerCase().trim();
|
126
|
+
const reasons = [];
|
127
|
+
let fastScore = 0;
|
128
|
+
let reasoningScore = 0;
|
129
|
+
// 1. Length analysis
|
130
|
+
const lengthScores = analyzeLengthFactors(prompt, reasons);
|
131
|
+
fastScore += lengthScores.fastScore;
|
132
|
+
reasoningScore += lengthScores.reasoningScore;
|
133
|
+
// 2. Pattern matching
|
134
|
+
fastScore += checkFastPatterns(normalizedPrompt, reasons);
|
135
|
+
reasoningScore += checkReasoningPatterns(normalizedPrompt, reasons);
|
136
|
+
// 3. Keyword analysis
|
137
|
+
const keywordScores = analyzeKeywords(normalizedPrompt, reasons);
|
138
|
+
fastScore += keywordScores.fastScore;
|
139
|
+
reasoningScore += keywordScores.reasoningScore;
|
140
|
+
// 4. Question complexity
|
141
|
+
reasoningScore += analyzeQuestionComplexity(prompt, reasons);
|
142
|
+
// 5. Structure analysis
|
143
|
+
reasoningScore += analyzePromptStructure(prompt, reasons);
|
144
|
+
// 6. Domain analysis
|
145
|
+
const domainScores = analyzeDomainIndicators(normalizedPrompt, prompt, reasons);
|
146
|
+
fastScore += domainScores.fastScore;
|
147
|
+
reasoningScore += domainScores.reasoningScore;
|
148
|
+
return { fastScore, reasoningScore, reasons };
|
149
|
+
}
|
@@ -0,0 +1,23 @@
|
|
1
|
+
/**
|
2
|
+
* Binary Task Classifier for NeuroLink Orchestration
|
3
|
+
* Classifies tasks as either 'fast' (quick responses) or 'reasoning' (complex analysis)
|
4
|
+
*/
|
5
|
+
import type { TaskType, TaskClassification, ClassificationStats, ClassificationValidation } from "../types/taskClassificationTypes.js";
|
6
|
+
/**
|
7
|
+
* Binary Task Classifier
|
8
|
+
* Determines if a task requires fast response or deeper reasoning
|
9
|
+
*/
|
10
|
+
export declare class BinaryTaskClassifier {
|
11
|
+
/**
|
12
|
+
* Classify a prompt as either fast or reasoning task
|
13
|
+
*/
|
14
|
+
static classify(prompt: string): TaskClassification;
|
15
|
+
/**
|
16
|
+
* Get classification statistics for multiple prompts
|
17
|
+
*/
|
18
|
+
static getClassificationStats(prompts: string[]): ClassificationStats;
|
19
|
+
/**
|
20
|
+
* Validate classification accuracy (for testing/tuning)
|
21
|
+
*/
|
22
|
+
static validateClassification(prompt: string, expectedType: TaskType): ClassificationValidation;
|
23
|
+
}
|
@@ -0,0 +1,94 @@
|
|
1
|
+
/**
|
2
|
+
* Binary Task Classifier for NeuroLink Orchestration
|
3
|
+
* Classifies tasks as either 'fast' (quick responses) or 'reasoning' (complex analysis)
|
4
|
+
*/
|
5
|
+
import { logger } from "./logger.js";
|
6
|
+
import { CLASSIFICATION_THRESHOLDS } from "../config/taskClassificationConfig.js";
|
7
|
+
import { analyzePrompt, calculateConfidence, determineTaskType, } from "./taskClassificationUtils.js";
|
8
|
+
import { redactForClassification } from "./promptRedaction.js";
|
9
|
+
/**
|
10
|
+
* Binary Task Classifier
|
11
|
+
* Determines if a task requires fast response or deeper reasoning
|
12
|
+
*/
|
13
|
+
export class BinaryTaskClassifier {
|
14
|
+
/**
|
15
|
+
* Classify a prompt as either fast or reasoning task
|
16
|
+
*/
|
17
|
+
static classify(prompt) {
|
18
|
+
const startTime = Date.now();
|
19
|
+
// Analyze the prompt using utility functions
|
20
|
+
const scores = analyzePrompt(prompt);
|
21
|
+
const { fastScore, reasoningScore, reasons } = scores;
|
22
|
+
// Determine final classification
|
23
|
+
const totalScore = fastScore + reasoningScore;
|
24
|
+
let type;
|
25
|
+
let confidence;
|
26
|
+
if (totalScore === 0) {
|
27
|
+
// Default to fast for ambiguous cases
|
28
|
+
type = "fast";
|
29
|
+
confidence = CLASSIFICATION_THRESHOLDS.DEFAULT_CONFIDENCE;
|
30
|
+
reasons.push("default fallback");
|
31
|
+
}
|
32
|
+
else {
|
33
|
+
type = determineTaskType(fastScore, reasoningScore);
|
34
|
+
confidence = calculateConfidence(fastScore, reasoningScore);
|
35
|
+
}
|
36
|
+
const classification = {
|
37
|
+
type,
|
38
|
+
confidence,
|
39
|
+
reasoning: reasons.join(", "),
|
40
|
+
};
|
41
|
+
const classificationTime = Date.now() - startTime;
|
42
|
+
logger.debug("Task classified", {
|
43
|
+
prompt: redactForClassification(prompt),
|
44
|
+
classification: type,
|
45
|
+
confidence: confidence.toFixed(2),
|
46
|
+
fastScore,
|
47
|
+
reasoningScore,
|
48
|
+
reasons: reasons.join(", "),
|
49
|
+
classificationTime: `${classificationTime}ms`,
|
50
|
+
});
|
51
|
+
return classification;
|
52
|
+
}
|
53
|
+
/**
|
54
|
+
* Get classification statistics for multiple prompts
|
55
|
+
*/
|
56
|
+
static getClassificationStats(prompts) {
|
57
|
+
// Guard against empty array to prevent divide-by-zero
|
58
|
+
if (prompts.length === 0) {
|
59
|
+
const stats = {
|
60
|
+
total: 0,
|
61
|
+
fast: 0,
|
62
|
+
reasoning: 0,
|
63
|
+
averageConfidence: 0,
|
64
|
+
};
|
65
|
+
logger.debug("Classification stats", stats);
|
66
|
+
return stats;
|
67
|
+
}
|
68
|
+
const classifications = prompts.map((prompt) => this.classify(prompt));
|
69
|
+
const stats = {
|
70
|
+
total: classifications.length,
|
71
|
+
fast: classifications.filter((c) => c.type === "fast").length,
|
72
|
+
reasoning: classifications.filter((c) => c.type === "reasoning").length,
|
73
|
+
averageConfidence: classifications.reduce((sum, c) => sum + c.confidence, 0) /
|
74
|
+
classifications.length,
|
75
|
+
};
|
76
|
+
logger.debug("Classification stats", stats);
|
77
|
+
return stats;
|
78
|
+
}
|
79
|
+
/**
|
80
|
+
* Validate classification accuracy (for testing/tuning)
|
81
|
+
*/
|
82
|
+
static validateClassification(prompt, expectedType) {
|
83
|
+
const classification = this.classify(prompt);
|
84
|
+
const correct = classification.type === expectedType;
|
85
|
+
logger.debug("Classification validation", {
|
86
|
+
prompt: redactForClassification(prompt),
|
87
|
+
expected: expectedType,
|
88
|
+
actual: classification.type,
|
89
|
+
correct,
|
90
|
+
confidence: classification.confidence,
|
91
|
+
});
|
92
|
+
return { correct, classification };
|
93
|
+
}
|
94
|
+
}
|
@@ -2,6 +2,7 @@
|
|
2
2
|
* Object Transformation Utilities
|
3
3
|
* Centralizes repeated object transformation patterns to improve code reuse and maintainability
|
4
4
|
*/
|
5
|
+
import { logger } from "./logger.js";
|
5
6
|
// ============================================================================
|
6
7
|
// TOOL EXECUTION TRANSFORMATIONS
|
7
8
|
// ============================================================================
|
@@ -43,22 +44,109 @@ export function transformToolExecutions(toolExecutions) {
|
|
43
44
|
if (!toolName) {
|
44
45
|
toolName = `tool_execution_${index}`;
|
45
46
|
}
|
47
|
+
// Enhanced tool parameter extraction with structured logging
|
48
|
+
const parameterExtractionData = {
|
49
|
+
executionIndex: index,
|
50
|
+
toolNameExtracted: toolName,
|
51
|
+
primarySources: {
|
52
|
+
hasInput: !!teRecord.input,
|
53
|
+
hasParameters: !!teRecord.parameters,
|
54
|
+
hasArgs: !!teRecord.args,
|
55
|
+
inputType: typeof teRecord.input,
|
56
|
+
parametersType: typeof teRecord.parameters,
|
57
|
+
argsType: typeof teRecord.args,
|
58
|
+
},
|
59
|
+
rawRecordKeys: Object.keys(teRecord),
|
60
|
+
};
|
61
|
+
logger.debug("[TransformationUtils] Tool parameter extraction analysis", parameterExtractionData);
|
46
62
|
// Enhanced input extraction
|
47
63
|
let input = teRecord.input ||
|
48
64
|
teRecord.parameters ||
|
49
65
|
teRecord.args ||
|
50
66
|
{};
|
67
|
+
const primaryExtractionResult = {
|
68
|
+
keysCount: Object.keys(input).length,
|
69
|
+
keys: Object.keys(input),
|
70
|
+
extractionSuccessful: Object.keys(input).length > 0,
|
71
|
+
extractionSource: teRecord.input
|
72
|
+
? "input"
|
73
|
+
: teRecord.parameters
|
74
|
+
? "parameters"
|
75
|
+
: teRecord.args
|
76
|
+
? "args"
|
77
|
+
: "empty",
|
78
|
+
};
|
79
|
+
logger.debug("[TransformationUtils] Primary parameter extraction result", primaryExtractionResult);
|
51
80
|
// Extract input from nested toolCall if available
|
52
81
|
if (Object.keys(input).length === 0 &&
|
53
82
|
teRecord.toolCall &&
|
54
83
|
typeof teRecord.toolCall === "object") {
|
55
84
|
const toolCall = teRecord.toolCall;
|
85
|
+
const nestedExtractionData = {
|
86
|
+
reason: "Primary extraction failed, checking nested toolCall",
|
87
|
+
nestedSources: {
|
88
|
+
hasInput: !!toolCall.input,
|
89
|
+
hasParameters: !!toolCall.parameters,
|
90
|
+
hasArgs: !!toolCall.args,
|
91
|
+
},
|
92
|
+
toolCallKeys: Object.keys(toolCall),
|
93
|
+
};
|
94
|
+
logger.debug("[TransformationUtils] Nested parameter extraction attempt", nestedExtractionData);
|
56
95
|
input =
|
57
96
|
toolCall.input ||
|
58
97
|
toolCall.parameters ||
|
59
98
|
toolCall.args ||
|
60
99
|
{};
|
100
|
+
const nestedExtractionResult = {
|
101
|
+
keysCount: Object.keys(input).length,
|
102
|
+
keys: Object.keys(input),
|
103
|
+
extractionSuccessful: Object.keys(input).length > 0,
|
104
|
+
extractionSource: toolCall.input
|
105
|
+
? "toolCall.input"
|
106
|
+
: toolCall.parameters
|
107
|
+
? "toolCall.parameters"
|
108
|
+
: toolCall.args
|
109
|
+
? "toolCall.args"
|
110
|
+
: "empty",
|
111
|
+
};
|
112
|
+
logger.debug("[TransformationUtils] Nested parameter extraction result", nestedExtractionResult);
|
113
|
+
}
|
114
|
+
// Target tool parameter analysis for critical tools
|
115
|
+
if (toolName &&
|
116
|
+
(toolName.includes("SuccessRateSRByTime") ||
|
117
|
+
toolName.includes("juspay-analytics"))) {
|
118
|
+
const targetToolAnalysis = {
|
119
|
+
toolName,
|
120
|
+
inputKeys: Object.keys(input),
|
121
|
+
keysCount: Object.keys(input).length,
|
122
|
+
hasStartTime: "startTime" in input,
|
123
|
+
hasEndTime: "endTime" in input,
|
124
|
+
startTimeValue: input.startTime || "MISSING",
|
125
|
+
endTimeValue: input.endTime || "MISSING",
|
126
|
+
extractionStatus: Object.keys(input).length === 0 ? "FAILED" : "SUCCESS",
|
127
|
+
};
|
128
|
+
logger.debug("[TransformationUtils] Target tool parameter analysis", targetToolAnalysis);
|
129
|
+
if (Object.keys(input).length === 0) {
|
130
|
+
logger.error("[TransformationUtils] Critical: Target tool parameter extraction failed", {
|
131
|
+
toolName,
|
132
|
+
reason: "Both primary and nested extraction returned empty parameters",
|
133
|
+
impact: "AI response did not contain expected parameter structure",
|
134
|
+
});
|
135
|
+
}
|
61
136
|
}
|
137
|
+
// Final parameter extraction summary
|
138
|
+
const finalExtractionSummary = {
|
139
|
+
toolName,
|
140
|
+
inputKeysCount: Object.keys(input).length,
|
141
|
+
inputKeys: Object.keys(input),
|
142
|
+
hasParameters: Object.keys(input).length > 0,
|
143
|
+
duration: teRecord.duration ??
|
144
|
+
teRecord.executionTime ??
|
145
|
+
teRecord.responseTime ??
|
146
|
+
0,
|
147
|
+
hasOutput: !!(teRecord.output || teRecord.result || teRecord.response),
|
148
|
+
};
|
149
|
+
logger.debug("[TransformationUtils] Final parameter extraction result", finalExtractionSummary);
|
62
150
|
// Enhanced output extraction with success indication
|
63
151
|
const output = teRecord.output ||
|
64
152
|
teRecord.result ||
|
@@ -169,14 +257,61 @@ export function transformAvailableTools(availableTools) {
|
|
169
257
|
}
|
170
258
|
return availableTools.map((tool) => {
|
171
259
|
const toolRecord = tool;
|
260
|
+
let extractedParameters = {};
|
261
|
+
const inputSchema = toolRecord.inputSchema;
|
262
|
+
const directParameters = toolRecord.parameters;
|
263
|
+
const fallbackSchema = toolRecord.schema;
|
264
|
+
if (inputSchema && typeof inputSchema === "object") {
|
265
|
+
if (inputSchema.$ref && inputSchema.definitions) {
|
266
|
+
const definitions = inputSchema.definitions;
|
267
|
+
const refValue = inputSchema.$ref;
|
268
|
+
if (typeof refValue === "string") {
|
269
|
+
const refKey = refValue.replace("#/definitions/", "");
|
270
|
+
if (definitions[refKey] && typeof definitions[refKey] === "object") {
|
271
|
+
const resolvedSchema = definitions[refKey];
|
272
|
+
extractedParameters = {
|
273
|
+
type: resolvedSchema.type || "object",
|
274
|
+
properties: resolvedSchema.properties || {},
|
275
|
+
required: resolvedSchema.required || [],
|
276
|
+
...resolvedSchema, // Include all schema metadata
|
277
|
+
};
|
278
|
+
}
|
279
|
+
}
|
280
|
+
}
|
281
|
+
else if (inputSchema.properties) {
|
282
|
+
extractedParameters = {
|
283
|
+
type: inputSchema.type || "object",
|
284
|
+
properties: inputSchema.properties,
|
285
|
+
required: inputSchema.required || [],
|
286
|
+
...inputSchema,
|
287
|
+
};
|
288
|
+
}
|
289
|
+
else if (inputSchema.type === "object") {
|
290
|
+
extractedParameters = inputSchema;
|
291
|
+
}
|
292
|
+
else {
|
293
|
+
extractedParameters = inputSchema;
|
294
|
+
}
|
295
|
+
}
|
296
|
+
else if (directParameters && typeof directParameters === "object") {
|
297
|
+
extractedParameters = directParameters;
|
298
|
+
}
|
299
|
+
else if (fallbackSchema && typeof fallbackSchema === "object") {
|
300
|
+
extractedParameters = fallbackSchema;
|
301
|
+
}
|
302
|
+
if (!extractedParameters || typeof extractedParameters !== "object") {
|
303
|
+
extractedParameters = {};
|
304
|
+
}
|
305
|
+
if (extractedParameters &&
|
306
|
+
!extractedParameters.type &&
|
307
|
+
extractedParameters.properties) {
|
308
|
+
extractedParameters.type = "object";
|
309
|
+
}
|
172
310
|
return {
|
173
311
|
name: tool.name || "",
|
174
312
|
description: tool.description || "",
|
175
313
|
server: tool.server || "",
|
176
|
-
parameters:
|
177
|
-
toolRecord.parameters ||
|
178
|
-
toolRecord.schema ||
|
179
|
-
{},
|
314
|
+
parameters: extractedParameters,
|
180
315
|
};
|
181
316
|
});
|
182
317
|
}
|
@@ -246,7 +381,10 @@ export function transformSchemaToParameterDescription(schema) {
|
|
246
381
|
.map(([key, value]) => {
|
247
382
|
const typedValue = value;
|
248
383
|
const required = requiredParams.has(key) ? " (required)" : "";
|
249
|
-
|
384
|
+
const description = typedValue.description
|
385
|
+
? ` - ${typedValue.description}`
|
386
|
+
: "";
|
387
|
+
return ` - ${key}: ${typedValue.type || "unknown"}${required}${description}`;
|
250
388
|
})
|
251
389
|
.join("\n");
|
252
390
|
}
|
@@ -89,9 +89,9 @@ export class ExternalServerManager extends EventEmitter {
|
|
89
89
|
enablePerformanceMonitoring: config.enablePerformanceMonitoring ?? true,
|
90
90
|
logLevel: config.logLevel ?? "info",
|
91
91
|
};
|
92
|
-
//
|
92
|
+
// Disable main tool registry integration by default to prevent automatic tool execution
|
93
93
|
this.enableMainRegistryIntegration =
|
94
|
-
options.enableMainRegistryIntegration ??
|
94
|
+
options.enableMainRegistryIntegration ?? false;
|
95
95
|
// Initialize tool discovery service
|
96
96
|
this.toolDiscovery = new ToolDiscoveryService();
|
97
97
|
// Forward tool discovery events
|