import { askOpenAI } from "./llm.js"; import { curateText } from "./curation.js"; import { queryCollectionDataEnhanced, queryCollectionData } from "./vector.js"; import { loadContextTreeDocuments } from "../utils.js"; export async function routeUserInput(input, config) { try { const intent = await classifyIntent(input, config); switch (intent.type) { case "search": return await handleSearch(input, intent, config); case "curate": return await handleCurate(input, intent, config); case "add": return await handleAdd(input, intent, config); case "list": return await handleList(input, intent, config); default: return { error: "Could not determine intent", input, intent: intent.type, }; } } catch (error) { return { error: `Routing failed: ${error.message}`, input, }; } } async function classifyIntent(input, config) { const prompt = `Analyze this user input and classify the intent. Return ONLY valid JSON: Input: "${input}" Classify as one of these intents: - "search": User is asking questions to find knowledge - "curate": User is teaching/storing new knowledge - "add": User is adding documents to the knowledge base - "list": User wants to see all stored knowledge Response format (valid JSON only): { "type": "search|curate|add|list", "confidence": 0.0-1.0, "reasoning": "brief explanation", "hints": { "enhanced": false, "rerank": false, "extractText": null } }`; try { const response = await askOpenAI(input, prompt); const parsed = JSON.parse(response); return parsed; } catch (error) { console.error("Intent classification failed:", error.message); return { type: "search", confidence: 0.5, reasoning: "Fallback to search" }; } } async function handleSearch(input, intent, config) { try { const searchParams = { query: input, nResults: 5, enhanced: intent.hints?.enhanced || false, rerank: intent.hints?.rerank || false, }; const results = searchParams.enhanced ? await queryCollectionDataEnhanced(searchParams) : await queryCollectionData(searchParams); const documents = results.ids?.[0] || []; const contents = results.documents?.[0] || []; const metadatas = results.metadatas?.[0] || []; if (documents.length === 0) { return { intent: "search", query: input, answer: "No matching knowledge found. Please curate relevant documentation first.", }; } const answer = contents .map((content, idx) => { const meta = metadatas[idx] || {}; return `**${meta.title || documents[idx]}** (${meta.topic || "general"})\n${content}`; }) .join("\n\n---\n\n"); return { intent: "search", query: input, answer, }; } catch (error) { return { intent: "search", error: `Search failed: ${error.message}`, query: input, }; } } async function handleCurate(input, intent, config) { try { const textToCurate = intent.hints?.extractText || input; const result = await curateText(textToCurate, config); return { intent: "curate", action: "extracted_and_stored", result, }; } catch (error) { return { intent: "curate", error: `Curation failed: ${error.message}`, input, }; } } async function handleAdd(input, intent, config) { return { intent: "add", message: "To add documents, use the add_documents tool with an array of {id, text, metadata}", guidance: input, }; } async function handleList(input, intent, config) { try { const dataDir = process.env.DATA_DIR || "/data"; const docs = await loadContextTreeDocuments(dataDir); return { intent: "list", count: docs.length, documents: docs.map((d) => ({ id: d.id, title: d.title, topic: d.topic, type: d.type, importance: d.importance, filePath: d.filePath, })), }; } catch (error) { return { intent: "list", error: `List failed: ${error.message}`, }; } }