providers/cohere.ps1
<#
Esta função é usada como base para invocar a a API da OpenAI! #> function Invoke-CohereApi { [CmdletBinding()] param( $endpoint ,$body ,$method = 'GET' ,$StreamCallback = $null ,$Token = $null ,$JsonDepth = 15 ) $Provider = Get-AiCurrentProvider -Context $Creds = Get-AiDefaultCredential $ApiKey = $Creds.credential.credential; if(!$ApiKey){ throw "POWERSHAI_COHERE_NOAPIKEY: No Api Key provided!"; } $headers = @{ Authorization = "Bearer $ApiKey" } if($endpoint -match '^https?://'){ $url = $endpoint } else { $BaseUrl = GetCurrentProviderData BaseUrl $url = "$BaseUrl/$endpoint" } $ReqParams = @{ data = $body url = $url method = $method Headers = $headers JsonDepth = $JsonDepth } if($StreamCallback){ $ReqParams['SseCallBack'] = $StreamCallback } verbose "ReqParams:`n$($ReqParams|out-string)" try { $RawResp = InvokeHttp @ReqParams } catch [System.Net.WebException] { $ex = $_.exception; if($ex.PowershaiDetails){ $ResponseError = $ex.PowershaiDetails.ResponseError.text; if($ResponseError){ $err = New-PowershaiError "POWERSHAI_COHERE_ERROR" "Error: $ResponseError" -Prop @{ HttpResponseText = $ResponseError HttpResponse = $ex.PowershaiDetails.ResponseError.Response } throw $err } } throw; } verbose "RawResp: `n$($RawResp|out-string)" if($RawResp.stream){ return $RawResp; } return $RawResp.text | ConvertFrom-Json } function Get-CohereModels { param() $resp = Invoke-CohereApi 'models' -body @{page_size = 1000} return $resp.models; } Set-Alias cohere_GetModels Get-CohereModels function Convert-OpenaiToolName2Cohere { param($OpenaiName) $COhereName = $OpenaiName -replace '[^A-Za-z0-9_]','' # Prevent start with digit! if($CohereName -match '^\d'){ $CohereName = "t" + $CohereName; } return $CohereName; } function Convert-Openai2CohereMessage { param($messages) [object[]]$OpenAiMessages = @(ConvertTo-OpenaiMessage $messages) [object[]]$CohereMessages = @() foreach($m in $OpenAiMessages){ switch($m.role){ "tool" { $CohereMessage = $m; } "assistant" { $CohereMessage = HashTableMerge @{} $m; $CohereMessage.remove("refusal"); foreach($Call in $CohereMessage.tool_calls){ $Call.function.name = Convert-OpenaiToolName2Cohere $Call.function.name } } default { $CohereMessage = @{ content = $m.content role = $m.role } } } $CohereMessages += $CohereMessage } return $CohereMessages; } function Get-CohereChat { param( $messages = @() ,$model = $null ,$RawParams = @{} ,$StreamCallback = $null ) [object[]]$CohereMessages = @(Convert-Openai2CohereMessage $messages) if(!$model){ $model = GetCurrentProviderData -Context DefaultModel } $stream = $false; if($StreamCallback){ $stream = $true; } $Data = HashTableMerge @{ model = $model messages = $CohereMessages stream = $stream } $RawParams $ReqParams = @{} Invoke-CohereApi "chat" -method POST -body $Data -StreamCallback $StreamCallback; } function Convert-CohereAnswerToOpenai { param($Answer, $StreamData) $Result = @{ id = $Answer.id object = "chat.completion" created = [int](((Get-Date) - (Get-Date "1970-01-01T00:00:00Z")).TotalSeconds) service_tier = $null system_fingerprint = $null usage = @{ completion_tokens = $Answer.usage.tokens.input_tokens prompt_tokens = $Answer.usage.tokens.output_tokens total_tokens = $null } logprobs = $null choices = @() model = $model } $OpenaiFinishReason = $null $NewChoice = @{ index = 0 logprobs = $null finish_reason = $Answer.finish_reason } $RespContent = $null $Message = @{ role = "assistant" refusal = $null content = $null } $OpenAiTools = $Answer.message.tool_calls if($OpenAiTools){ $Message.tool_calls = $OpenAiTools } if($StreamData.ChunkId){ $Result.object = "chat.completion.chunk" $Result.id = $StreamData.ChunkId $Message.content = $Answer.delta.message.content.text; $NewChoice.delta = $Message } else { if($Answer.message.content){ $Message.content = $Answer.message.content[0].text; } $NewChoice.message = $Message } $Result.choices += $NewChoice; return $result; } function cohere_Chat { param( $prompt ,$model ,$StreamCallback ,$RawParams ) $AiChatParams = $ProviderFuncRawData.params; $Tools = $AiChatParams.Functions; # fix tools arguments! $AllTools = @() $ToolMap = @{} #Maps cohere names to original name foreach($Tool in $Tools){ $NewTool = HashTableMerge @{} $Tool if(!$NewTool.function){ continue; } $OriginalCallName = $NewTool.function.name; $CohereName = Convert-OpenaiToolName2Cohere $NewTool.function.name $NewTool.function.name = $CohereName; $ToolMap[$CohereName] = $OriginalCallName if(!$NewTool.function.parameters){ $NewTool.function.parameters = @{ type = "object" } } $AllTools += $NewTool; } if(!$RawParams.tools){ $RawParams.tools = $AllTools } $StreamData = @{ ChunkId = [guid]::NewGuid().Guid AllToolCalls = @() CurrentToolCall = $null } $StreamScript = $null if($StreamCallback){ $UserScriptCallback = $StreamCallback $StreamScript = { param($data) $line = @($data.line)[0]; if(!$line){ return; } if($line -like "event: *"){ $StreamData.CurrentEvent = $line.replace("event: ",""); return; } $Answer = $null; if($line -match 'data: (.+)'){ $data = $matches[1]; if($data -eq "[DONE]"){ return $false; } $Answer = $matches[1] | ConvertFrom-Json; } if($StreamData.CurrentEvent -eq "message-start"){ $OpenaiAnswer = Convert-CohereAnswerToOpenai $Answer $StreamData; #Copy to message $OpenaiAnswer.choices[0].message = $OpenaiAnswer.choices[0].delta; $OpenaiAnswer.choices[0].remove('delta'); $StreamData.OpenaiAnswer = $OpenaiAnswer; } if($StreamData.CurrentEvent -eq "content-delta"){ $DeltaAnswer = Convert-CohereAnswerToOpenai $Answer $StreamData $StreamData.OpenaiAnswer.choices[0].message.content += $Answer.delta.message.content.text; & $UserScriptCallback $DeltaAnswer } #https://docs.cohere.com/v2/reference/chat-stream#response.body.tool-call-start if($StreamData.CurrentEvent -eq "tool-call-start"){ $ToolCallParams = @{ FunctionName = $Answer.delta.message.tool_calls.function.name FunctionArgs = $Answer.delta.message.tool_calls.function.arguments CallId = $Answer.delta.message.tool_calls.id } $StreamData.CurrentToolCall = New-AiChatResultToolCall @ToolCallParams $StreamData.AllToolCalls += $StreamData.CurrentToolCall } if($StreamData.CurrentEvent -eq "tool-call-delta"){ $StreamData.CurrentToolCall.function.arguments += $Answer.delta.message.tool_calls.function.arguments } if($StreamData.CurrentEvent -eq "tool-call-end"){} if($StreamData.CurrentEvent -eq "message-end"){ $StreamData.OpenaiAnswer.choices[0].finish_reason = $Answer.delta.finish_reason; } } } $resp = Get-CohereChat -messages $prompt -model $model -RawParams $RawParams -StreamCallback $StreamScript if($resp.stream){ $StreamData.OpenaiAnswer.choices[0].message.tool_calls = $StreamData.AllToolCalls; $OpenaiAnswer = $StreamData.OpenaiAnswer; } else { $OpenaiAnswer = Convert-CohereAnswerToOpenai $resp } $Choices = @(); foreach($choice in $OpenaiAnswer.choices){ $tools = @() foreach($call in $choice.message.tool_calls){ #Map back! $ToolRealName = $ToolMap[$call.function.name] $CallArgs = $call.function.arguments; if(!$CallArgs){ $CallArgs = '{}' } $tools += New-AiChatResultToolCall -FunctionName $ToolRealName -FunctionArgs $CallArgs -CallId $call.id } switch( $choice.finish_reason){ "COMPLETE" { $OpenaiFinishReason = "stop" } "STOP_SEQUENCE" { $OpenaiFinishReason = "stop" } "MAX_TOKENS" { $OpenaiFinishReason = "length" } "ERROR" { $OpenaiFinishReason = "stop" write-warning "Cohere reported error when finished!!"; } "TOOL_CALL" { $OpenaiFinishReason = "tool_calls" } default { verbose "Unknown cohere complete length: $OpenaiFinishReason" $OpenaiFinishReason = "stop" } } $Choices += New-AiChatResultChoice -FinishReason $OpenaiFinishReason -role $choice.message.role -Content $choice.message.content -tools $tools } if(!$OpenaiAnswer.id){ [string]$OpenaiAnswer.id = [guid]::NewGuid() } $params = @{ id = $OpenaiAnswer.id model = $OpenaiAnswer.model choices = $Choices SystemFingerprint = $OpenaiAnswer.system_fingerprint PromptTokens = $OpenaiAnswer.usage.prompt_tokens CompletionTokens = $OpenaiAnswer.usage.completion_tokens TotalTokens = $OpenaiAnswer.usage.total_tokens } $ChatResult = New-AiChatResult @params return $ChatResult; } function cohere_FormatPrompt { param($model) $ModelEmoji = "🟣"; if($model -like "c4ai-aya*"){ $ModelEmoji = "❄️" } return "🟠$($ModelEmoji) $($model): "; } return @{ BaseUrl = "https://api.cohere.com/v2" DefaultModel = "command-r" CredentialEnvName = "COHERE_API_KEY" #Assume every openai model support tools. ToolsModels = @( "command-r-*" "command-r" "command-r7b*" "ch4ai-*" ) EmbeddingsModels = @( "embed-*" ) info = @{ desc = "Cohere" url = "https://docs.cohere.com/" } } |