Private/Invoke-AISecurityAnalysis.ps1

function Invoke-AISecurityAnalysis {
    <#
    .SYNOPSIS
    Perform AI analysis on Conditional Access policies with multiple specialist agents
     
    .DESCRIPTION
    Uses multiple specialist AI agents to analyze policies, find gaps, provide recommendations,
    and analyze per-policy improvements. Logs all results in separate files.
    Supports chunking for large policy sets to avoid rate limits.
    #>

    
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [array]$Policies,
        
        [Parameter(Mandatory = $true)]
        [PSCustomObject]$AIConfig,
        
        [Parameter(Mandatory = $false)]
        [string]$StoragePath,
        
        [Parameter(Mandatory = $false)]
        [int]$ChunkSize = 10
    )
    
    # Helper function to split policies into chunks
    function Split-PoliciesIntoChunks {
        param(
            [array]$Policies,
            [int]$ChunkSize
        )
        $chunks = @()
        for ($i = 0; $i -lt $Policies.Count; $i += $ChunkSize) {
            $chunk = $Policies[$i..([Math]::Min($i + $ChunkSize - 1, $Policies.Count - 1))]
            $chunks += ,$chunk
        }
        return $chunks
    }
    
    # Track if chunking was used (use script scope for nested function access)
    $script:usedChunking = $false
    
    # Helper function to call AI with chunking support and smart rate limit handling
    function Invoke-AIWithChunking {
        param(
            [string]$PromptTemplate,
            [array]$Policies,
            [PSCustomObject]$AIConfig,
            [string]$AgentName,
            [int]$ChunkSize = 10,
            [int]$MaxRetries = 3
        )
        
        $allResults = @()
        $chunks = Split-PoliciesIntoChunks -Policies $Policies -ChunkSize $ChunkSize
        
        if ($chunks.Count -eq 1) {
            # Single chunk - no need for chunking
            $policiesJson = ($Policies | ForEach-Object {
                @{
                    Name = $_.displayName
                    State = $_.state
                    Id = $_.id
                    Users = if ($_.conditions.users) { 
                        @{
                            Include = $_.conditions.users.includeUsers
                            Exclude = $_.conditions.users.excludeUsers
                            IncludeGroups = $_.conditions.users.includeGroups
                            ExcludeGroups = $_.conditions.users.excludeGroups
                        }
                    } else { $null }
                    Applications = if ($_.conditions.applications) {
                        @{
                            Include = $_.conditions.applications.includeApplications
                            Exclude = $_.conditions.applications.excludeApplications
                        }
                    } else { $null }
                    GrantControls = if ($_.grantControls) {
                        $_.grantControls.builtInControls
                    } else { $null }
                }
            }) | ConvertTo-Json -Depth 10
            
            $prompt = $PromptTemplate -replace '\$policiesJson', $policiesJson
            $response = Invoke-OpenAICall -Prompt $prompt -AIConfig $AIConfig
            if ($response) {
                return $response
            }
            return $null
        }
        else {
            # Multiple chunks - process with smart queue and rate limit handling
            $script:usedChunking = $true
            Write-Host " Processing $($chunks.Count) chunks (${ChunkSize} policies each) to avoid rate limits..." -ForegroundColor Gray
            $chunkResults = @()
            $failedChunks = @()
            
            # Process chunks with smart delays and retry logic
            for ($i = 0; $i -lt $chunks.Count; $i++) {
                $chunk = $chunks[$i]
                $chunkSuccess = $false
                $chunkAttempts = 0
                $maxChunkAttempts = 3
                
                while (-not $chunkSuccess -and $chunkAttempts -lt $maxChunkAttempts) {
                    $chunkAttempts++
                    Write-Host " Chunk $($i + 1)/$($chunks.Count) ($($chunk.Count) policies) - Attempt $chunkAttempts/$maxChunkAttempts..." -ForegroundColor DarkGray
                    
                    $chunkPoliciesJson = ($chunk | ForEach-Object {
                        @{
                            Name = $_.displayName
                            State = $_.state
                            Id = $_.id
                            Users = if ($_.conditions.users) { 
                                @{
                                    Include = $_.conditions.users.includeUsers
                                    Exclude = $_.conditions.users.excludeUsers
                                    IncludeGroups = $_.conditions.users.includeGroups
                                    ExcludeGroups = $_.conditions.users.excludeGroups
                                }
                            } else { $null }
                            Applications = if ($_.conditions.applications) {
                                @{
                                    Include = $_.conditions.applications.includeApplications
                                    Exclude = $_.conditions.applications.excludeApplications
                                }
                            } else { $null }
                            GrantControls = if ($_.grantControls) {
                                $_.grantControls.builtInControls
                            } else { $null }
                        }
                    }) | ConvertTo-Json -Depth 10
                    
                    $chunkPrompt = $PromptTemplate -replace '\$policiesJson', $chunkPoliciesJson
                    
                    # Use longer delays and more retries for chunk processing
                    $chunkResponse = Invoke-OpenAICall -Prompt $chunkPrompt -AIConfig $AIConfig -MaxRetries 8 -BaseDelaySeconds 5
                    
                    if ($chunkResponse) {
                        $chunkResults += @{
                            ChunkNumber = $i + 1
                            TotalChunks = $chunks.Count
                            PoliciesInChunk = $chunk.Count
                            Analysis = $chunkResponse
                        }
                        $chunkSuccess = $true
                        Write-Host " Chunk $($i + 1) completed successfully" -ForegroundColor Green
                    }
                    else {
                        if ($chunkAttempts -lt $maxChunkAttempts) {
                            # Exponential backoff: 15, 30, 60 seconds
                            $backoffDelay = 15 * [Math]::Pow(2, $chunkAttempts - 1)
                            Write-Host " Chunk $($i + 1) failed, waiting $backoffDelay seconds before retry..." -ForegroundColor Yellow
                            Start-Sleep -Seconds $backoffDelay
                        }
                        else {
                            Write-Host " Chunk $($i + 1) failed after $maxChunkAttempts attempts, will retry later" -ForegroundColor Red
                            $failedChunks += @{
                                Index = $i
                                Chunk = $chunk
                                Attempts = $chunkAttempts
                            }
                        }
                    }
                }
                
                # Smart delay between chunks: longer delays as we progress
                if ($i -lt $chunks.Count - 1) {
                    # Base delay increases with chunk number to prevent rate limits
                    $baseDelay = 10
                    $progressiveDelay = [Math]::Min($baseDelay + ($i * 2), 30)
                    Write-Host " Waiting $progressiveDelay seconds before next chunk..." -ForegroundColor DarkGray
                    Start-Sleep -Seconds $progressiveDelay
                }
            }
            
            # Retry failed chunks with longer delays
            if ($failedChunks.Count -gt 0) {
                Write-Host " Retrying $($failedChunks.Count) failed chunk(s) with extended delays..." -ForegroundColor Yellow
                Start-Sleep -Seconds 60  # Wait 1 minute before retrying failed chunks
                
                foreach ($failedChunk in $failedChunks) {
                    $i = $failedChunk.Index
                    $chunk = $failedChunk.Chunk
                    Write-Host " Retrying Chunk $($i + 1)/$($chunks.Count) ($($chunk.Count) policies)..." -ForegroundColor Yellow
                    
                    $chunkPoliciesJson = ($chunk | ForEach-Object {
                        @{
                            Name = $_.displayName
                            State = $_.state
                            Id = $_.id
                            Users = if ($_.conditions.users) { 
                                @{
                                    Include = $_.conditions.users.includeUsers
                                    Exclude = $_.conditions.users.excludeUsers
                                    IncludeGroups = $_.conditions.users.includeGroups
                                    ExcludeGroups = $_.conditions.users.excludeGroups
                                }
                            } else { $null }
                            Applications = if ($_.conditions.applications) {
                                @{
                                    Include = $_.conditions.applications.includeApplications
                                    Exclude = $_.conditions.applications.excludeApplications
                                }
                            } else { $null }
                            GrantControls = if ($_.grantControls) {
                                $_.grantControls.builtInControls
                            } else { $null }
                        }
                    }) | ConvertTo-Json -Depth 10
                    
                    $chunkPrompt = $PromptTemplate -replace '\$policiesJson', $chunkPoliciesJson
                    $chunkResponse = Invoke-OpenAICall -Prompt $chunkPrompt -AIConfig $AIConfig -MaxRetries 10 -BaseDelaySeconds 10
                    
                    if ($chunkResponse) {
                        $chunkResults += @{
                            ChunkNumber = $i + 1
                            TotalChunks = $chunks.Count
                            PoliciesInChunk = $chunk.Count
                            Analysis = $chunkResponse
                            Retried = $true
                        }
                        Write-Host " Chunk $($i + 1) retry successful" -ForegroundColor Green
                    }
                    else {
                        Write-Host " Chunk $($i + 1) retry failed - will continue without this chunk" -ForegroundColor Red
                    }
                    
                    Start-Sleep -Seconds 20  # Delay between retry attempts
                }
            }
            
            # Bundle all chunk results
            if ($chunkResults.Count -gt 0) {
                Write-Host " Bundling results from $($chunkResults.Count)/$($chunks.Count) successful chunks..." -ForegroundColor Gray
                $bundlePrompt = @"
You are a Bundling Specialist for the Baseline Secure Cloud.
 
You have received analysis results from multiple chunks of Conditional Access policies.
Combine and consolidate these results into a single comprehensive analysis.
 
Chunk Results:
$($chunkResults | ConvertTo-Json -Depth 10)
 
Your task:
1. Combine all identified gaps from all chunks (remove duplicates, prioritize critical ones)
2. Consolidate recommendations (merge similar ones, prioritize by impact)
3. Create a unified assessment that covers all policies
4. Ensure no information is lost in the consolidation
5. Maintain the structure and quality of the original analyses
6. Note: Some chunks may have failed, work with available data
 
Return the consolidated result in the same format as the original analysis.
"@

                
                $bundledResponse = Invoke-OpenAICall -Prompt $bundlePrompt -AIConfig $AIConfig -MaxRetries 8 -BaseDelaySeconds 5
                return $bundledResponse
            }
            else {
                Write-Warning "All chunks failed. Cannot bundle results."
                return $null
            }
        }
    }
    
    try {
        # Create logs directory
        $timestamp = Get-Date -Format "yyyyMMdd-HHmmss"
        $logsPath = $null
        if ($StoragePath) {
            $logsPath = Join-Path $StoragePath "SecurityAnalysis"
            if (-not (Test-Path $logsPath)) {
                New-Item -Path $logsPath -ItemType Directory -Force | Out-Null
            }
            $logsPath = Join-Path $logsPath $timestamp
            New-Item -Path $logsPath -ItemType Directory -Force | Out-Null
        }
        
        # Prepare detailed policy summary for AI analysis
        $policySummary = @()
        foreach ($policy in $Policies) {
            $summary = @{
                Name = $policy.displayName
                State = $policy.state
                Id = $policy.id
                Users = if ($policy.conditions.users) { 
                    @{
                        Include = $policy.conditions.users.includeUsers
                        Exclude = $policy.conditions.users.excludeUsers
                        IncludeGroups = $policy.conditions.users.includeGroups
                        ExcludeGroups = $policy.conditions.users.excludeGroups
                        IncludeGuests = $policy.conditions.users.includeGuestsOrExternalUsers
                        ExcludeGuests = $policy.conditions.users.excludeGuestsOrExternalUsers
                    }
                } else { $null }
                Applications = if ($policy.conditions.applications) {
                    @{
                        Include = $policy.conditions.applications.includeApplications
                        Exclude = $policy.conditions.applications.excludeApplications
                    }
                } else { $null }
                Locations = if ($policy.conditions.locations) {
                    @{
                        Include = $policy.conditions.locations.includeLocations
                        Exclude = $policy.conditions.locations.excludeLocations
                    }
                } else { $null }
                Platforms = if ($policy.conditions.platforms) {
                    @{
                        Include = $policy.conditions.platforms.includePlatforms
                        Exclude = $policy.conditions.platforms.excludePlatforms
                    }
                } else { $null }
                ClientAppTypes = $policy.conditions.clientAppTypes
                UserRiskLevels = $policy.conditions.userRiskLevels
                SignInRiskLevels = $policy.conditions.signInRiskLevels
                GrantControls = if ($policy.grantControls) {
                    @{
                        Operator = $policy.grantControls.operator
                        BuiltInControls = $policy.grantControls.builtInControls
                        AuthenticationStrength = $policy.grantControls.authenticationStrength
                    }
                } else { $null }
                SessionControls = if ($policy.sessionControls) { $policy.sessionControls } else { $null }
            }
            $policySummary += $summary
        }
        
        $policiesJson = $policySummary | ConvertTo-Json -Depth 10
        
        # Load baseline policies for coverage analysis
        $baselinePolicies = @()
        $moduleRoot = Split-Path -Parent (Split-Path -Parent $PSScriptRoot)
        $baselinePath = Join-Path $moduleRoot "Baseline"
        if (Test-Path $baselinePath) {
            $baselineFiles = Get-ChildItem -Path $baselinePath -Filter "*.json" -File -ErrorAction SilentlyContinue
            foreach ($file in $baselineFiles) {
                try {
                    $baseline = Get-Content $file.FullName | ConvertFrom-Json
                    $baselinePolicies += @{
                        Name = $baseline.displayName
                        FileName = $file.Name
                    }
                }
                catch {
                    # Skip invalid files
                }
            }
        }
        
        $baselineJson = $baselinePolicies | ConvertTo-Json -Depth 5
        
        # Initialize comprehensive results
        $results = @{
            AnalysisDate = (Get-Date).ToString("o")
            TotalPolicies = $Policies.Count
            AgentResults = @{}
            PolicyAnalysis = @()
            BaselineCoverage = @{}
            OverallGaps = @()
            OverallRecommendations = @()
            OverallAssessment = ""
            RiskScore = 0
            QualityScore = 0
            UsedChunking = $false
        }
        
        # Add delay between agents to prevent rate limiting (longer delays for better rate limit handling)
        $agentDelay = 5
        
        # Agent 1: Gap Analysis Specialist
        Write-Host " Agent 1: Gap Analysis Specialist..." -ForegroundColor Cyan
        Start-Sleep -Seconds $agentDelay
        $gapPromptTemplate = @"
You are a Gap Analysis Specialist for the Baseline Secure Cloud.
 
Analyze these Conditional Access policies and identify SECURITY GAPS:
 
$policiesJson
 
Focus on identifying:
- Missing MFA requirements for critical users/groups/applications
- Missing device compliance requirements
- Missing risk-based policies (user risk, sign-in risk)
- Missing session controls (sign-in frequency, persistent browser, etc.)
- Missing guest user restrictions
- Missing location-based restrictions
- Missing platform restrictions
- Missing application-specific protections
- Policies that are disabled when they should be enabled
- Missing break-glass exclusions
 
For each gap, provide:
1. The specific gap description
2. Why it's a security concern
3. Which user groups/applications are affected
 
Return as a structured list, one gap per line with clear description.
"@

        
        $gapResponse = Invoke-AIWithChunking -PromptTemplate $gapPromptTemplate -Policies $Policies -AIConfig $AIConfig -AgentName "Gap Analysis" -ChunkSize $ChunkSize
        $gaps = @()
        if ($gapResponse) {
            $gaps = ($gapResponse -split "`n" | Where-Object { $_.Trim() -ne "" }) | ForEach-Object { $_.Trim() }
        }
        $results.OverallGaps = $gaps
        $results.AgentResults.GapAnalysis = $gaps
        
        if ($logsPath) {
            $gapLog = Join-Path $logsPath "01-GapAnalysis.json"
            @{
                Agent = "Gap Analysis Specialist"
                Timestamp = (Get-Date).ToString("o")
                Gaps = $gaps
                RawResponse = $gapResponse
            } | ConvertTo-Json -Depth 10 | Out-File -FilePath $gapLog -Encoding UTF8
        }
        
        # Agent 2: Policy Compliance Specialist
        Write-Host " Agent 2: Policy Compliance Specialist..." -ForegroundColor Cyan
        Start-Sleep -Seconds $agentDelay
        $compliancePromptTemplate = @"
You are a Policy Compliance Specialist for the Baseline Secure Cloud.
 
Analyze these Conditional Access policies for compliance with security best practices:
 
$policiesJson
 
Evaluate each policy for:
- Compliance with Security Baseline requirements
- Microsoft security best practices
- Zero Trust principles
- NIST Cybersecurity Framework alignment
- GDPR compliance considerations
 
For each policy, identify:
1. Compliance status (Compliant / Partially Compliant / Non-Compliant)
2. Specific compliance issues
3. Required improvements to achieve compliance
 
Return a structured assessment per policy.
"@

        
        $complianceResponse = Invoke-AIWithChunking -PromptTemplate $compliancePromptTemplate -Policies $Policies -AIConfig $AIConfig -AgentName "Policy Compliance" -ChunkSize $ChunkSize
        $results.AgentResults.PolicyCompliance = $complianceResponse
        
        if ($logsPath) {
            $complianceLog = Join-Path $logsPath "02-PolicyCompliance.json"
            @{
                Agent = "Policy Compliance Specialist"
                Timestamp = (Get-Date).ToString("o")
                Assessment = $complianceResponse
            } | ConvertTo-Json -Depth 10 | Out-File -FilePath $complianceLog -Encoding UTF8
        }
        
        # Agent 3: Baseline Coverage Specialist
        Write-Host " Agent 3: Baseline Coverage Specialist..." -ForegroundColor Cyan
        Start-Sleep -Seconds $agentDelay
        # Baseline coverage doesn't need chunking as it compares against all baselines
        $coveragePrompt = @"
You are a Baseline Coverage Specialist for the Baseline Secure Cloud.
 
Available baseline policies:
$baselineJson
 
Current deployed policies:
$policiesJson
 
Analyze which baseline policies are MISSING from the current deployment. For each missing baseline:
1. Identify the baseline policy code and name
2. Explain what security control it provides
3. Assess the risk of not having this policy
4. Recommend priority for implementation (High/Medium/Low)
 
Also identify:
- Which baseline policies are partially implemented
- Which baseline policies are fully implemented
- Coverage percentage
 
Return structured analysis.
"@

        
        $coverageResponse = Invoke-OpenAICall -Prompt $coveragePrompt -AIConfig $AIConfig
        $results.AgentResults.BaselineCoverage = $coverageResponse
        
        if ($logsPath) {
            $coverageLog = Join-Path $logsPath "03-BaselineCoverage.json"
            @{
                Agent = "Baseline Coverage Specialist"
                Timestamp = (Get-Date).ToString("o")
                Analysis = $coverageResponse
                AvailableBaselines = $baselinePolicies.Count
            } | ConvertTo-Json -Depth 10 | Out-File -FilePath $coverageLog -Encoding UTF8
        }
        
        # Agent 4: Security Best Practices Specialist
        Write-Host " Agent 4: Security Best Practices Specialist..." -ForegroundColor Cyan
        Start-Sleep -Seconds $agentDelay
        $bestPracticesPromptTemplate = @"
You are a Security Best Practices Specialist for the Baseline Secure Cloud.
 
Analyze these Conditional Access policies for security best practices:
 
$policiesJson
 
Provide specific recommendations for:
- Implementing Zero Trust principles
- Defense in depth strategies
- Least privilege access
- Continuous monitoring and evaluation
- Incident response readiness
- User experience optimization while maintaining security
- Automation opportunities
 
For each recommendation, provide:
1. The specific improvement
2. Why it's important
3. Implementation priority
4. Expected security benefit
 
Return structured recommendations.
"@

        
        $bestPracticesResponse = Invoke-AIWithChunking -PromptTemplate $bestPracticesPromptTemplate -Policies $Policies -AIConfig $AIConfig -AgentName "Security Best Practices" -ChunkSize $ChunkSize
        $results.AgentResults.SecurityBestPractices = $bestPracticesResponse
        
        if ($logsPath) {
            $bestPracticesLog = Join-Path $logsPath "04-SecurityBestPractices.json"
            @{
                Agent = "Security Best Practices Specialist"
                Timestamp = (Get-Date).ToString("o")
                Recommendations = $bestPracticesResponse
            } | ConvertTo-Json -Depth 10 | Out-File -FilePath $bestPracticesLog -Encoding UTF8
        }
        
        # Agent 5: Risk Assessment Specialist
        Write-Host " Agent 5: Risk Assessment Specialist..." -ForegroundColor Cyan
        Start-Sleep -Seconds $agentDelay
        $riskPromptTemplate = @"
You are a Risk Assessment Specialist for the Baseline Secure Cloud.
 
Analyze these Conditional Access policies for security risks:
 
$policiesJson
 
Assess:
- Overall risk score (0-100, where 0 is no risk, 100 is critical risk)
- High-risk areas that need immediate attention
- Medium-risk areas for improvement
- Low-risk areas that are acceptable
- Attack surface exposure
- Potential attack vectors
- Business impact of security gaps
 
Provide:
1. Overall risk score with justification
2. Top 5 highest risk areas
3. Risk mitigation priorities
4. Timeline recommendations for addressing risks
 
Return structured risk assessment.
"@

        
        $riskResponse = Invoke-AIWithChunking -PromptTemplate $riskPromptTemplate -Policies $Policies -AIConfig $AIConfig -AgentName "Risk Assessment" -ChunkSize $ChunkSize
        $results.AgentResults.RiskAssessment = $riskResponse
        
        # Extract risk score if mentioned
        if ($riskResponse -match "(?i)(?:risk\s*score|score)[:\s]*(\d+)") {
            $results.RiskScore = [int]$matches[1]
        }
        
        if ($logsPath) {
            $riskLog = Join-Path $logsPath "05-RiskAssessment.json"
            @{
                Agent = "Risk Assessment Specialist"
                Timestamp = (Get-Date).ToString("o")
                Assessment = $riskResponse
                RiskScore = $results.RiskScore
            } | ConvertTo-Json -Depth 10 | Out-File -FilePath $riskLog -Encoding UTF8
        }
        
        # Per-Policy Analysis
        Write-Host " Analyzing individual policies..." -ForegroundColor Cyan
        $policyAnalysis = @()
        $policyCount = 0
        foreach ($policy in $Policies) {
            $policyCount++
            # Add delay between policy analyses to prevent rate limiting (longer for better handling)
            if ($policyCount -gt 1) {
                Start-Sleep -Seconds ($agentDelay * 2)
            }
            $policyJson = $policy | ConvertTo-Json -Depth 10
            $policyPrompt = @"
You are analyzing a single Conditional Access policy for the Baseline Secure Cloud.
 
Policy details:
$policyJson
 
For this specific policy, provide:
1. Policy strengths (what it does well)
2. Security gaps specific to this policy
3. Recommended improvements
4. Compliance status with Security Baseline
5. Priority for improvement (High/Medium/Low)
 
Be specific and actionable.
"@

            
            $policyResponse = Invoke-OpenAICall -Prompt $policyPrompt -AIConfig $AIConfig
            $policyAnalysis += @{
                PolicyName = $policy.displayName
                PolicyId = $policy.id
                State = $policy.state
                Analysis = $policyResponse
                AnalysisDate = (Get-Date).ToString("o")
            }
            
            if ($logsPath) {
                $policyLogName = ($policy.displayName -replace '[^\w\s-]', '' -replace '\s+', '_') + ".json"
                $policyLog = Join-Path $logsPath "Policy-$policyLogName"
                $policyAnalysis[-1] | ConvertTo-Json -Depth 10 | Out-File -FilePath $policyLog -Encoding UTF8
            }
        }
        $results.PolicyAnalysis = $policyAnalysis
        
        # Agent 6: Overall Assessment and Recommendations
        Write-Host " Agent 6: Overall Assessment..." -ForegroundColor Cyan
        Start-Sleep -Seconds $agentDelay
        $assessmentPromptTemplate = @"
You are a Senior Security Architect for the Baseline Secure Cloud.
 
Based on the analysis of these Conditional Access policies:
 
$policiesJson
 
Provide a comprehensive overall assessment (max 300 words) covering:
- Overall security posture summary
- Key strengths
- Critical weaknesses
- Compliance status with Security Baseline
- Top 5 priority actions
- Long-term security strategy recommendations
 
Be concise but comprehensive.
"@

        
        $assessmentResponse = Invoke-AIWithChunking -PromptTemplate $assessmentPromptTemplate -Policies $Policies -AIConfig $AIConfig -AgentName "Overall Assessment" -ChunkSize $ChunkSize
        $results.OverallAssessment = if ($assessmentResponse) { $assessmentResponse.Trim() } else { "" }
        
        # Extract overall recommendations
        $recommendationsPrompt = @"
Based on this security analysis, provide the top 10 actionable recommendations in priority order.
Each recommendation should be one line, specific and actionable.
"@

        
        $recommendationsResponse = Invoke-OpenAICall -Prompt $recommendationsPrompt -AIConfig $AIConfig
        if ($recommendationsResponse) {
            $results.OverallRecommendations = ($recommendationsResponse -split "`n" | Where-Object { $_.Trim() -ne "" }) | ForEach-Object { $_.Trim() }
        }
        
        # Agent 7: Reviewer Agent - Validates and improves all results
        Write-Host " Agent 7: Reviewer Agent (Validating and improving results)..." -ForegroundColor Cyan
        Start-Sleep -Seconds $agentDelay
        
        $reviewerPrompt = @"
You are a Senior Security Reviewer for the Baseline Secure Cloud.
 
Review and validate the following security analysis results. Your task is to:
1. Validate the accuracy and completeness of all findings
2. Identify any missing critical security gaps
3. Improve the quality and clarity of recommendations
4. Ensure consistency across all agent analyses
5. Verify compliance assessments are accurate
6. Enhance the overall assessment with additional insights
7. Prioritize recommendations based on risk and impact
 
Analysis Results to Review:
- Gap Analysis: $($results.OverallGaps -join '; ')
- Policy Compliance: $($results.AgentResults.PolicyCompliance)
- Baseline Coverage: $($results.AgentResults.BaselineCoverage)
- Security Best Practices: $($results.AgentResults.SecurityBestPractices)
- Risk Assessment: $($results.AgentResults.RiskAssessment)
- Overall Assessment: $($results.OverallAssessment)
- Recommendations: $($results.OverallRecommendations -join '; ')
 
Provide:
1. Validated and improved gap list (add any missing critical gaps)
2. Enhanced recommendations (improve clarity, add missing ones, prioritize)
3. Improved overall assessment (more comprehensive, actionable)
4. Quality score (1-10) for the analysis
5. Any corrections or improvements needed
 
Return structured review results.
"@

        
        $reviewerResponse = Invoke-OpenAICall -Prompt $reviewerPrompt -AIConfig $AIConfig
        $results.AgentResults.Reviewer = $reviewerResponse
        
        # Extract improvements from reviewer
        if ($reviewerResponse) {
            # Try to extract improved gaps (using multiline regex with [\s\S] instead of .)
            if ($reviewerResponse -match "(?smi)(?:improved gaps|validated gaps|gaps:)(.*?)(?:\n\n|\nRecommendations|$)" -or 
                $reviewerResponse -match "(?smi)(?:gap.*?:)(.*?)(?:\n\n|Recommendations|$)") {
                $improvedGaps = ($matches[1] -split "`n" | Where-Object { $_.Trim() -ne "" -and $_.Trim() -notmatch "^\d+\.\s*$" }) | ForEach-Object { $_.Trim() }
                if ($improvedGaps.Count -gt 0) {
                    $results.OverallGaps = $improvedGaps
                }
            }
            
            # Try to extract improved recommendations
            if ($reviewerResponse -match "(?smi)(?:recommendations|improved recommendations):(.*?)(?:\n\n|Assessment|$)") {
                $improvedRecs = ($matches[1] -split "`n" | Where-Object { $_.Trim() -ne "" -and $_.Trim() -notmatch "^\d+\.\s*$" }) | ForEach-Object { $_.Trim() }
                if ($improvedRecs.Count -gt 0) {
                    $results.OverallRecommendations = $improvedRecs
                }
            }
            
            # Try to extract improved assessment
            if ($reviewerResponse -match "(?smi)(?:improved assessment|enhanced assessment|assessment):(.*?)(?:\n\n|Quality|$)") {
                $improvedAssessment = $matches[1].Trim()
                if ($improvedAssessment) {
                    $results.OverallAssessment = $improvedAssessment
                }
            }
            
            # Extract quality score
            if ($reviewerResponse -match "(?i)(?:quality score|score)[:\s]*(\d+)") {
                $results.QualityScore = [int]$matches[1]
            }
        }
        
        if ($logsPath) {
            $assessmentLog = Join-Path $logsPath "06-OverallAssessment.json"
            @{
                Agent = "Overall Assessment"
                Timestamp = (Get-Date).ToString("o")
                Assessment = $results.OverallAssessment
                Recommendations = $results.OverallRecommendations
            } | ConvertTo-Json -Depth 10 | Out-File -FilePath $assessmentLog -Encoding UTF8
            
            # Save reviewer results
            $reviewerLog = Join-Path $logsPath "07-ReviewerValidation.json"
            @{
                Agent = "Reviewer Agent"
                Timestamp = (Get-Date).ToString("o")
                Review = $reviewerResponse
                QualityScore = $results.QualityScore
            } | ConvertTo-Json -Depth 10 | Out-File -FilePath $reviewerLog -Encoding UTF8
            
            # Save complete summary
            $summaryLog = Join-Path $logsPath "00-CompleteAnalysis.json"
            $results | ConvertTo-Json -Depth 10 | Out-File -FilePath $summaryLog -Encoding UTF8
        }
        
        # Mark if chunking was used
        $results.UsedChunking = $script:usedChunking
        
        # Backward compatibility - keep old structure
        $results.Gaps = $results.OverallGaps
        $results.Recommendations = $results.OverallRecommendations
        $results.Assessment = $results.OverallAssessment
        
        return $results
    }
    catch {
        Write-Error "Error in AI analysis: $_"
        return @{
            Gaps = @("Error analyzing: $_")
            Recommendations = @()
            Assessment = "Analysis failed"
            AnalysisDate = (Get-Date).ToString("o")
            AgentResults = @{}
            PolicyAnalysis = @()
        }
    }
}