// engine/detectors/ai-native-detector.ts — SPEC-056
// Detects AI-native vs AI-bolted-on projects, inference mode, orchestration
// frameworks, memory patterns, agentic patterns, and multi-modal inputs.
import { collectDependencies } from '../detection-utils.js';
// --- Dependency maps ---
const AI_DEPS = new Set([
    'openai',
    '@anthropic-ai/sdk',
    'anthropic',
    'langchain',
    'langchain-core',
    '@langchain/core',
    '@langchain/openai',
    'llama-index',
    'llamaindex',
    'llama_index',
    'transformers',
    'huggingface_hub',
    'huggingface-hub',
    '@huggingface/inference',
    'ollama',
    'ollama-ai-provider',
    'litellm',
    'groq',
    'groq-sdk',
    'cohere',
    'cohere-ai',
    'mistralai',
    '@mistralai/mistralai',
    'google-generativeai',
    '@google/generative-ai',
    'ai',
    'dspy-ai',
    'dspy',
    'instructor',
    'haystack-ai',
    'farm-haystack',
]);
const OFFLINE_DEPS = new Set([
    'ollama',
    'ollama-ai-provider',
    'llama-cpp-python',
    'llama-cpp',
    'llama.cpp',
    'ctransformers',
    'gpt4all',
]);
const ONLINE_DEPS = new Set([
    'openai',
    '@anthropic-ai/sdk',
    'anthropic',
    'groq',
    'groq-sdk',
    'cohere',
    'cohere-ai',
    'mistralai',
    '@mistralai/mistralai',
    'google-generativeai',
    '@google/generative-ai',
    'litellm',
]);
const FRAMEWORK_MAP = new Map([
    ['langchain', 'langchain'],
    ['langchain-core', 'langchain'],
    ['@langchain/core', 'langchain'],
    ['@langchain/openai', 'langchain'],
    ['llama-index', 'llamaindex'],
    ['llamaindex', 'llamaindex'],
    ['llama_index', 'llamaindex'],
    ['haystack-ai', 'haystack'],
    ['farm-haystack', 'haystack'],
    ['dspy-ai', 'dspy'],
    ['dspy', 'dspy'],
    ['instructor', 'instructor'],
]);
const VECTOR_DB_DEPS = new Set([
    'pinecone-client',
    '@pinecone-database/pinecone',
    'pinecone',
    'chromadb',
    'chromadb-client',
    'qdrant-client',
    '@qdrant/js-client-rest',
    'weaviate-client',
    'weaviate-ts-client',
    'pgvector',
    'faiss-node',
    'faiss',
]);
const EMBEDDING_DEPS = new Set([
    'sentence-transformers',
    '@xenova/transformers',
    'openai', // embedding API
    'cohere', // embedding API
]);
const SHORT_TERM_MEMORY_DEPS = new Set([
    'redis',
    'ioredis',
    '@upstash/redis',
    'memcached',
]);
const AGENTIC_FRAMEWORK_DEPS = new Set([
    'crewai',
    'autogen',
    'pyautogen',
    'langgraph',
    '@langchain/langgraph',
    'semantic-kernel',
]);
const MULTIMODAL_DEPS = new Set([
    'pillow',
    'pil',
    'soundfile',
    'librosa',
    'pymupdf',
    'pdfplumber',
    'diffusers',
    'open-clip-torch',
    'clip',
    'sharp', // image processing in Node
    'jimp', // image processing in Node
]);
const AI_NATIVE_THRESHOLD = 3;
/**
 * Detect AI-native architecture patterns in a project.
 * Reads dependency manifests from all ecosystems and classifies the project.
 */
export async function detectAiNative(projectPath) {
    const deps = await collectDependencies(projectPath);
    return analyzeAiDeps(deps);
}
/**
 * Pure analysis function that classifies AI deps.
 * Exported for testing without filesystem access.
 */
export function analyzeAiDeps(deps) {
    const aiDeps = findMatchingDeps(deps, AI_DEPS);
    const aiDepCount = aiDeps.length;
    const isAiNative = aiDepCount >= AI_NATIVE_THRESHOLD;
    const isAiBoltedOn = aiDepCount > 0 && aiDepCount < AI_NATIVE_THRESHOLD;
    const inferenceMode = detectInferenceMode(deps);
    const frameworks = detectFrameworks(deps);
    const memoryPatterns = detectMemoryPatterns(deps);
    const agenticPatterns = detectAgenticPatterns(deps);
    const isMultiModal = isAiNative || isAiBoltedOn ? detectMultiModal(deps) : false;
    return {
        isAiNative,
        isAiBoltedOn,
        inferenceMode,
        frameworks,
        memoryPatterns,
        agenticPatterns,
        isMultiModal,
        aiDeps,
    };
}
function findMatchingDeps(deps, targetSet) {
    const matched = [];
    for (const dep of deps) {
        if (targetSet.has(dep.toLowerCase())) {
            matched.push(dep);
        }
    }
    return matched;
}
function detectInferenceMode(deps) {
    const hasOnline = hasAnyDep(deps, ONLINE_DEPS);
    const hasOffline = hasAnyDep(deps, OFFLINE_DEPS);
    if (hasOnline && hasOffline) {
        return 'hybrid';
    }
    if (hasOnline) {
        return 'online';
    }
    if (hasOffline) {
        return 'offline';
    }
    return 'none';
}
function detectFrameworks(deps) {
    const found = new Set();
    for (const dep of deps) {
        const framework = FRAMEWORK_MAP.get(dep.toLowerCase());
        if (framework) {
            found.add(framework);
        }
    }
    return [...found];
}
function detectMemoryPatterns(deps) {
    const patterns = [];
    if (hasAnyDep(deps, SHORT_TERM_MEMORY_DEPS)) {
        patterns.push('short-term');
    }
    if (hasAnyDep(deps, VECTOR_DB_DEPS)) {
        patterns.push('long-term');
    }
    if (hasAnyDep(deps, EMBEDDING_DEPS) && hasAnyDep(deps, VECTOR_DB_DEPS)) {
        patterns.push('semantic');
    }
    return patterns;
}
function detectAgenticPatterns(deps) {
    const patterns = [];
    // Multi-agent frameworks
    if (hasAnyDep(deps, AGENTIC_FRAMEWORK_DEPS)) {
        patterns.push('multi-agent');
    }
    // Tool-use: any AI dep + function calling indicators
    const hasAiDeps = hasAnyDep(deps, AI_DEPS);
    if (hasAiDeps && hasAnyDep(deps, AGENTIC_FRAMEWORK_DEPS)) {
        patterns.push('tool-use');
    }
    // ReAct and plan-execute detected via LangChain/LangGraph
    const hasLangchain = hasAnyDep(deps, new Set(['langchain', 'langchain-core', '@langchain/core', '@langchain/openai']));
    const hasLanggraph = hasAnyDep(deps, new Set(['langgraph', '@langchain/langgraph']));
    if (hasLangchain || hasLanggraph) {
        if (!patterns.includes('react')) {
            patterns.push('react');
        }
        if (hasLanggraph && !patterns.includes('plan-execute')) {
            patterns.push('plan-execute');
        }
    }
    // Chain of Thought via DSPy
    if (hasAnyDep(deps, new Set(['dspy', 'dspy-ai']))) {
        if (!patterns.includes('cot')) {
            patterns.push('cot');
        }
    }
    return patterns;
}
function detectMultiModal(deps) {
    return hasAnyDep(deps, MULTIMODAL_DEPS);
}
function hasAnyDep(deps, targetSet) {
    for (const dep of deps) {
        if (targetSet.has(dep.toLowerCase())) {
            return true;
        }
    }
    return false;
}
//# sourceMappingURL=ai-native-detector.js.map