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

108 lines (100 loc) 4.46 kB
// File: src/agents/finalPlanGenStep.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'; /** * FINAL PLAN GENERATOR * Generates a single finalization step to wrap up and produce user-facing results. */ export const finalPlanGenStep = { name: 'finalPlanGen', description: 'Generates a single finalization step for the workflow.', requires: ['analysis.intent', 'analysis.focus'], produces: ['analysis.planSuggestion'], async run(context) { context.analysis || (context.analysis = {}); // Clear previous final plan delete context.analysis.planSuggestion; // Restrict actions to FINALIZE only const effectiveActions = PLAN_ACTIONS.filter(a => a.groups?.includes('finalize')); if (!effectiveActions.length) { context.analysis.planSuggestion = { plan: { steps: [] } }; logInputOutput('finalPlanGen', 'output', { steps: [] }); return; } const actionsJson = JSON.stringify(effectiveActions, null, 2); const intentText = context.analysis.intent?.normalizedQuery ?? ''; const intentCategory = context.analysis.intent?.intentCategory ?? ''; const prompt = ` You are an autonomous coding agent. Produce exactly one structured step to finalize the workflow and generate the user-facing output. Intent / task description: ${intentText} Task category: ${intentCategory} Allowed actions (finalize only): ${actionsJson} Rules: - Only produce a single finalize step. - Step must include: "action", "targetFile" (optional), "description", "metadata". - Do NOT invent new actions. - Always ensure a user-facing result is produced. Return strictly valid JSON representing one step: { "action": "stepName", "targetFile": "optional/path.ts", "description": "Generate final user-facing output summarizing results.", "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 ?? '{}'); let step = JSON.parse(jsonString); // Validate structure if (!step || typeof step.action !== 'string') { step = { id: 'finalize', action: 'finalAnswer', description: 'Generate final user-facing response summarizing results.', metadata: {} }; } // Map groups & metadata const actionDef = PLAN_ACTIONS.find(a => a.action === step.action); step.groups = actionDef?.groups ?? ['finalize']; const confidence = context.analysis?.routingDecision?.confidence; step.metadata = { ...step.metadata, ...(typeof confidence === 'number' && confidence > 0 ? { routingConfidence: confidence } : {}) }; // Save single step to context context.analysis.planSuggestion = { plan: { steps: [step] } }; logInputOutput('finalPlanGen', 'output', step); } catch (err) { console.warn('⚠️ Failed to generate final step:', err); // Fallback: always include finalAnswer const confidence = context.analysis?.routingDecision?.confidence; const step = { id: 'finalize', action: 'finalAnswer', description: 'Generate final user-facing response summarizing results.', metadata: { ...(typeof confidence === 'number' && confidence > 0 ? { routingConfidence: confidence } : {}) }, groups: ['finalize'] }; context.analysis.planSuggestion = { plan: { steps: [step] } }; logInputOutput('finalPlanGen', 'output', step); } } };