scai
Version:
> **AI-powered CLI for local code analysis, commit message suggestions, and natural-language queries.** 100% local, private, GDPR-friendly, made in Denmark/EU with ❤️.
105 lines (96 loc) • 3.75 kB
JavaScript
// File: src/modules/contextReviewStep.ts
import { generate } from "../lib/generate.js";
import { logInputOutput } from "../utils/promptLogHelper.js";
export async function contextReviewStep(context) {
if (!context.plan?.targetFiles || context.plan.targetFiles.length === 0) {
throw new Error("[contextReviewStep] No targetFiles defined in plan.");
}
// ------------------------------
// Authoritative view: only target files
// ------------------------------
const authoritativeFiles = (context.workingFiles ?? [])
.filter(f => context.plan.targetFiles.includes(f.path))
.map((f) => ({
path: f.path,
hasCode: Boolean(f.code),
code: f.code ?? null,
summary: f.summary ?? null,
}));
// ------------------------------
// Structural verification: only target files
// ------------------------------
const structuralProof = context.analysis?.structure
? {
fileCount: context.analysis.structure.files.filter(f => context.plan.targetFiles.includes(f.path)).length,
files: context.analysis.structure.files
.filter(f => context.plan.targetFiles.includes(f.path))
.map(f => ({
path: f.path,
hasCode: Boolean(authoritativeFiles.find(af => af.path === f.path)?.code),
})),
}
: null;
// ------------------------------
// Include combined architecture analysis
// ------------------------------
const combinedAnalysis = context.analysis?.combinedAnalysis ?? {};
const architectureSummary = combinedAnalysis.architectureSummary ?? "";
const hotspots = combinedAnalysis.hotspots ?? [];
// ------------------------------
// Build prompt
// ------------------------------
const prompt = `
You are a meta-reasoning agent responsible for determining whether the agent
has sufficient information to proceed.
IMPORTANT CONTRACT:
- Any file listed below with a non-null "code" field MUST be treated as the
complete and authoritative source code for that file.
- Do NOT request file contents again if "code" is present.
User intent:
${JSON.stringify(context.analysis?.intent ?? {}, null, 2)}
Authoritative source files:
${JSON.stringify(authoritativeFiles, null, 2)}
Structural verification:
${JSON.stringify(structuralProof, null, 2)}
Combined architecture analysis:
{
"architectureSummary": ${JSON.stringify(architectureSummary, null, 2)}
}
Your task:
1. Determine whether the available information is sufficient to fulfill the user intent.
2. If NOT sufficient, explicitly list what is missing.
3. Output STRICT JSON with the following shape:
{
"decision": "loopAgain" | "stop",
"reason": "string",
"missing": string[]
}
Rules:
- If the intent involves modifying, commenting, refactoring, or analyzing code,
and at least one relevant file includes full source code, the context SHOULD
be considered sufficient.
- Do NOT request information that is already present in the authoritative files.
`.trim();
// ------------------------------
// Call LLM
// ------------------------------
const ai = await generate({
query: context.initContext?.userQuery ?? '',
content: prompt,
});
const text = typeof ai.data === "string" ? ai.data : JSON.stringify(ai.data);
logInputOutput("contextReviewHelper", "output", text);
// ------------------------------
// Parse JSON or fallback
// ------------------------------
try {
return JSON.parse(text);
}
catch {
return {
decision: text.toLowerCase().includes("loop") ? "loopAgain" : "stop",
reason: text,
missing: [],
};
}
}