Private/Invoke-AICompletion.ps1

function Invoke-AICompletion {
    <#
    .SYNOPSIS
        Sends a prompt to an AI provider and returns the completion.
    .DESCRIPTION
        Provider-agnostic AI completion function supporting Anthropic, OpenAI, Ollama, and Custom endpoints.
        Used internally for runbook generation from ticket history and intelligent decision support.
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [string]$Prompt,

        [Parameter()]
        [ValidateSet('Anthropic', 'OpenAI', 'Ollama', 'Custom')]
        [string]$Provider = 'OpenAI',

        [Parameter()]
        [string]$ApiKey,

        [Parameter()]
        [string]$Model,

        [Parameter()]
        [string]$SystemPrompt = 'You are an infrastructure automation expert. Generate precise, actionable content.',

        [Parameter()]
        [string]$CustomEndpoint,

        [Parameter()]
        [int]$MaxTokens = 4096,

        [Parameter()]
        [double]$Temperature = 0.3
    )

    # Set default models per provider
    if (-not $Model) {
        $Model = switch ($Provider) {
            'Anthropic' { 'claude-sonnet-4-20250514' }
            'OpenAI'    { 'gpt-4o' }
            'Ollama'    { 'llama3' }
            'Custom'    { 'default' }
        }
    }

    $result = $null

    switch ($Provider) {
        'Anthropic' {
            if (-not $ApiKey) { throw 'ApiKey is required for Anthropic provider.' }

            $headers = @{
                'x-api-key'         = $ApiKey
                'anthropic-version' = '2023-06-01'
                'Content-Type'      = 'application/json'
            }

            $body = @{
                model      = $Model
                max_tokens = $MaxTokens
                system     = $SystemPrompt
                messages   = @(
                    @{ role = 'user'; content = $Prompt }
                )
            } | ConvertTo-Json -Depth 10

            try {
                $response = Invoke-RestMethod -Uri 'https://api.anthropic.com/v1/messages' `
                    -Method Post -Headers $headers -Body $body -ErrorAction Stop
                $result = $response.content[0].text
            }
            catch {
                Write-Warning "Anthropic API call failed: $_"
                throw
            }
        }

        'OpenAI' {
            if (-not $ApiKey) { throw 'ApiKey is required for OpenAI provider.' }

            $headers = @{
                'Authorization' = "Bearer $ApiKey"
                'Content-Type'  = 'application/json'
            }

            $body = @{
                model       = $Model
                max_tokens  = $MaxTokens
                temperature = $Temperature
                messages    = @(
                    @{ role = 'system'; content = $SystemPrompt }
                    @{ role = 'user';   content = $Prompt }
                )
            } | ConvertTo-Json -Depth 10

            try {
                $response = Invoke-RestMethod -Uri 'https://api.openai.com/v1/chat/completions' `
                    -Method Post -Headers $headers -Body $body -ErrorAction Stop
                $result = $response.choices[0].message.content
            }
            catch {
                Write-Warning "OpenAI API call failed: $_"
                throw
            }
        }

        'Ollama' {
            $ollamaUrl = if ($CustomEndpoint) { $CustomEndpoint } else { 'http://localhost:11434' }

            $body = @{
                model  = $Model
                prompt = "${SystemPrompt}`n`n${Prompt}"
                stream = $false
                options = @{
                    num_predict = $MaxTokens
                    temperature = $Temperature
                }
            } | ConvertTo-Json -Depth 10

            try {
                $response = Invoke-RestMethod -Uri "$ollamaUrl/api/generate" `
                    -Method Post -Body $body -ContentType 'application/json' -ErrorAction Stop
                $result = $response.response
            }
            catch {
                Write-Warning "Ollama API call failed: $_"
                throw
            }
        }

        'Custom' {
            if (-not $CustomEndpoint) { throw 'CustomEndpoint is required for Custom provider.' }

            $headers = @{ 'Content-Type' = 'application/json' }
            if ($ApiKey) { $headers['Authorization'] = "Bearer $ApiKey" }

            $body = @{
                model       = $Model
                max_tokens  = $MaxTokens
                temperature = $Temperature
                messages    = @(
                    @{ role = 'system'; content = $SystemPrompt }
                    @{ role = 'user';   content = $Prompt }
                )
            } | ConvertTo-Json -Depth 10

            try {
                $response = Invoke-RestMethod -Uri $CustomEndpoint `
                    -Method Post -Headers $headers -Body $body -ErrorAction Stop

                # Try common response formats
                if ($response.choices) {
                    $result = $response.choices[0].message.content
                }
                elseif ($response.content) {
                    $result = if ($response.content -is [array]) { $response.content[0].text } else { $response.content }
                }
                elseif ($response.response) {
                    $result = $response.response
                }
                elseif ($response.text) {
                    $result = $response.text
                }
                else {
                    $result = $response | ConvertTo-Json -Depth 5
                }
            }
            catch {
                Write-Warning "Custom API call failed: $_"
                throw
            }
        }
    }

    return $result
}