// ============================================================================ // LangGraph State Management // Defines the graph state channels and initial state // ============================================================================ import { AgentState, SuiteConfig, GeneratedTest, TestReview, TestResult } from '../types'; /** * Creates the initial state for the LangGraph workflow. */ export function createInitialState(projectPath: string, config: SuiteConfig): AgentState { return { projectPath, config, projectStructure: undefined, codeAnalysis: undefined, testStrategy: undefined, generatedTests: [], testReviews: [], testResults: [], securityReport: undefined, report: undefined, currentAgent: 'scanner', agentLog: [], errors: [], status: 'idle', }; } /** * Merges partial state updates into the current state. * LangGraph uses this pattern for state channel updates. */ export function mergeState(current: AgentState, updates: Partial): AgentState { return { ...current, ...updates, // Merge arrays instead of replacing generatedTests: updates.generatedTests ?? current.generatedTests, testReviews: updates.testReviews ?? current.testReviews, testResults: updates.testResults ?? current.testResults, agentLog: updates.agentLog ?? current.agentLog, errors: updates.errors ?? current.errors, }; } /** * State channel definitions for LangGraph. * Each channel defines how state updates are merged. */ export const stateChannels = { projectPath: { value: (a: string, b: string) => b || a, default: () => '' }, config: { value: (a: SuiteConfig, b: SuiteConfig) => b || a }, projectStructure: { value: (a: any, b: any) => b ?? a, default: () => undefined }, codeAnalysis: { value: (a: any, b: any) => b ?? a, default: () => undefined }, testStrategy: { value: (a: any, b: any) => b ?? a, default: () => undefined }, generatedTests: { value: (a: GeneratedTest[], b: GeneratedTest[]) => b.length > 0 ? b : a, default: () => [] as GeneratedTest[], }, testReviews: { value: (a: TestReview[], b: TestReview[]) => b.length > 0 ? b : a, default: () => [] as TestReview[], }, testResults: { value: (a: TestResult[], b: TestResult[]) => b.length > 0 ? b : a, default: () => [] as TestResult[], }, securityReport: { value: (a: any, b: any) => b ?? a, default: () => undefined }, report: { value: (a: any, b: any) => b ?? a, default: () => undefined }, currentAgent: { value: (a: string, b: string) => b || a, default: () => 'scanner' }, agentLog: { value: (a: any[], b: any[]) => [...a, ...(b || [])], default: () => [], }, errors: { value: (a: string[], b: string[]) => [...a, ...(b || [])], default: () => [] as string[], }, status: { value: (a: string, b: string) => b || a, default: () => 'idle' }, };