Public/Add-OpenAIDecisionTag.ps1
|
<# .SYNOPSIS Adds every matching semantic tag to each input. .DESCRIPTION Turns a label-to-description dictionary into independent predicate questions. All tag questions share one request per input. Tags whose yes probability meets Threshold are returned in Tags; individual probabilities and full answers are also retained. Inputs are not modified. #> function Add-OpenAIDecisionTag { [CmdletBinding(PositionalBinding = $false)] param( [Parameter(Mandatory, ValueFromPipeline)][object]$State, [Parameter(Mandatory, Position = 0)][System.Collections.IDictionary]$Tags, [Parameter(Position = 1)][ValidateRange(0.0, 1.0)][double]$Threshold = 0.5, [Parameter()][string]$Model = 'gpt-6-luna' ) begin { if ($Tags.Count -eq 0) { throw 'Add-OpenAIDecisionTag requires at least one tag description.' } $questions = [System.Collections.Generic.List[object]]::new() $seen = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::OrdinalIgnoreCase) foreach ($entry in $Tags.GetEnumerator()) { $name = [string]$entry.Key if ([string]::IsNullOrWhiteSpace($name)) { throw 'Tag names cannot be empty or whitespace.' } if (-not $seen.Add($name)) { throw "Duplicate tag name '$name'. Tag names are case-insensitive." } if ($entry.Value -isnot [string] -or [string]::IsNullOrWhiteSpace($entry.Value)) { throw "Tag '$name' requires a non-empty string description." } $questions.Add((New-OpenAIYesNoQuestion -Name $name -Question "Does this input match the tag '$name'?" -TrueCriteria $entry.Value -FalseCriteria 'The input does not meet the description of this tag.')) } } process { $response = Invoke-OpenAIDecision -InputObject $State -Question $questions.ToArray() -Model $Model -Raw -ErrorAction Stop $matchingTags = [System.Collections.Generic.List[string]]::new() foreach ($question in $questions) { $answer = Get-OpenAIDecisionAnswer -Response $response -Name $question.Name if ($answer.type -eq 'refusal' -or $null -eq $answer.probability) { throw "OpenAI declined or omitted the probability for tag '$($question.Name)'." } $probability = [double]$answer.probability if ([double]::IsNaN($probability) -or $probability -lt 0 -or $probability -gt 1) { throw "OpenAI returned an invalid probability for tag '$($question.Name)'." } if ($probability -ge $Threshold) { $matchingTags.Add($question.Name) } } $result = ConvertTo-OpenAIDecisionEnrichedResult -State $State -Response $response $propertyName = 'Tags' while ($null -ne $result.PSObject.Properties[$propertyName]) { $propertyName = "OpenAIDecision_$propertyName" } $result.PSObject.Properties.Add([psnoteproperty]::new($propertyName, [string[]]$matchingTags.ToArray())) $result } } |