Classes/Extensions/Functions.psm1
using module "..\Dialog.psm1" using module "..\OpenAiChat.psm1" using module "..\Options.psm1" using module "..\..\Private\OutHelper.psm1" class Functions { [string]$Path [OpenAiChat]$ChatApi [bool]$Enabled = $true [object[]]$Names = @() [OpenAiChatMessage] PostOpenAiChatResponse([object]$messageDialog) { $message = $messageDialog.message $dialog = $messageDialog.dialog if(!$this.Enabled) { return $message } $openAiMessages = $dialog.AsOpenAiChatMessages() while($null -ne $message.FunctionCall) { # call function that returns object $fnName = $message.FunctionCall.Name Write-Debug "Functions: Calling '$fnName' with arguments $($message.FunctionCall.Arguments | ConvertTo-Json -Depth 10)" $result = $null try { $result = $this.InvokePsFunction($message.FunctionCall.Name, $message.FunctionCall.Arguments) } catch { [OutHelper]::NonCriticalError("Functions: Call to '$fnName' failed: $($_.Exception.Message)") return [OpenAiChatMessage]::FromAssistant("Function call failed: $($_.Exception.Message)") } Write-Debug "Functions: Call to '$fnName' returned $($result | ConvertTo-Json -Depth 10)" # add function result to existing messages $openAiMessages += [OpenAiChatMessage]::FromFunction($message.FunctionCall.Name, $result) # call open ai again $message = $this.ChatApi.GetAnswer($openAiMessages) } # return final non-function-call message return $message } [object] InvokePsFunction($name, $arguments) { $func = Get-Command $name if($null -eq $func) { throw "Function '$name' not found" } return Invoke-Command -ScriptBlock { param($command, $params) & $command @params } -ArgumentList $name, $arguments } [Dialog] BeforeChatLoop([Dialog]$dialog) { if (!$this.Enabled) { return $dialog } # $scriptPath = "./myscript.ps1" # $scriptPath = Resolve-Path -Path $scriptPath # [OutHelper]::Info("Functions being loaded from $scriptPath.") # . $scriptPath $functions = Get-Command # -CommandType Function $chatFunctions = @() # $importedFunctions = $functions | Where-Object { $_.ScriptBlock.File -eq $scriptPath } $importedFunctions = $functions | Where-Object { $this.Names.Contains($_.Name) } foreach ($func in $importedFunctions) { # get name and type $funcName = $func.Name $helpContent = Get-Help -Name $funcName $funcDesc = $helpContent.Details.Description.Text if($null -eq $funcDesc) { $funcDesc = "" } $chatFunction = @{ "name" = $funcName "description" = $funcDesc "parameters" = @{ "type" = "object" "properties" = @{} "required" = @() } } $paramHelp = $helpContent.Syntax.SyntaxItem.Parameter foreach ($param in $func.Parameters.Values) { # check for system/default parameters if ($param.Attributes.Position -eq [Int32]::MinValue) { continue } # get name, type and description $paramName = $param.Name $paramType = $param.ParameterType.Name.ToLower() switch($paramType) { "int32" { $paramType = "integer" } "int64" { $paramType = "integer" } "boolean" { $paramType = "boolean" } default { $paramType = "string" } } $paramRequired = $param.Attributes.Mandatory $paramDescription = ($paramHelp | Where-Object name -EQ $paramName).description.text if($null -eq $paramDescription) { $paramDescription = "" } # Write-Debug " - Parameter: Name=$paramName, Type=$paramType, Required=$paramAttribute, Desc=$paramDescription" $chatFunction.parameters.properties.$paramName = @{ "type" = $paramType "description" = $paramDescription } if($paramRequired) { $chatFunction.parameters.required += $paramName } } $chatFunctions += $chatFunction } $this.ChatApi.Functions = $chatFunctions # Write-Debug "$($this.ChatApi.Functions | ConvertTo-Json -Depth 10)" if($chatFunctions.Count -gt 0) { [OutHelper]::Info("- Functions: $(($chatFunctions | ForEach-Object { $_.name }) -join ', ').") } return $dialog } } |