Public/New-AgentHarness.ps1
|
function New-AgentHarness { <# .SYNOPSIS Runs an agent with a prompt or an interactive conversation. .DESCRIPTION With Prompt, runs one request through PSAISuite's model/tool loop and returns the response. Without Prompt, reads input with Read-Host and retains user messages and final assistant replies for follow-up turns. Enter exit, quit, or an empty line to end the interactive conversation. Use PassThru to return an editable harness without starting a conversation. OpenAI, Anthropic, and Vercel show request/tool progress while running. Add Verbose to retain the activity log. Progress is separate from the answer. .PARAMETER Prompt The prompt to run immediately, including any tool calls needed to answer it. Omit this parameter to start an interactive conversation. .PARAMETER PassThru Return the configuration object with a GetResponse(prompt) method without reading input, calling a model, or executing tools. Cannot be used with Prompt. .PARAMETER Model The provider:model identifier. Defaults to openai:gpt-5.6-luna. .PARAMETER Tools PowerShell command names or tool schemas accepted by Invoke-ChatCompletion. Defaults to no tools. .PARAMETER SystemPrompt Instructions sent with each request. .PARAMETER MaxIterations Maximum tool-calling rounds for providers that support this setting. .EXAMPLE New-AgentHarness -Prompt 'List the files in the current directory.' -Tools Get-ChildItem .EXAMPLE New-AgentHarness -Model 'anthropic:claude-sonnet-4-6' -Tools Get-Date Starts an interactive conversation. Enter exit or quit to finish. .EXAMPLE $harness = New-AgentHarness -PassThru -Tools Get-Date $harness.MaxIterations = 3 $harness.GetResponse('What is the current date?') .NOTES Interactive history lasts only for this invocation. Tool exchanges are handled within each request by the provider. GetResponse starts a fresh conversation on each call. Tools run with the current user's permissions. Provider credentials and model overrides follow Invoke-ChatCompletion. #> [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Justification = 'Delegates requests and tool execution to Invoke-ChatCompletion; PassThru only creates an in-memory configuration object.')] [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '', Justification = 'Displays interactive exit instructions on the host without mixing them into response output.')] [CmdletBinding(DefaultParameterSetName = 'Run')] param( [Parameter(Position = 0, ParameterSetName = 'Run')] [ValidateNotNullOrEmpty()] [ValidateScript({ -not [string]::IsNullOrWhiteSpace($_) })] [string]$Prompt, [ValidateNotNullOrEmpty()] [string]$Model = 'openai:gpt-5.6-luna', [object[]]$Tools = @(), [string]$SystemPrompt = 'You are a helpful assistant.', [ValidateRange(1, 100)] [int]$MaxIterations = 5, [Parameter(Mandatory, ParameterSetName = 'Object')] [switch]$PassThru ) $harness = [pscustomobject]@{ Model = $Model Tools = $Tools SystemPrompt = $SystemPrompt MaxIterations = $MaxIterations } $harness | Add-Member -MemberType ScriptMethod -Name GetResponse -Value { param( [ValidateNotNullOrEmpty()] [string]$Prompt ) $parameters = @{ Messages = @( @{ role = 'system'; content = $this.SystemPrompt } @{ role = 'user'; content = $Prompt } ) Model = $this.Model Tools = $this.Tools MaxIterations = $this.MaxIterations } Invoke-ChatCompletion @parameters } if ($PassThru) { return $harness } if ($PSBoundParameters.ContainsKey('Prompt')) { return $harness.GetResponse($Prompt) } $messages = @(@{ role = 'system'; content = $SystemPrompt }) Write-Host 'Enter a prompt. Type exit or quit, or press Enter on an empty line, to finish.' while ($true) { $userInput = Read-Host -Prompt 'You' if ([string]::IsNullOrWhiteSpace($userInput) -or $userInput.Trim() -in @('exit', 'quit')) { break } $parameters = @{ Messages = $messages + @(@{ role = 'user'; content = $userInput }) Model = $Model Tools = $Tools MaxIterations = $MaxIterations ErrorAction = 'Stop' } $response = Invoke-ChatCompletion @parameters $messages = $parameters.Messages + @(@{ role = 'assistant'; content = $response }) $response } } |