remove some env vars
This commit is contained in:
parent
bcd92af8a0
commit
2cb25d1dd6
@ -60,7 +60,7 @@ FORENSIC_AUDIT_MAX_ENTRIES=50
|
|||||||
|
|
||||||
# === AI SEMANTIC SEARCH ===
|
# === AI SEMANTIC SEARCH ===
|
||||||
# Enable semantic search (highly recommended for better results)
|
# Enable semantic search (highly recommended for better results)
|
||||||
AI_EMBEDDINGS_ENABLED=true
|
REMOVE_AI_EMBEDDINGS_ENABLED=true
|
||||||
AI_EMBEDDINGS_ENDPOINT=https://api.mistral.ai/v1/embeddings
|
AI_EMBEDDINGS_ENDPOINT=https://api.mistral.ai/v1/embeddings
|
||||||
AI_EMBEDDINGS_API_KEY=your-embeddings-api-key-here
|
AI_EMBEDDINGS_API_KEY=your-embeddings-api-key-here
|
||||||
AI_EMBEDDINGS_MODEL=mistral-embed
|
AI_EMBEDDINGS_MODEL=mistral-embed
|
||||||
@ -122,8 +122,8 @@ AI_EMBEDDINGS_BATCH_SIZE=10
|
|||||||
AI_EMBEDDINGS_BATCH_DELAY_MS=1000
|
AI_EMBEDDINGS_BATCH_DELAY_MS=1000
|
||||||
|
|
||||||
# === Context Management ===
|
# === Context Management ===
|
||||||
AI_MAX_CONTEXT_TOKENS=4000
|
REMOVE_AI_MAX_CONTEXT_TOKENS=4000
|
||||||
AI_MAX_PROMPT_TOKENS=2500
|
REMOVE_AI_MAX_PROMPT_TOKENS=2500
|
||||||
|
|
||||||
# === Confidence Scoring ===
|
# === Confidence Scoring ===
|
||||||
CONFIDENCE_SEMANTIC_WEIGHT=0.5
|
CONFIDENCE_SEMANTIC_WEIGHT=0.5
|
||||||
|
@ -2,17 +2,15 @@
|
|||||||
|
|
||||||
export const AI_PROMPTS = {
|
export const AI_PROMPTS = {
|
||||||
|
|
||||||
toolSelection: (mode: string, userQuery: string, selectionMethod: string, maxSelectedItems: number) => {
|
toolSelection: (mode: string, userQuery: string, maxSelectedItems: number) => {
|
||||||
const modeInstruction = mode === 'workflow'
|
const modeInstruction = mode === 'workflow'
|
||||||
? 'Workflow mit 15-25 Items über alle Phasen. PFLICHT: Mindestens 40% Methoden, Rest Tools/Konzepte.'
|
? 'Workflow mit 15-25 Items über alle Phasen. PFLICHT: Mindestens 40% Methoden, Rest Tools/Konzepte.'
|
||||||
: 'Spezifische Lösung mit 4-10 Items. PFLICHT: Mindestens 30% Methoden wenn verfügbar.';
|
: 'Spezifische Lösung mit 4-10 Items. PFLICHT: Mindestens 30% Methoden wenn verfügbar.';
|
||||||
|
|
||||||
return `Du bist ein DFIR-Experte. Wähle die BESTEN Items aus dem vorgefilterten Set.
|
return `Du bist ein DFIR-Experte. Wähle die BESTEN Items aus dem vorgefilterten Set.
|
||||||
|
|
||||||
AUSWAHLMETHODE: ${selectionMethod}
|
AUSWAHLMETHODE:
|
||||||
${selectionMethod === 'embeddings_candidates' ?
|
'✓ Semantisch relevante Items bereits vorgefiltert\n✓ Wähle die BESTEN für die konkrete Aufgabe'}
|
||||||
'✓ Semantisch relevante Items bereits vorgefiltert\n✓ Wähle die BESTEN für die konkrete Aufgabe' :
|
|
||||||
'✓ Vollständige Datenbank verfügbar\n✓ Wähle die relevantesten Items'}
|
|
||||||
|
|
||||||
${modeInstruction}
|
${modeInstruction}
|
||||||
|
|
||||||
@ -309,7 +307,7 @@ Antwort: Fließtext ohne Listen, max ${isWorkflow ? '100' : '80'} Wörter.`;
|
|||||||
}
|
}
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export function getPrompt(key: 'toolSelection', mode: string, userQuery: string, selectionMethod: string, maxSelectedItems: number): string;
|
export function getPrompt(key: 'toolSelection', mode: string, userQuery: string, maxSelectedItems: number): string;
|
||||||
export function getPrompt(key: 'toolSelectionWithData', basePrompt: string, toolsToSend: any[], conceptsToSend: any[]): string;
|
export function getPrompt(key: 'toolSelectionWithData', basePrompt: string, toolsToSend: any[], conceptsToSend: any[]): string;
|
||||||
export function getPrompt(key: 'scenarioAnalysis', isWorkflow: boolean, userQuery: string): string;
|
export function getPrompt(key: 'scenarioAnalysis', isWorkflow: boolean, userQuery: string): string;
|
||||||
export function getPrompt(key: 'investigationApproach', isWorkflow: boolean, userQuery: string): string;
|
export function getPrompt(key: 'investigationApproach', isWorkflow: boolean, userQuery: string): string;
|
||||||
|
@ -11,7 +11,7 @@ import 'dotenv/config';
|
|||||||
|
|
||||||
interface PipelineConfig {
|
interface PipelineConfig {
|
||||||
microTaskDelay: number;
|
microTaskDelay: number;
|
||||||
maxContextTokens: number;
|
//maxContextTokens: number;
|
||||||
maxPromptTokens: number;
|
maxPromptTokens: number;
|
||||||
taskRelevanceModeration: {
|
taskRelevanceModeration: {
|
||||||
maxInitialScore: number;
|
maxInitialScore: number;
|
||||||
@ -36,7 +36,7 @@ interface MicroTaskResult {
|
|||||||
interface AnalysisResult {
|
interface AnalysisResult {
|
||||||
recommendation: any;
|
recommendation: any;
|
||||||
processingStats: {
|
processingStats: {
|
||||||
embeddingsUsed: boolean;
|
//embeddingsUsed: boolean;
|
||||||
candidatesFromEmbeddings: number;
|
candidatesFromEmbeddings: number;
|
||||||
finalSelectedItems: number;
|
finalSelectedItems: number;
|
||||||
processingTimeMs: number;
|
processingTimeMs: number;
|
||||||
@ -57,7 +57,7 @@ interface PipelineContext {
|
|||||||
mode: string;
|
mode: string;
|
||||||
filteredData: any;
|
filteredData: any;
|
||||||
contextHistory: string[];
|
contextHistory: string[];
|
||||||
maxContextLength: number;
|
//maxContextLength: number;
|
||||||
currentContextLength: number;
|
currentContextLength: number;
|
||||||
scenarioAnalysis?: string;
|
scenarioAnalysis?: string;
|
||||||
problemAnalysis?: string;
|
problemAnalysis?: string;
|
||||||
@ -91,7 +91,7 @@ class AIPipeline {
|
|||||||
constructor() {
|
constructor() {
|
||||||
this.config = {
|
this.config = {
|
||||||
microTaskDelay: parseInt(process.env.AI_MICRO_TASK_DELAY_MS || '500', 10),
|
microTaskDelay: parseInt(process.env.AI_MICRO_TASK_DELAY_MS || '500', 10),
|
||||||
maxContextTokens: parseInt(process.env.AI_MAX_CONTEXT_TOKENS || '4000', 10),
|
//maxContextTokens: parseInt(process.env.AI_MAX_CONTEXT_TOKENS || '4000', 10),
|
||||||
maxPromptTokens: parseInt(process.env.AI_MAX_PROMPT_TOKENS || '1500', 10),
|
maxPromptTokens: parseInt(process.env.AI_MAX_PROMPT_TOKENS || '1500', 10),
|
||||||
taskRelevanceModeration: {
|
taskRelevanceModeration: {
|
||||||
maxInitialScore: 85,
|
maxInitialScore: 85,
|
||||||
@ -123,7 +123,7 @@ class AIPipeline {
|
|||||||
mode,
|
mode,
|
||||||
filteredData: {},
|
filteredData: {},
|
||||||
contextHistory: [],
|
contextHistory: [],
|
||||||
maxContextLength: this.config.maxContextTokens,
|
//maxContextLength: this.config.maxContextTokens,
|
||||||
currentContextLength: 0,
|
currentContextLength: 0,
|
||||||
seenToolNames: new Set<string>(),
|
seenToolNames: new Set<string>(),
|
||||||
embeddingsSimilarities: new Map<string, number>(),
|
embeddingsSimilarities: new Map<string, number>(),
|
||||||
@ -138,20 +138,20 @@ class AIPipeline {
|
|||||||
const selectionConfidence = this.calculateToolSelectionConfidence(
|
const selectionConfidence = this.calculateToolSelectionConfidence(
|
||||||
candidateData.tools.length,
|
candidateData.tools.length,
|
||||||
toolsData.tools.length,
|
toolsData.tools.length,
|
||||||
candidateData.selectionMethod,
|
//candidateData.selectionMethod,
|
||||||
candidateData.concepts.length
|
candidateData.concepts.length
|
||||||
);
|
);
|
||||||
|
|
||||||
auditService.addToolSelection(
|
auditService.addToolSelection(
|
||||||
candidateData.tools.map(t => t.name),
|
candidateData.tools.map(t => t.name),
|
||||||
toolsData.tools.map(t => t.name),
|
toolsData.tools.map(t => t.name),
|
||||||
candidateData.selectionMethod,
|
//candidateData.selectionMethod,
|
||||||
selectionConfidence,
|
selectionConfidence,
|
||||||
candidateSelectionStart,
|
candidateSelectionStart,
|
||||||
{
|
{
|
||||||
embeddingsUsed: embeddingsService.isEnabled(),
|
//embeddingsUsed: embeddingsService.isEnabled(),
|
||||||
totalCandidatesFound: candidateData.tools.length + candidateData.concepts.length,
|
totalCandidatesFound: candidateData.tools.length + candidateData.concepts.length,
|
||||||
selectionMethod: candidateData.selectionMethod,
|
//selectionMethod: candidateData.selectionMethod,
|
||||||
reductionRatio: candidateData.tools.length / toolsData.tools.length
|
reductionRatio: candidateData.tools.length / toolsData.tools.length
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -201,7 +201,7 @@ class AIPipeline {
|
|||||||
const recommendation = this.buildRecommendation(context, mode, finalResult.content);
|
const recommendation = this.buildRecommendation(context, mode, finalResult.content);
|
||||||
|
|
||||||
const processingStats = {
|
const processingStats = {
|
||||||
embeddingsUsed: embeddingsService.isEnabled(),
|
//embeddingsUsed: embeddingsService.isEnabled(),
|
||||||
candidatesFromEmbeddings: candidateData.tools.length,
|
candidatesFromEmbeddings: candidateData.tools.length,
|
||||||
finalSelectedItems: (context.selectedTools?.length || 0) + (context.backgroundKnowledge?.length || 0),
|
finalSelectedItems: (context.selectedTools?.length || 0) + (context.backgroundKnowledge?.length || 0),
|
||||||
processingTimeMs: Date.now() - startTime,
|
processingTimeMs: Date.now() - startTime,
|
||||||
@ -213,7 +213,7 @@ class AIPipeline {
|
|||||||
aiModel: aiConfig.model,
|
aiModel: aiConfig.model,
|
||||||
toolsDataHash,
|
toolsDataHash,
|
||||||
temperature: 0.3,
|
temperature: 0.3,
|
||||||
maxTokensUsed: 2500
|
maxTokensUsed: 32768
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log('[AI-PIPELINE] Pipeline completed successfully:', {
|
console.log('[AI-PIPELINE] Pipeline completed successfully:', {
|
||||||
@ -292,7 +292,7 @@ class AIPipeline {
|
|||||||
private calculateToolSelectionConfidence(
|
private calculateToolSelectionConfidence(
|
||||||
selectedCount: number,
|
selectedCount: number,
|
||||||
totalCount: number,
|
totalCount: number,
|
||||||
method: string,
|
//method: string,
|
||||||
conceptsCount: number
|
conceptsCount: number
|
||||||
): number {
|
): number {
|
||||||
let confidence = 50;
|
let confidence = 50;
|
||||||
@ -307,9 +307,9 @@ class AIPipeline {
|
|||||||
confidence -= 15;
|
confidence -= 15;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (method.includes('embeddings')) {
|
//if (method.includes('embeddings')) {
|
||||||
confidence += 15;
|
//confidence += 15;
|
||||||
}
|
//}
|
||||||
|
|
||||||
if (conceptsCount > 0) {
|
if (conceptsCount > 0) {
|
||||||
confidence += 10;
|
confidence += 10;
|
||||||
@ -1280,10 +1280,12 @@ class AIPipeline {
|
|||||||
context.contextHistory.push(newEntry);
|
context.contextHistory.push(newEntry);
|
||||||
context.currentContextLength += entryTokens;
|
context.currentContextLength += entryTokens;
|
||||||
|
|
||||||
while (context.currentContextLength > this.config.maxContextTokens && context.contextHistory.length > 1) {
|
/*while (context.currentContextLength > this.config.maxContextTokens && context.contextHistory.length > 1) {
|
||||||
const removed = context.contextHistory.shift()!;
|
const removed = context.contextHistory.shift()!;
|
||||||
context.currentContextLength -= aiService.estimateTokens(removed);
|
context.currentContextLength -= aiService.estimateTokens(removed);
|
||||||
}
|
}*/
|
||||||
|
const removed = context.contextHistory.shift()!;
|
||||||
|
context.currentContextLength -= aiService.estimateTokens(removed);
|
||||||
}
|
}
|
||||||
|
|
||||||
private addToolToSelection(
|
private addToolToSelection(
|
||||||
|
@ -34,7 +34,7 @@ class AIService {
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.defaultOptions = {
|
this.defaultOptions = {
|
||||||
maxTokens: 1500,
|
maxTokens: 32768,
|
||||||
temperature: 0.3,
|
temperature: 0.3,
|
||||||
timeout: 30000
|
timeout: 30000
|
||||||
};
|
};
|
||||||
|
@ -26,7 +26,7 @@ export interface AuditEntry {
|
|||||||
completionTokens?: number;
|
completionTokens?: number;
|
||||||
toolsDataHash?: string;
|
toolsDataHash?: string;
|
||||||
embeddingsUsed?: boolean;
|
embeddingsUsed?: boolean;
|
||||||
selectionMethod?: string;
|
//selectionMethod?: string;
|
||||||
microTaskType?: string;
|
microTaskType?: string;
|
||||||
confidenceFactors?: string[];
|
confidenceFactors?: string[];
|
||||||
reasoning?: string;
|
reasoning?: string;
|
||||||
@ -146,7 +146,7 @@ class AuditService {
|
|||||||
addToolSelection(
|
addToolSelection(
|
||||||
selectedTools: string[],
|
selectedTools: string[],
|
||||||
availableTools: string[],
|
availableTools: string[],
|
||||||
selectionMethod: string,
|
//selectionMethod: string,
|
||||||
confidence: number,
|
confidence: number,
|
||||||
startTime: number,
|
startTime: number,
|
||||||
metadata: Record<string, any> = {}
|
metadata: Record<string, any> = {}
|
||||||
@ -154,17 +154,22 @@ class AuditService {
|
|||||||
const calculatedConfidence = this.calculateSelectionConfidence(
|
const calculatedConfidence = this.calculateSelectionConfidence(
|
||||||
selectedTools,
|
selectedTools,
|
||||||
availableTools,
|
availableTools,
|
||||||
selectionMethod,
|
//selectionMethod,
|
||||||
metadata
|
metadata
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const decisionBasis =
|
||||||
|
metadata.embeddingsUsed || metadata.similarityScores
|
||||||
|
? 'semantic-search'
|
||||||
|
: (metadata.aiPrompt || metadata.microTaskType ? 'ai-analysis' : 'rule-based');
|
||||||
|
|
||||||
this.addEntry(
|
this.addEntry(
|
||||||
'tool-selection',
|
'tool-selection',
|
||||||
'selection-decision',
|
'selection-decision',
|
||||||
{
|
{
|
||||||
availableTools: availableTools.slice(0, 10),
|
availableTools: availableTools.slice(0, 10),
|
||||||
totalAvailable: availableTools.length,
|
totalAvailable: availableTools.length,
|
||||||
selectionMethod: selectionMethod
|
//selectionMethod: selectionMethod
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
selectedTools: selectedTools,
|
selectedTools: selectedTools,
|
||||||
@ -174,10 +179,11 @@ class AuditService {
|
|||||||
startTime,
|
startTime,
|
||||||
{
|
{
|
||||||
...metadata,
|
...metadata,
|
||||||
selectionMethod,
|
//selectionMethod,
|
||||||
availableToolsCount: availableTools.length,
|
availableToolsCount: availableTools.length,
|
||||||
selectedToolsCount: selectedTools.length,
|
selectedToolsCount: selectedTools.length,
|
||||||
decisionBasis: selectionMethod.includes('embeddings') ? 'semantic-search' : 'ai-analysis'
|
//decisionBasis: selectionMethod.includes('embeddings') ? 'semantic-search' : 'ai-analysis'
|
||||||
|
decisionBasis
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -282,7 +288,7 @@ class AuditService {
|
|||||||
private calculateSelectionConfidence(
|
private calculateSelectionConfidence(
|
||||||
selectedTools: string[],
|
selectedTools: string[],
|
||||||
availableTools: string[],
|
availableTools: string[],
|
||||||
selectionMethod: string,
|
//selectionMethod: string,
|
||||||
metadata: Record<string, any>
|
metadata: Record<string, any>
|
||||||
): number {
|
): number {
|
||||||
let confidence = 50;
|
let confidence = 50;
|
||||||
@ -297,9 +303,9 @@ class AuditService {
|
|||||||
confidence -= 20;
|
confidence -= 20;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selectionMethod.includes('embeddings')) {
|
/*if (selectionMethod.includes('embeddings')) {
|
||||||
confidence += 15;
|
confidence += 15;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
if (selectedTools.length >= 5 && selectedTools.length <= 25) {
|
if (selectedTools.length >= 5 && selectedTools.length <= 25) {
|
||||||
confidence += 10;
|
confidence += 10;
|
||||||
@ -589,7 +595,8 @@ class AuditService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private inferDecisionBasis(metadata: Record<string, any>): string {
|
private inferDecisionBasis(metadata: Record<string, any>): string {
|
||||||
if (metadata.embeddingsUsed || metadata.selectionMethod?.includes('embeddings')) return 'semantic-search';
|
if (metadata.embeddingsUsed) return 'semantic-search';
|
||||||
|
//if (metadata.embeddingsUsed || metadata.selectionMethod?.includes('embeddings')) return 'semantic-search';
|
||||||
if (metadata.aiPrompt || metadata.microTaskType) return 'ai-analysis';
|
if (metadata.aiPrompt || metadata.microTaskType) return 'ai-analysis';
|
||||||
if (metadata.semanticQuery && metadata.aiReasoningUsed) return 'hybrid';
|
if (metadata.semanticQuery && metadata.aiReasoningUsed) return 'hybrid';
|
||||||
return 'rule-based';
|
return 'rule-based';
|
||||||
|
@ -31,7 +31,7 @@ interface EmbeddingsDatabase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface EmbeddingsConfig {
|
interface EmbeddingsConfig {
|
||||||
enabled: boolean;
|
//enabled: boolean;
|
||||||
endpoint?: string;
|
endpoint?: string;
|
||||||
apiKey?: string;
|
apiKey?: string;
|
||||||
model?: string;
|
model?: string;
|
||||||
@ -49,14 +49,14 @@ class EmbeddingsService {
|
|||||||
constructor() {
|
constructor() {
|
||||||
this.config = this.loadConfig();
|
this.config = this.loadConfig();
|
||||||
console.log('[EMBEDDINGS-SERVICE] Initialized:', {
|
console.log('[EMBEDDINGS-SERVICE] Initialized:', {
|
||||||
enabled: this.config.enabled,
|
//enabled: this.config.enabled,
|
||||||
hasEndpoint: !!this.config.endpoint,
|
hasEndpoint: !!this.config.endpoint,
|
||||||
hasModel: !!this.config.model
|
hasModel: !!this.config.model
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private loadConfig(): EmbeddingsConfig {
|
private loadConfig(): EmbeddingsConfig {
|
||||||
const enabled = process.env.AI_EMBEDDINGS_ENABLED === 'true';
|
//const enabled = process.env.AI_EMBEDDINGS_ENABLED === 'true';
|
||||||
const endpoint = process.env.AI_EMBEDDINGS_ENDPOINT;
|
const endpoint = process.env.AI_EMBEDDINGS_ENDPOINT;
|
||||||
const apiKey = process.env.AI_EMBEDDINGS_API_KEY;
|
const apiKey = process.env.AI_EMBEDDINGS_API_KEY;
|
||||||
const model = process.env.AI_EMBEDDINGS_MODEL;
|
const model = process.env.AI_EMBEDDINGS_MODEL;
|
||||||
@ -64,7 +64,7 @@ class EmbeddingsService {
|
|||||||
const batchDelay = parseInt(process.env.AI_EMBEDDINGS_BATCH_DELAY_MS || '1000', 10);
|
const batchDelay = parseInt(process.env.AI_EMBEDDINGS_BATCH_DELAY_MS || '1000', 10);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
enabled,
|
//enabled,
|
||||||
endpoint,
|
endpoint,
|
||||||
apiKey,
|
apiKey,
|
||||||
model,
|
model,
|
||||||
@ -92,10 +92,10 @@ class EmbeddingsService {
|
|||||||
try {
|
try {
|
||||||
console.log('[EMBEDDINGS-SERVICE] Starting initialization');
|
console.log('[EMBEDDINGS-SERVICE] Starting initialization');
|
||||||
|
|
||||||
if (!this.config.enabled) {
|
/*if (!this.config.enabled) {
|
||||||
console.log('[EMBEDDINGS-SERVICE] Service disabled via configuration');
|
console.log('[EMBEDDINGS-SERVICE] Service disabled via configuration');
|
||||||
return;
|
return;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
await fs.mkdir(path.dirname(this.embeddingsPath), { recursive: true });
|
await fs.mkdir(path.dirname(this.embeddingsPath), { recursive: true });
|
||||||
|
|
||||||
@ -263,7 +263,7 @@ class EmbeddingsService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async embedText(text: string): Promise<number[]> {
|
async embedText(text: string): Promise<number[]> {
|
||||||
if (!this.isEnabled() || !this.isInitialized) {
|
if (!this.isInitialized) {
|
||||||
throw new Error('Embeddings service not available');
|
throw new Error('Embeddings service not available');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -272,9 +272,9 @@ class EmbeddingsService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async waitForInitialization(): Promise<void> {
|
async waitForInitialization(): Promise<void> {
|
||||||
if (!this.config.enabled) {
|
/*if (!this.config.enabled) {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}*/
|
||||||
|
|
||||||
if (this.isInitialized) {
|
if (this.isInitialized) {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
@ -303,10 +303,10 @@ class EmbeddingsService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async findSimilar(query: string, maxResults: number = 30, threshold: number = 0.3): Promise<SimilarityResult[]> {
|
async findSimilar(query: string, maxResults: number = 30, threshold: number = 0.3): Promise<SimilarityResult[]> {
|
||||||
if (!this.config.enabled) {
|
/*if (!this.config.enabled) {
|
||||||
console.log('[EMBEDDINGS-SERVICE] Service disabled, returning empty results');
|
console.log('[EMBEDDINGS-SERVICE] Service disabled, returning empty results');
|
||||||
return [];
|
return [];
|
||||||
}
|
}*/
|
||||||
|
|
||||||
if (!this.isInitialized || this.embeddings.length === 0) {
|
if (!this.isInitialized || this.embeddings.length === 0) {
|
||||||
console.log('[EMBEDDINGS-SERVICE] Not initialized or no embeddings available');
|
console.log('[EMBEDDINGS-SERVICE] Not initialized or no embeddings available');
|
||||||
@ -349,16 +349,24 @@ class EmbeddingsService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
isEnabled(): boolean {
|
/*isEnabled(): boolean {
|
||||||
return this.config.enabled;
|
return this.config.enabled;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
getStats(): { enabled: boolean; initialized: boolean; count: number } {
|
/*getStats(): { enabled: boolean; initialized: boolean; count: number } {
|
||||||
return {
|
return {
|
||||||
enabled: this.config.enabled,
|
enabled: this.config.enabled,
|
||||||
initialized: this.isInitialized,
|
initialized: this.isInitialized,
|
||||||
count: this.embeddings.length
|
count: this.embeddings.length
|
||||||
};
|
};
|
||||||
|
}*/
|
||||||
|
|
||||||
|
getStats(): {initialized: boolean; count: number } {
|
||||||
|
return {
|
||||||
|
//enabled: this.config.enabled,
|
||||||
|
initialized: this.isInitialized,
|
||||||
|
count: this.embeddings.length
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
getConfig(): EmbeddingsConfig {
|
getConfig(): EmbeddingsConfig {
|
||||||
|
@ -38,7 +38,7 @@ export interface SelectionContext {
|
|||||||
export interface ToolSelectionResult {
|
export interface ToolSelectionResult {
|
||||||
selectedTools: any[];
|
selectedTools: any[];
|
||||||
selectedConcepts: any[];
|
selectedConcepts: any[];
|
||||||
selectionMethod: string;
|
//selectionMethod: string;
|
||||||
confidence: number;
|
confidence: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,13 +84,13 @@ class ToolSelector {
|
|||||||
domains: any[];
|
domains: any[];
|
||||||
phases: any[];
|
phases: any[];
|
||||||
'domain-agnostic-software': any[];
|
'domain-agnostic-software': any[];
|
||||||
selectionMethod: string;
|
//selectionMethod: string;
|
||||||
}> {
|
}> {
|
||||||
console.log('[TOOL-SELECTOR] Getting intelligent candidates for query');
|
console.log('[TOOL-SELECTOR] Getting intelligent candidates for query');
|
||||||
|
|
||||||
let candidateTools: any[] = [];
|
let candidateTools: any[] = [];
|
||||||
let candidateConcepts: any[] = [];
|
let candidateConcepts: any[] = [];
|
||||||
let selectionMethod = 'unknown';
|
//let selectionMethod = 'unknown';
|
||||||
|
|
||||||
context.embeddingsSimilarities.clear();
|
context.embeddingsSimilarities.clear();
|
||||||
|
|
||||||
@ -100,62 +100,56 @@ class ToolSelector {
|
|||||||
console.error('[TOOL-SELECTOR] Embeddings initialization failed:', error);
|
console.error('[TOOL-SELECTOR] Embeddings initialization failed:', error);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (embeddingsService.isEnabled()) {
|
console.log('[TOOL-SELECTOR] Using embeddings for candidate selection');
|
||||||
console.log('[TOOL-SELECTOR] Using embeddings for candidate selection');
|
|
||||||
|
const similarItems = await embeddingsService.findSimilar(
|
||||||
|
userQuery,
|
||||||
|
this.config.embeddingCandidates,
|
||||||
|
this.config.similarityThreshold
|
||||||
|
) as SimilarityResult[];
|
||||||
|
|
||||||
|
console.log('[TOOL-SELECTOR] Embeddings found', similarItems.length, 'similar items');
|
||||||
|
|
||||||
|
similarItems.forEach(item => {
|
||||||
|
context.embeddingsSimilarities.set(item.name, item.similarity);
|
||||||
|
});
|
||||||
|
|
||||||
|
const toolsMap = new Map(toolsData.tools.map((tool: any) => [tool.name, tool]));
|
||||||
|
const conceptsMap = new Map(toolsData.concepts.map((concept: any) => [concept.name, concept]));
|
||||||
|
|
||||||
|
const similarTools = similarItems
|
||||||
|
.filter((item: any) => item.type === 'tool')
|
||||||
|
.map((item: any) => toolsMap.get(item.name))
|
||||||
|
.filter((tool: any): tool is NonNullable<any> => tool !== undefined && tool !== null);
|
||||||
|
|
||||||
|
const similarConcepts = similarItems
|
||||||
|
.filter((item: any) => item.type === 'concept')
|
||||||
|
.map((item: any) => conceptsMap.get(item.name))
|
||||||
|
.filter((concept: any): concept is NonNullable<any> => concept !== undefined && concept !== null);
|
||||||
|
|
||||||
|
const totalAvailableTools = toolsData.tools.length;
|
||||||
|
const reductionRatio = similarTools.length / totalAvailableTools;
|
||||||
|
|
||||||
|
if (similarTools.length >= this.config.embeddingsMinTools && reductionRatio <= this.config.embeddingsMaxReductionRatio) {
|
||||||
|
candidateTools = similarTools;
|
||||||
|
candidateConcepts = similarConcepts;
|
||||||
|
//selectionMethod = 'embeddings_candidates';
|
||||||
|
|
||||||
const similarItems = await embeddingsService.findSimilar(
|
console.log('[TOOL-SELECTOR] Using embeddings filtering:', totalAvailableTools, '→', similarTools.length, 'tools');
|
||||||
userQuery,
|
|
||||||
this.config.embeddingCandidates,
|
|
||||||
this.config.similarityThreshold
|
|
||||||
) as SimilarityResult[];
|
|
||||||
|
|
||||||
console.log('[TOOL-SELECTOR] Embeddings found', similarItems.length, 'similar items');
|
|
||||||
|
|
||||||
similarItems.forEach(item => {
|
|
||||||
context.embeddingsSimilarities.set(item.name, item.similarity);
|
|
||||||
});
|
|
||||||
|
|
||||||
const toolsMap = new Map(toolsData.tools.map((tool: any) => [tool.name, tool]));
|
|
||||||
const conceptsMap = new Map(toolsData.concepts.map((concept: any) => [concept.name, concept]));
|
|
||||||
|
|
||||||
const similarTools = similarItems
|
|
||||||
.filter((item: any) => item.type === 'tool')
|
|
||||||
.map((item: any) => toolsMap.get(item.name))
|
|
||||||
.filter((tool: any): tool is NonNullable<any> => tool !== undefined && tool !== null);
|
|
||||||
|
|
||||||
const similarConcepts = similarItems
|
|
||||||
.filter((item: any) => item.type === 'concept')
|
|
||||||
.map((item: any) => conceptsMap.get(item.name))
|
|
||||||
.filter((concept: any): concept is NonNullable<any> => concept !== undefined && concept !== null);
|
|
||||||
|
|
||||||
const totalAvailableTools = toolsData.tools.length;
|
|
||||||
const reductionRatio = similarTools.length / totalAvailableTools;
|
|
||||||
|
|
||||||
if (similarTools.length >= this.config.embeddingsMinTools && reductionRatio <= this.config.embeddingsMaxReductionRatio) {
|
|
||||||
candidateTools = similarTools;
|
|
||||||
candidateConcepts = similarConcepts;
|
|
||||||
selectionMethod = 'embeddings_candidates';
|
|
||||||
|
|
||||||
console.log('[TOOL-SELECTOR] Using embeddings filtering:', totalAvailableTools, '→', similarTools.length, 'tools');
|
|
||||||
} else {
|
|
||||||
console.log('[TOOL-SELECTOR] Embeddings filtering insufficient, using full dataset');
|
|
||||||
candidateTools = toolsData.tools;
|
|
||||||
candidateConcepts = toolsData.concepts;
|
|
||||||
selectionMethod = 'full_dataset';
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
console.log('[TOOL-SELECTOR] Embeddings disabled, using full dataset');
|
console.log('[TOOL-SELECTOR] Embeddings filtering insufficient, using full dataset');
|
||||||
candidateTools = toolsData.tools;
|
candidateTools = toolsData.tools;
|
||||||
candidateConcepts = toolsData.concepts;
|
candidateConcepts = toolsData.concepts;
|
||||||
selectionMethod = 'full_dataset';
|
//selectionMethod = 'full_dataset';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const selection = await this.performAISelection(
|
const selection = await this.performAISelection(
|
||||||
userQuery,
|
userQuery,
|
||||||
candidateTools,
|
candidateTools,
|
||||||
candidateConcepts,
|
candidateConcepts,
|
||||||
mode,
|
mode,
|
||||||
selectionMethod,
|
//selectionMethod,
|
||||||
context
|
context
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -165,7 +159,7 @@ class ToolSelector {
|
|||||||
domains: toolsData.domains,
|
domains: toolsData.domains,
|
||||||
phases: toolsData.phases,
|
phases: toolsData.phases,
|
||||||
'domain-agnostic-software': toolsData['domain-agnostic-software'],
|
'domain-agnostic-software': toolsData['domain-agnostic-software'],
|
||||||
selectionMethod
|
//selectionMethod
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,81 +168,56 @@ class ToolSelector {
|
|||||||
candidateTools: any[],
|
candidateTools: any[],
|
||||||
candidateConcepts: any[],
|
candidateConcepts: any[],
|
||||||
mode: string,
|
mode: string,
|
||||||
selectionMethod: string,
|
|
||||||
context: SelectionContext
|
context: SelectionContext
|
||||||
): Promise<ToolSelectionResult> {
|
): Promise<ToolSelectionResult> {
|
||||||
console.log('[TOOL-SELECTOR] Performing AI selection');
|
console.log('[TOOL-SELECTOR] Performing AI selection');
|
||||||
|
|
||||||
const candidateMethods = candidateTools.filter((tool: any) => tool && tool.type === 'method');
|
const candidateMethods = candidateTools.filter((tool: any) => tool && tool.type === 'method');
|
||||||
const candidateSoftware = candidateTools.filter((tool: any) => tool && tool.type === 'software');
|
const candidateSoftware = candidateTools.filter((tool: any) => tool && tool.type === 'software');
|
||||||
|
|
||||||
console.log('[TOOL-SELECTOR] Candidates:', candidateMethods.length, 'methods,', candidateSoftware.length, 'software,', candidateConcepts.length, 'concepts');
|
console.log('[TOOL-SELECTOR] Candidates:', candidateMethods.length, 'methods,', candidateSoftware.length, 'software,', candidateConcepts.length, 'concepts');
|
||||||
|
|
||||||
const methodsWithFullData = candidateMethods.map(this.createToolData);
|
const methodsWithFullData = candidateMethods.map(this.createToolData);
|
||||||
const softwareWithFullData = candidateSoftware.map(this.createToolData);
|
const softwareWithFullData = candidateSoftware.map(this.createToolData);
|
||||||
const conceptsWithFullData = candidateConcepts.map(this.createConceptData);
|
const conceptsWithFullData = candidateConcepts.map(this.createConceptData);
|
||||||
|
|
||||||
let toolsToSend: any[];
|
// Unified selection limits (method-agnostic)
|
||||||
let conceptsToSend: any[];
|
const maxTools = Math.min(this.config.embeddingSelectionLimit, this.config.noEmbeddingsToolLimit);
|
||||||
|
const maxConcepts = Math.min(this.config.embeddingConceptsLimit, this.config.noEmbeddingsConceptLimit);
|
||||||
if (selectionMethod === 'embeddings_candidates') {
|
const methodLimit = Math.ceil(maxTools * this.config.methodSelectionRatio);
|
||||||
const totalLimit = this.config.embeddingSelectionLimit;
|
const softwareLimit = Math.floor(maxTools * this.config.softwareSelectionRatio);
|
||||||
const methodLimit = Math.ceil(totalLimit * this.config.methodSelectionRatio);
|
|
||||||
const softwareLimit = Math.floor(totalLimit * this.config.softwareSelectionRatio);
|
// Build tool list to send
|
||||||
|
const toolsToSend: any[] = [
|
||||||
toolsToSend = [
|
...methodsWithFullData.slice(0, methodLimit),
|
||||||
...methodsWithFullData.slice(0, methodLimit),
|
...softwareWithFullData.slice(0, softwareLimit),
|
||||||
...softwareWithFullData.slice(0, softwareLimit)
|
];
|
||||||
];
|
|
||||||
|
const remainingCapacity = maxTools - toolsToSend.length;
|
||||||
const remainingCapacity = totalLimit - toolsToSend.length;
|
if (remainingCapacity > 0) {
|
||||||
if (remainingCapacity > 0) {
|
// Fill remainder from whichever bucket still has items
|
||||||
if (methodsWithFullData.length > methodLimit) {
|
const extraMethods = methodsWithFullData.slice(methodLimit, methodLimit + remainingCapacity);
|
||||||
toolsToSend.push(...methodsWithFullData.slice(methodLimit, methodLimit + remainingCapacity));
|
const extraSoftware = softwareWithFullData.slice(softwareLimit, softwareLimit + (remainingCapacity - extraMethods.length));
|
||||||
} else if (softwareWithFullData.length > softwareLimit) {
|
toolsToSend.push(...extraMethods, ...extraSoftware);
|
||||||
toolsToSend.push(...softwareWithFullData.slice(softwareLimit, softwareLimit + remainingCapacity));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
conceptsToSend = conceptsWithFullData.slice(0, this.config.embeddingConceptsLimit);
|
|
||||||
} else {
|
|
||||||
const maxTools = this.config.noEmbeddingsToolLimit;
|
|
||||||
const maxConcepts = this.config.noEmbeddingsConceptLimit;
|
|
||||||
const methodLimit = Math.ceil(maxTools * 0.4);
|
|
||||||
const softwareLimit = Math.floor(maxTools * 0.5);
|
|
||||||
|
|
||||||
toolsToSend = [
|
|
||||||
...methodsWithFullData.slice(0, methodLimit),
|
|
||||||
...softwareWithFullData.slice(0, softwareLimit)
|
|
||||||
];
|
|
||||||
|
|
||||||
const remainingCapacity = maxTools - toolsToSend.length;
|
|
||||||
if (remainingCapacity > 0) {
|
|
||||||
if (methodsWithFullData.length > methodLimit) {
|
|
||||||
toolsToSend.push(...methodsWithFullData.slice(methodLimit, methodLimit + remainingCapacity));
|
|
||||||
} else if (softwareWithFullData.length > softwareLimit) {
|
|
||||||
toolsToSend.push(...softwareWithFullData.slice(softwareLimit, softwareLimit + remainingCapacity));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
conceptsToSend = conceptsWithFullData.slice(0, maxConcepts);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const basePrompt = getPrompt('toolSelection', mode, userQuery, selectionMethod, this.config.maxSelectedItems);
|
const conceptsToSend = conceptsWithFullData.slice(0, maxConcepts);
|
||||||
|
|
||||||
|
const basePrompt = getPrompt('toolSelection', mode, userQuery, this.config.maxSelectedItems);
|
||||||
const prompt = getPrompt('toolSelectionWithData', basePrompt, toolsToSend, conceptsToSend);
|
const prompt = getPrompt('toolSelectionWithData', basePrompt, toolsToSend, conceptsToSend);
|
||||||
|
|
||||||
aiService.validatePromptLength(prompt);
|
aiService.validatePromptLength(prompt);
|
||||||
|
|
||||||
console.log('[TOOL-SELECTOR] Sending to AI:',
|
console.log('[TOOL-SELECTOR] Sending to AI:',
|
||||||
toolsToSend.filter((t: any) => t.type === 'method').length, 'methods,',
|
toolsToSend.filter((t: any) => t.type === 'method').length, 'methods,',
|
||||||
toolsToSend.filter((t: any) => t.type === 'software').length, 'software,',
|
toolsToSend.filter((t: any) => t.type === 'software').length, 'software,',
|
||||||
conceptsToSend.length, 'concepts'
|
conceptsToSend.length, 'concepts'
|
||||||
);
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await aiService.callAI(prompt, { maxTokens: 2500 });
|
const response = await aiService.callAI(prompt, { maxTokens: 32768 });
|
||||||
const result = JSONParser.safeParseJSON(response.content, null);
|
const result = JSONParser.safeParseJSON(response.content, null);
|
||||||
|
|
||||||
if (!result || !Array.isArray(result.selectedTools) || !Array.isArray(result.selectedConcepts)) {
|
if (!result || !Array.isArray(result.selectedTools) || !Array.isArray(result.selectedConcepts)) {
|
||||||
console.error('[TOOL-SELECTOR] AI selection returned invalid structure');
|
console.error('[TOOL-SELECTOR] AI selection returned invalid structure');
|
||||||
throw new Error('AI selection failed to return valid tool and concept selection');
|
throw new Error('AI selection failed to return valid tool and concept selection');
|
||||||
@ -258,38 +227,36 @@ class ToolSelector {
|
|||||||
if (totalSelected === 0) {
|
if (totalSelected === 0) {
|
||||||
throw new Error('AI selection returned empty selection');
|
throw new Error('AI selection returned empty selection');
|
||||||
}
|
}
|
||||||
|
|
||||||
const toolsMap = new Map(candidateTools.map((tool: any) => [tool.name, tool]));
|
const toolsMap = new Map(candidateTools.map((tool: any) => [tool.name, tool]));
|
||||||
const conceptsMap = new Map(candidateConcepts.map((concept: any) => [concept.name, concept]));
|
const conceptsMap = new Map(candidateConcepts.map((concept: any) => [concept.name, concept]));
|
||||||
|
|
||||||
const selectedTools = result.selectedTools
|
const selectedTools = result.selectedTools
|
||||||
.map((name: string) => toolsMap.get(name))
|
.map((name: string) => toolsMap.get(name))
|
||||||
.filter((tool: any): tool is NonNullable<any> => tool !== undefined && tool !== null);
|
.filter((tool: any): tool is NonNullable<any> => tool !== undefined && tool !== null);
|
||||||
|
|
||||||
const selectedConcepts = result.selectedConcepts
|
const selectedConcepts = result.selectedConcepts
|
||||||
.map((name: string) => conceptsMap.get(name))
|
.map((name: string) => conceptsMap.get(name))
|
||||||
.filter((concept: any): concept is NonNullable<any> => concept !== undefined && concept !== null);
|
.filter((concept: any): concept is NonNullable<any> => concept !== undefined && concept !== null);
|
||||||
|
|
||||||
const selectedMethods = selectedTools.filter((t: any) => t && t.type === 'method');
|
const selectedMethods = selectedTools.filter((t: any) => t && t.type === 'method');
|
||||||
const selectedSoftware = selectedTools.filter((t: any) => t && t.type === 'software');
|
const selectedSoftware = selectedTools.filter((t: any) => t && t.type === 'software');
|
||||||
|
|
||||||
console.log('[TOOL-SELECTOR] AI selected:', selectedMethods.length, 'methods,', selectedSoftware.length, 'software,', selectedConcepts.length, 'concepts');
|
console.log('[TOOL-SELECTOR] AI selected:', selectedMethods.length, 'methods,', selectedSoftware.length, 'software,', selectedConcepts.length, 'concepts');
|
||||||
|
|
||||||
const confidence = confidenceScoring.calculateSelectionConfidence(result, candidateTools.length + candidateConcepts.length);
|
const confidence = confidenceScoring.calculateSelectionConfidence(
|
||||||
|
result,
|
||||||
return {
|
candidateTools.length + candidateConcepts.length
|
||||||
selectedTools,
|
);
|
||||||
selectedConcepts,
|
|
||||||
selectionMethod,
|
|
||||||
confidence
|
|
||||||
};
|
|
||||||
|
|
||||||
|
return { selectedTools, selectedConcepts, confidence };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[TOOL-SELECTOR] AI selection failed:', error);
|
console.error('[TOOL-SELECTOR] AI selection failed:', error);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async selectToolsForPhase(
|
async selectToolsForPhase(
|
||||||
userQuery: string,
|
userQuery: string,
|
||||||
phase: any,
|
phase: any,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user