Private/Invoke-OpenAIReview.ps1

function Invoke-OpenAIReview {
    <#
    .SYNOPSIS
    Invoke code review using OpenAI API (direct)
     
    .DESCRIPTION
    Calls OpenAI API with retry logic.
     
    .PARAMETER ReviewContext
    Array of file diffs
     
    .PARAMETER Rules
    Review rules markdown
     
    .PARAMETER ApiKey
    OpenAI 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
            
            # Estimate tokens
            $estimatedInputTokens = [int](($prompts.SystemPrompt.Length + $prompts.UserPrompt.Length) / 4)
            Write-Host "Estimated input tokens: $estimatedInputTokens"
            
            $headers = @{
                "Authorization" = "Bearer $ApiKey"
                "content-type" = "application/json"
            }
            
            $body = @{
                model = $Config.model
                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 $Config.endpoint `
                -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)"
    }
}