UNPKG

scai

Version:

> **A local-first AI CLI for understanding, querying, and iterating on large codebases.** > **100% local • No token costs • No cloud • No prompt injection • Private by design**

102 lines (89 loc) 3.2 kB
// File: src/modules/contextReviewStep.ts import { generate } from "../lib/generate.js"; import { logInputOutput } from "../utils/promptLogHelper.js"; export async function contextReviewStep(context) { const analysis = context.analysis; if (!analysis) { throw new Error("[contextReviewStep] No analysis state available."); } const intent = analysis.intent ?? { intent: "", intentCategory: "", normalizedQuery: "", confidence: 0, }; const focus = analysis.focus ?? { selectedFiles: [], candidateFiles: [], rationale: "", }; const fileAnalysis = analysis.fileAnalysis ?? {}; const planDecision = analysis.planSuggestion?.plan ? "planExists" : "needsPlan"; // ------------------------------ // Compress file-level analysis to high-signal summaries // ------------------------------ const summarizedFiles = Object.entries(fileAnalysis) .filter(([, fa]) => fa.intent === "relevant") .map(([filePath, fa]) => ({ file: filePath, role: fa.role ?? "unspecified", relevance: fa.relevanceExplanation, proposedChangeScope: fa.proposedChanges?.scope ?? "none", excerptCount: fa.excerpts?.length ?? 0, excerptTopics: fa.excerpts?.map(e => e.description).slice(0, 3), })); // ------------------------------ // Build prompt using distilled conclusions only // ------------------------------ const prompt = ` You are a meta-reasoning agent. Your job is to determine whether enough relevant information has been collected to directly answer the user's intent, or whether more data must be gathered first. Decision meanings: - "executeOnQuery": The collected analysis and files are sufficient to answer the user's question. - "gatherData": The current analysis is insufficient; more files or analysis are required. User Intent: ${JSON.stringify(intent, null, 2)} Plan Suggestion Status: ${planDecision} Relevant Files (paths only): ${JSON.stringify(focus.selectedFiles, null, 2)} Missing Files: ${JSON.stringify(focus.candidateFiles, null, 2)} Why these files were selected: ${focus.rationale ?? "No rationale provided."} Relevant File Summaries (high-signal only): ${JSON.stringify(summarizedFiles, null, 2)} Question: Based on the above, is there enough information to answer the user's question directly? Output STRICT JSON with shape: { "decision": "gatherData" | "executeOnQuery", "reason": "concise explanation", "missing": string[] } `.trim(); const ai = await generate({ query: context.initContext?.userQuery ?? "", content: prompt, }); const text = typeof ai.data === "string" ? ai.data : JSON.stringify(ai.data); logInputOutput("contextReviewStep", "output", text); // ------------------------------ // Parse JSON or fallback // ------------------------------ try { return JSON.parse(text); } catch { return { decision: text.toLowerCase().includes("gather") ? "gatherData" : "executeOnQuery", reason: text, missing: [], }; } }