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**

97 lines (90 loc) 3.9 kB
// File: src/agents/infoPlanGenStep.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'; /** * INFO PLAN GENERATOR * Generates a single information-acquisition step. * * NOTE: * - This step only creates a plan; execution happens in the agent loop. * - The agent controls when this step runs. */ export const infoPlanGenStep = { name: 'infoPlanGen', description: 'Generates one information-acquisition step.', requires: ['userQuery', 'analysis.intent'], produces: ['analysis.planSuggestion'], async run(context) { context.analysis || (context.analysis = {}); // Clear any previous plan delete context.analysis.planSuggestion; const analysis = context.analysis; const intentText = analysis.intent?.normalizedQuery ?? ''; const intentCategory = analysis.intent?.intentCategory ?? ''; // Only info-type actions const effectiveActions = PLAN_ACTIONS.filter(a => a.groups?.includes('info')); if (!effectiveActions.length) { context.analysis.planSuggestion = { plan: { steps: [] } }; logInputOutput('infoPlanGen', 'output', []); return; } const actionsJson = JSON.stringify(effectiveActions, null, 2); const prompt = ` You are an autonomous coding agent. Produce exactly ONE structured step to gather additional information needed to satisfy the user's intent. Intent / task description: ${intentText} Task category: ${intentCategory} Allowed actions (info only): ${actionsJson} Rules: - Only produce a single info step. - Step must include: "action", "description", "subQuery" (array), "metadata". - Do NOT invent new actions or files. - Return strictly valid JSON representing one step. If no further information is required, return: { "step": null } `.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 ?? '{}'); // Unwrap the step from LLM output const parsed = JSON.parse(jsonString); let step = parsed?.step ?? null; // Validate minimal structure if (!step || typeof step.action !== 'string') { step = null; } // Attach groups & routing confidence if available if (step) { const actionDef = PLAN_ACTIONS.find(a => a.action === step.action); step.groups = actionDef?.groups ?? ['info']; const confidence = analysis?.routingDecision?.confidence; step.metadata = { ...step.metadata, ...(typeof confidence === 'number' && confidence > 0 ? { routingConfidence: confidence } : {}) }; } // Save as array in planSuggestion context.analysis.planSuggestion = { plan: { steps: step ? [step] : [] } }; logInputOutput('infoPlanGen', 'output', context.analysis.planSuggestion.plan?.steps ?? []); } catch (err) { console.warn('⚠️ Failed to generate info step:', err); context.analysis.planSuggestion = { plan: { steps: [] } }; logInputOutput('infoPlanGen', 'output', []); } } };