Public/Invoke-AzAIAgent.ps1
|
function Invoke-AzAIAgent { <# .SYNOPSIS Invokes an AI agent via the Azure AI Foundry Responses API. .DESCRIPTION Sends a message to an agent and returns the complete response. Supports two execution modes: - Agent Reference: provide -AgentName to use a named agent in Foundry - Direct Mode: provide -Model (+ optional -Instructions, -Tools) Use -Conversation to continue on an existing conversation thread (shared-conversation pattern). Omit -Conversation to create a new isolated conversation. .EXAMPLE # Agent Reference mode $resp = Invoke-AzAIAgent -AgentName "MyAgent" -Message "What is Azure RBAC?" .EXAMPLE # Direct mode — specify model and instructions per-request $resp = Invoke-AzAIAgent -Model "gpt-5-mini" -Instructions "You are a cloud architect" -Message "What is Azure RBAC?" .EXAMPLE # Shared conversation — agent switching $conv = New-AzAIConversation $r1 = Invoke-AzAIAgent -Conversation $conv -AgentName "ResearchAgent" -Message "Explain RBAC" $r2 = Invoke-AzAIAgent -Conversation $conv -Model "gpt-5-mini" -Message "Summarize the above" .EXAMPLE # Direct mode with MCP tools Invoke-AzAIAgent -Model "gpt-5-mini" -Instructions "Manage cases" -Tools @("https://my-mcp/mcp") -Message "List cases" #> [CmdletBinding(DefaultParameterSetName = 'AgentReference')] param( [Parameter(Mandatory, ParameterSetName = 'AgentReference')] [string]$AgentName, [Parameter(Mandatory, ParameterSetName = 'DirectMode')] [string]$Model, [Parameter(ParameterSetName = 'DirectMode')] [string]$Instructions, [Parameter(ParameterSetName = 'DirectMode')] [string[]]$Tools, [Parameter(Mandatory)] [string]$Message, [PSCustomObject]$Conversation, [int]$MaxOutputTokens, [double]$Temperature, [switch]$NoAutoApprove ) $conn = $script:Connection if (-not $conn) { throw 'Not connected. Run Connect-AzAIFoundry first.' } $convId = if ($Conversation) { $Conversation.ConversationId } else { $null } $mode = if ($AgentName) { 'agent_reference' } else { 'direct' } Write-Verbose "Mode: $mode | Agent: $($AgentName ?? $Model) | Conversation: $($convId ?? '(new)')" if ($conn.Mode -eq 'Workbench') { # Route through AI Workbench /api/invoke $body = ConvertTo-InvokePayload ` -Message $Message ` -AgentName $AgentName ` -Model $Model ` -Instructions $Instructions ` -Tools $Tools ` -ConversationId $convId ` -MaxOutputTokens $MaxOutputTokens ` -Temperature $Temperature ` -AutoApprove (-not $NoAutoApprove) $result = Send-FoundryRequest -Method POST -Path '/api/invoke' -Body $body # Update conversation object if one was passed if ($Conversation -and $result.conversationId) { $Conversation.ConversationId = $result.conversationId } $output = [PSCustomObject]@{ PSTypeName = 'AzAIAgentResponse' ConversationId = $result.conversationId ResponseId = $result.responseId AgentName = $result.agentName Mode = $result.mode Response = $result.response ToolCalls = $result.toolCalls TokensUsed = if ($result.tokensUsed) { [PSCustomObject]@{ InputTokens = $result.tokensUsed.inputTokens OutputTokens = $result.tokensUsed.outputTokens TotalTokens = $result.tokensUsed.totalTokens } } else { $null } Model = $result.model DurationMs = $result.durationMs } # Auto-create conversation object for chaining if none was passed if (-not $Conversation) { $output | Add-Member -NotePropertyName '_Conversation' -NotePropertyValue ([PSCustomObject]@{ ConversationId = $result.conversationId Source = 'Workbench' CreatedAt = Get-Date }) } Write-Verbose "$($result.agentName ?? $Model) ($mode) → $($result.response.Length) chars, $($result.durationMs)ms" return $output } else { # Foundry Direct — build Responses API payload if (-not $convId) { $newConv = New-AzAIConversation $convId = $newConv.ConversationId } $body = @{ conversation = $convId input = $Message stream = $false } if ($AgentName) { $body.agent = @{ type = 'agent_reference' name = $AgentName } } else { $body.model = $Model if ($Instructions) { $body.instructions = $Instructions } if ($MaxOutputTokens -gt 0) { $body.max_output_tokens = $MaxOutputTokens } if ($Tools) { $body.tools = @($Tools | ForEach-Object { @{ type = 'mcp'; server_url = $_; server_label = "mcp-$($Tools.IndexOf($_))" } }) } } if ($PSBoundParameters.ContainsKey('Temperature')) { $body.temperature = $Temperature } $start = Get-Date $result = Send-FoundryRequest -Method POST -Path '/openai/responses' -Body $body $elapsed = ((Get-Date) - $start).TotalMilliseconds # Extract text from response output $responseText = ($result.output | Where-Object { $_.type -eq 'message' } | ForEach-Object { $_.content | Where-Object { $_.type -eq 'output_text' } | ForEach-Object { $_.text } }) -join '' $toolCalls = @($result.output | Where-Object { $_.type -eq 'mcp_call' } | ForEach-Object { [PSCustomObject]@{ name = $_.name; status = $_.status } }) $usage = if ($result.usage) { [PSCustomObject]@{ InputTokens = $result.usage.input_tokens OutputTokens = $result.usage.output_tokens TotalTokens = $result.usage.total_tokens } } else { $null } # Update conversation object if ($Conversation) { $Conversation.ConversationId = $convId } $output = [PSCustomObject]@{ PSTypeName = 'AzAIAgentResponse' ConversationId = $convId ResponseId = $result.id AgentName = $AgentName Mode = $mode Response = $responseText ToolCalls = $toolCalls TokensUsed = $usage Model = $Model DurationMs = [int]$elapsed } Write-Verbose "$($AgentName ?? $Model) ($mode) → $($responseText.Length) chars, $([int]$elapsed)ms" return $output } } |