Private/Invoke-AzureAIReview.ps1

function Invoke-AzureAIReview {
    <#
    .SYNOPSIS
    Invoke code review using Azure AI Foundry
     
    .DESCRIPTION
    Calls Azure AI Foundry API (unified model catalog) with retry logic.
     
    .PARAMETER ReviewContext
    Array of file diffs
     
    .PARAMETER Rules
    Review rules markdown
     
    .PARAMETER ApiKey
    Azure AI API key
     
    .PARAMETER Config
    Provider configuration
     
    .PARAMETER MaxTokens
    Maximum output tokens
     
    .OUTPUTS
    System.Array - Array of violations
     
    .NOTES
    Author: waldo
    Version: 1.0.0
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [array]$ReviewContext,
        
        [Parameter(Mandatory = $true)]
        [string]$Rules,
        
        [Parameter(Mandatory = $true)]
        [string]$ApiKey,
        
        [Parameter(Mandatory = $true)]
        [object]$Config,
        
        [Parameter(Mandatory = $false)]
        [int]$MaxTokens = 4000
    )
    
    begin {
        Write-Verbose "Starting $($MyInvocation.MyCommand.Name)"
    }
    
    process {
        try {
            $prompts = Build-ReviewPrompt -Rules $Rules -ReviewContext $ReviewContext
            
            # Construct full URL
            $fullUrl = "$($Config.endpoint)/openai/deployments/$($Config.deployment)/chat/completions?api-version=$($Config.api_version)"
            Write-Verbose "Azure AI endpoint: $fullUrl"
            
            # Estimate tokens
            $estimatedInputTokens = [int](($prompts.SystemPrompt.Length + $prompts.UserPrompt.Length) / 4)
            Write-Host "Estimated input tokens: $estimatedInputTokens"
            
            $headers = @{
                "api-key" = $ApiKey
                "content-type" = "application/json"
            }
            
            $body = @{
                messages = @(
                    @{
                        role = "system"
                        content = $prompts.SystemPrompt
                    },
                    @{
                        role = "user"
                        content = $prompts.UserPrompt
                    }
                )
                max_tokens = $MaxTokens
                temperature = 0.1
            } | ConvertTo-Json -Depth 10
            
            $response = Invoke-RestMethod -Uri $fullUrl `
                -Method Post `
                -Headers $headers `
                -Body $body `
                -TimeoutSec 120
            
            $responseText = $response.choices[0].message.content
            Write-Verbose "Received response: $($responseText.Length) characters"
            
            $violations = Parse-AIResponse -ResponseText $responseText
            
            if ($null -ne $violations) {
                Write-Host "✅ Successfully received $($violations.Count) violation(s)"
                
                # Log actual usage
                if ($response.usage) {
                    Write-Host "Actual tokens: $($response.usage.prompt_tokens) input, $($response.usage.completion_tokens) output"
                    $cost = ($response.usage.prompt_tokens / 1000000) * 2.5 + ($response.usage.completion_tokens / 1000000) * 10.0
                    Write-Host "Estimated cost: `$$([math]::Round($cost, 4))"
                }
            }
            
            return $violations
        }
        catch {
            Write-Error "Error in $($MyInvocation.MyCommand.Name): $_"
            throw
        }
    }
    
    end {
        Write-Verbose "Completed $($MyInvocation.MyCommand.Name)"
    }
}