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**
115 lines (105 loc) • 4.64 kB
JavaScript
// src/agents/analysisPlanGenStep.ts
import { generate } from "../lib/generate.js";
import { PLAN_ACTIONS } from "../utils/planActions.js";
import { logInputOutput } from "../utils/promptLogHelper.js";
import { cleanupModule } from "../pipeline/modules/cleanupModule.js";
/**
* ANALYSIS PLAN GENERATOR (single-step)
* Generates exactly one analysis reasoning step per iteration.
*/
export const analysisPlanGenStep = {
name: "analysisPlanGen",
description: "Generates a single analysis reasoning step.",
requires: ["analysis.intent", "analysis.focus", "analysis.routingDecision"],
produces: ["analysis.planSuggestion"],
async run(context) {
context.analysis || (context.analysis = {});
context.execution || (context.execution = {});
// Ensure task exists (required for currentStep)
if (!context.task) {
throw new Error("analysisPlanGenStep: context.task must exist — ensure runBoot has been called");
}
// 🔁 Always overwrite previous planSuggestion
delete context.analysis.planSuggestion;
// Use the DB-backed currentStep
const currentStep = context.task.currentStep;
if (!currentStep?.filePath) {
context.analysis.planSuggestion = { plan: { steps: [] } };
logInputOutput("analysisPlanGen", "output", { steps: [] });
return;
}
const targetFile = currentStep.filePath;
// Restrict actions to ANALYSIS only
const effectiveActions = PLAN_ACTIONS.filter(a => a.groups?.includes("analysis"));
if (!effectiveActions.length) {
context.analysis.planSuggestion = { plan: { steps: [] } };
logInputOutput("analysisPlanGen", "output", { steps: [] });
return;
}
const actionsJson = JSON.stringify(effectiveActions, null, 2);
const intentText = context.analysis.intent?.normalizedQuery ?? context.initContext?.userQuery ?? "";
const intentCategory = context.analysis.intent?.intentCategory ?? "";
const relevantFiles = JSON.stringify([targetFile], null, 2);
const rationaleText = context.analysis.focus?.rationale ?? "";
const understandingText = context.analysis.understanding
? JSON.stringify(context.analysis.understanding, null, 2)
: "";
const prompt = `
You are an autonomous coding agent.
Produce **exactly one structured analysis step** that will advance understanding
of the codebase, suitable for safe planning of transformations.
Intent / task description:
${intentText}
Task category:
${intentCategory}
Allowed actions (analysis only):
${actionsJson}
Relevant files:
${relevantFiles}
Rationale / notes from pre-file check:
${rationaleText}
Existing understanding of the codebase:
${understandingText}
If this is NOT a coding, refactoring, or inline commenting task,
return: { "step": null }
Return a valid JSON object in this format:
{
"step": {
"action": "analysisAction",
"targetFile": "optional/path.ts",
"description": "what this analysis step achieves",
"metadata": {}
}
}
`.trim();
try {
const genInput = { query: intentText, content: prompt };
const genOutput = await generate(genInput);
const raw = typeof genOutput.data === "string"
? genOutput.data
: JSON.stringify(genOutput.data ?? "{}");
const cleaned = await cleanupModule.run({ query: intentText, content: raw });
const jsonString = typeof cleaned.content === "string"
? cleaned.content
: JSON.stringify(cleaned.content ?? "{}");
const planObj = JSON.parse(jsonString);
const steps = planObj.step ? [planObj.step] : [];
const finalSteps = steps.map((step) => {
const actionDef = PLAN_ACTIONS.find(a => a.action === step.action);
return {
...step,
groups: actionDef?.groups ?? ["analysis"],
metadata: step.metadata ?? {},
};
});
context.analysis.planSuggestion = { plan: { steps: finalSteps } };
logInputOutput("analysisPlanGen", "output", finalSteps);
console.log("🧠 [analysisPlanGenStep] EXIT (success)");
}
catch (err) {
console.warn("⚠️ [analysisPlanGenStep] FAILED to generate analysis plan:", err);
context.analysis.planSuggestion = { plan: { steps: [] } };
logInputOutput("analysisPlanGen", "output", { steps: [] });
}
}
};