Providers/OpenAI.ps1
|
<#
.SYNOPSIS Invokes the OpenAI API to generate responses using specified models. .DESCRIPTION The Invoke-OpenAIProvider function sends requests to the OpenAI API and returns the generated content. It requires an API key to be set in the environment variable 'OpenAIKey'. .PARAMETER ModelName The name of the OpenAI model to use (e.g., 'gpt-4', 'gpt-3.5-turbo'). .PARAMETER Messages An array of hashtables containing the messages to send to the model. .PARAMETER Tools An array of tool definitions for function calling. Can be strings (command names) or hashtables. .EXAMPLE $Message = New-ChatMessage -Prompt 'Write a PowerShell function to calculate factorial' $response = Invoke-OpenAIProvider -ModelName 'gpt-4' -Message $Message .EXAMPLE $response = Invoke-OpenAIProvider -ModelName 'gpt-4' -Messages $messages -Tools "Get-ChildItem" .NOTES Requires the OpenAIKey environment variable to be set with a valid API key. Uses OpenAI's Responses API for all models. API Reference: https://platform.openai.com/docs/api-reference/responses #> function Invoke-OpenAIProvider { param( [Parameter(Mandatory)] [string]$ModelName, [Parameter(Mandatory)] [hashtable[]]$Messages, [object[]]$Tools ) # Process tools: if strings, register them; then convert to provider schema if ($Tools) { $toolDefinitions = New-Object System.Collections.Generic.List[object] foreach ($tool in $Tools) { if ($tool -is [string]) { $toolDefinitions.Add((Register-Tool $tool)) } else { $toolDefinitions.Add($tool) } } $Tools = ConvertTo-ProviderToolSchema -Tools $toolDefinitions -Provider openai } $headers = @{ 'Authorization' = "Bearer $env:OpenAIKey" 'OpenAI-Beta' = 'responses=v1' 'content-type' = 'application/json' } $Uri = "https://api.openai.com/v1/responses" $body = @{ 'model' = $ModelName 'input' = $Messages } # Add tools if provided - convert from Chat Completions format to Responses API format if ($Tools) { $body['tools'] = @($Tools | ForEach-Object { @{ type = 'function' name = $_.function.name description = $_.function.description parameters = $_.function.parameters } }) } $maxIterations = 5 $iteration = 0 while ($iteration -lt $maxIterations) { $params = @{ Uri = $Uri Method = 'POST' Headers = $headers Body = $body | ConvertTo-Json -Depth 10 } try { $response = Invoke-RestMethod @params # Check if the response contains an error if ($response.error) { Write-Error $response.error.message return "Error: $($response.error.message)" } # Check if output exists if (!$response.output) { return "No output in response from API." } # Check for function calls in the response output $functionCalls = $response.output | Where-Object { $_.type -eq 'function_call' } if ($functionCalls) { # Add all response output items to the input for context $body.input += $response.output # Execute function calls and add results foreach ($call in $functionCalls) { $functionName = $call.name $functionArgs = $call.arguments | ConvertFrom-Json -AsHashtable try { if (Get-Command $functionName -ErrorAction SilentlyContinue) { $result = & $functionName @functionArgs } else { $result = "Error: Function $functionName not found" } } catch { $result = "Error: $($_.Exception.Message)" } $body.input += @{ type = 'function_call_output' call_id = $call.call_id output = $result | Out-String } } } else { # No function calls, extract text from message output items # Responses API returns: output[].type='message', output[].content[].type='output_text' $textOutput = ($response.output | Where-Object { $_.type -eq 'message' } | ForEach-Object { if ($_.content -is [array]) { ($_.content | Where-Object { $_.type -eq 'output_text' } | ForEach-Object { $_.text }) -join '' } elseif ($_.content) { $_.content } }) -join '' if (!$textOutput) { return "No text content in response." } return $textOutput } } catch { $statusCode = $_.Exception.Response.StatusCode.value__ $errorMessage = $_.ErrorDetails.Message Write-Error "OpenAI API Error (HTTP $statusCode): $errorMessage" return "Error calling OpenAI API: $($_.Exception.Message)" } $iteration++ } return "Maximum iterations reached without completing the response." } |