Public/Translation/Get-OpenRouterModel.ps1
|
function Get-OpenRouterModel { <# .SYNOPSIS Lists models available through the OpenRouter API. .DESCRIPTION Calls OpenRouter's GET /models endpoint, which is public and requires no authentication. If an OpenRouter provider has already been saved via Set-TranslationProvider (with an API key), its key is sent opportunistically as a bearer token - but decrypting it requires Windows DPAPI, so on non-Windows platforms (or if decryption fails for any reason) this degrades gracefully to an unauthenticated call rather than failing the whole cmdlet. Use this to discover current model IDs (the "vendor/model" slug format OpenRouter expects, e.g. 'anthropic/claude-sonnet-5') before configuring Set-TranslationProvider -Name OpenRouter. .PARAMETER Filter Optional wildcard pattern matched against each model's Id and Name (case-insensitive). Only matching models are returned. .PARAMETER BaseUrl Override the OpenRouter API base URL. Defaults to the saved OpenRouter provider's BaseUrl if one is configured, otherwise the value from Data/ProviderDefaults.json. .OUTPUTS PSCustomObject: Id, Name, ContextLength, MaxOutputTokens, PromptPricePerMTok, CompletionPricePerMTok .EXAMPLE Get-OpenRouterModel | Sort-Object PromptPricePerMTok | Select-Object -First 10 .EXAMPLE Get-OpenRouterModel -Filter 'anthropic/*' | Format-Table Id, ContextLength, PromptPricePerMTok .EXAMPLE Get-OpenRouterModel -Filter '*claude*' -BaseUrl 'https://openrouter.ai/api/v1' #> [CmdletBinding()] [OutputType([PSCustomObject[]])] param( [string] $Filter, [string] $BaseUrl ) if (-not $BaseUrl) { if ($script:ConfiguredProviders.ContainsKey('OpenRouter')) { $BaseUrl = $script:ConfiguredProviders['OpenRouter'].BaseUrl } elseif ($script:ProviderDefaults.OpenRouter) { $BaseUrl = $script:ProviderDefaults.OpenRouter.BaseUrl } else { throw 'Get-OpenRouterModel: no BaseUrl was supplied and no OpenRouter default is available.' } } $headers = @{} if ($script:ConfiguredProviders.ContainsKey('OpenRouter')) { $encryptedKey = $script:ConfiguredProviders['OpenRouter'].ApiKeyEncrypted if (-not [string]::IsNullOrEmpty($encryptedKey)) { try { $plainKey = Unprotect-ApiKey -EncryptedBase64 $encryptedKey $headers.Authorization = "Bearer $plainKey" } catch { # Decryption requires Windows DPAPI - on non-Windows platforms (or # any other decryption failure) fall back to the unauthenticated # call, since listing models does not require a key. Write-Verbose "Get-OpenRouterModel: could not decrypt saved OpenRouter API key, continuing unauthenticated: $_" } } } $result = Invoke-TranslationApiRequest -Uri "$BaseUrl/models" -Method Get -Headers $headers -ProviderLabel 'OpenRouter' if (-not $result.Success) { throw "Get-OpenRouterModel: request failed (status=$($result.StatusCode)): $($result.ErrorMessage)" } $models = $result.Response.data foreach ($model in $models) { if ($Filter -and ($model.id -notlike $Filter) -and ($model.name -notlike $Filter)) { continue } $promptPrice = $null $completionPrice = $null if ($model.pricing) { if (-not [string]::IsNullOrEmpty($model.pricing.prompt)) { $promptPrice = [decimal]$model.pricing.prompt * 1000000 } if (-not [string]::IsNullOrEmpty($model.pricing.completion)) { $completionPrice = [decimal]$model.pricing.completion * 1000000 } } $maxOutputTokens = $null if ($model.top_provider -and $null -ne $model.top_provider.max_completion_tokens) { $maxOutputTokens = [int]$model.top_provider.max_completion_tokens } [PSCustomObject]@{ Id = $model.id Name = $model.name ContextLength = $model.context_length MaxOutputTokens = $maxOutputTokens PromptPricePerMTok = $promptPrice CompletionPricePerMTok = $completionPrice } } } |