Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
c17ba8e
ci: refactor main-sync-to-dev to cherry-pick allow-listed files onto …
marc-romu May 3, 2026
a4e1e31
ci: add automated provider model discovery via OpenRouter API
marc-romu May 3, 2026
8418e06
refactor: remove JsonInput capability and add wildcard support for Di…
marc-romu May 3, 2026
7138dc6
refactor: skip fine-tuned models and group provider models by release…
marc-romu May 3, 2026
7c59756
refactor: reorganize MistralAI models by release quarter and mark 10 …
marc-romu May 3, 2026
93c4cde
refactor: add DeepSeek v4 models and deprecate v3/reasoner models
marc-romu May 3, 2026
45767e2
refactor: add suffix-based alias grouping for OpenAI/Anthropic and no…
marc-romu May 3, 2026
ee9d426
refactor: reorganize Anthropic models by release quarter, add Claude …
marc-romu May 3, 2026
406a865
refactor: reorganize OpenAI models by release quarter, add GPT-5/o3/o…
marc-romu May 3, 2026
1115076
refactor: fix dated model aliasing to preserve distinct releases and …
marc-romu May 3, 2026
96f0b62
refactor: reorder Anthropic/MistralAI models by release quarter and a…
marc-romu May 3, 2026
eff5608
refactor: resolve OpenRouter entries by newest release when multiple …
marc-romu May 3, 2026
85d5ebe
refactor: increase non-deprecated model rank ceiling from 1000 to 10000
marc-romu May 3, 2026
2531e01
refactor: add 4000+ OpenRouter models organized by release quarter (F…
marc-romu May 3, 2026
518deb5
refactor: exclude OpenRouter from provider API queries since it uses …
marc-romu May 3, 2026
7e5eee9
refactor: add section headers and improve formatting in code review w…
marc-romu May 3, 2026
3178a45
refactor: add optional provider-api-key input for dual-source model v…
marc-romu May 3, 2026
200ed76
chore(ci): update license headers
github-actions[bot] May 3, 2026
b4dd14e
refactor: add default capability flags to claude-sonnet-4-5-20250929 …
marc-romu May 3, 2026
1941580
Potential fix for pull request finding
marc-romu May 3, 2026
c5e1ac2
Potential fix for pull request finding
marc-romu May 3, 2026
b0b0f09
refactor: add VideoInput, VideoOutput, and EmbedOutput capability fla…
marc-romu May 3, 2026
2ec97a8
refactor: normalize model ranking scale from 900-1000 to 9900-10000 r…
marc-romu May 3, 2026
5b5b931
refactor: prioritize output_modalities for detecting embedding capabi…
marc-romu May 3, 2026
5bbb073
refactor: update default capability assignments for Anthropic models …
marc-romu May 3, 2026
79a9ab0
chore(ci): update license headers
github-actions[bot] May 3, 2026
0894e47
refactor: remove trailing whitespace from comment in Update-ProviderM…
marc-romu May 3, 2026
3f972d3
refactor: replace AICapability.Embedding with AICapability.EmbedOutpu…
marc-romu May 3, 2026
91eefc4
fix(ci): normalize whitespace in provider filter check for model upda…
marc-romu May 3, 2026
f1ab0a0
refactor(ci): standardize automation label from 'automation' to 'auto…
marc-romu May 3, 2026
e8b5dc4
refactor(ci): improve model alias handling and file encoding in Updat…
marc-romu May 3, 2026
8b44e47
refactor: add -latest aliases to all OpenAI and Anthropic models, con…
marc-romu May 3, 2026
1cc86d2
chore: anonymize SmartHopperPublicKey
actions-user May 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 100 additions & 0 deletions .github/actions/ai/fetch-models/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# Reusable action that delegates to tools/Update-ProviderModels.ps1.
# OpenRouter is used as the single source of truth; the script queries
# OpenRouter's /models endpoint, filters by provider prefix, and updates
# the *ProviderModels.cs file with full capabilities mapped from metadata.
#
# Usage:
# - uses: ./.github/actions/ai/fetch-models
# with:
# provider: OpenAI
# api-key: ${{ secrets.OPENROUTER_API_KEY }}
# update-file: true

name: 'Fetch AI Provider Models'
description: 'Fetch model metadata from OpenRouter and update *ProviderModels.cs via the centralized Update-ProviderModels.ps1 tool'

inputs:
provider:
description: 'Provider identifier (e.g. OpenAI, MistralAI, Anthropic, OpenRouter, DeepSeek)'
required: true
api-key:
description: 'OpenRouter API key (used as the single source of truth for all providers)'
required: true
provider-api-key:
description: 'Optional native API key for the target provider. When supplied, the provider''s own /models endpoint is queried as a secondary authoritative source (alias merging, deprecation flags). OpenRouter remains the metadata source of truth.'
required: false
default: ''
update-file:
description: 'When true, the script rewrites the source file: auto-inserts new models with capabilities mapped from OpenRouter metadata, updates existing model capabilities/ContextLimit, and marks disappeared or expiring models as Deprecated = true'
required: false
default: 'false'

outputs:
models:
description: 'JSON array of model ID strings returned by the API'
value: ${{ steps.run.outputs.models }}
count:
description: 'Number of distinct models returned'
value: ${{ steps.run.outputs.count }}
success:
description: 'Whether the operation succeeded'
value: ${{ steps.run.outputs.success }}
error:
description: 'Error message if the call failed'
value: ${{ steps.run.outputs.error }}
report:
description: 'Full JSON report emitted by Update-ProviderModels.ps1'
value: ${{ steps.run.outputs.report }}
changed:
description: 'Whether the source file was modified'
value: ${{ steps.run.outputs.changed }}

runs:
using: 'composite'
steps:
- name: Run Update-ProviderModels.ps1
id: run
shell: pwsh
env:
API_KEY: ${{ inputs.api-key }}
PROVIDER_API_KEY: ${{ inputs.provider-api-key }}
run: |
$params = @{
Provider = '${{ inputs.provider }}'
ApiKey = $env:API_KEY
}
if (-not [string]::IsNullOrWhiteSpace($env:PROVIDER_API_KEY)) {
$params['ProviderApiKey'] = $env:PROVIDER_API_KEY
}
if ('${{ inputs.update-file }}' -eq 'true') {
$params['UpdateFile'] = $true
}

try {
$reportJson = & .\tools\Update-ProviderModels.ps1 @params
$report = $reportJson | ConvertFrom-Json

$modelsJson = ($report.apiModels | ConvertTo-Json -Compress)
if ($modelsJson -eq 'null') { $modelsJson = '[]' }

"success=true" >> $env:GITHUB_OUTPUT
"error=" >> $env:GITHUB_OUTPUT
"changed=$($report.fileUpdated)" >> $env:GITHUB_OUTPUT
"count=$($report.apiModels.Count)" >> $env:GITHUB_OUTPUT

"models<<EOF_MODELS" >> $env:GITHUB_OUTPUT
"$modelsJson" >> $env:GITHUB_OUTPUT
"EOF_MODELS" >> $env:GITHUB_OUTPUT

"report<<EOF_REPORT" >> $env:GITHUB_OUTPUT
"$reportJson" >> $env:GITHUB_OUTPUT
"EOF_REPORT" >> $env:GITHUB_OUTPUT
}
catch {
"success=false" >> $env:GITHUB_OUTPUT
"error=$($_.Exception.Message)" >> $env:GITHUB_OUTPUT
"changed=false" >> $env:GITHUB_OUTPUT
"count=0" >> $env:GITHUB_OUTPUT
"models=[]" >> $env:GITHUB_OUTPUT
"report={}" >> $env:GITHUB_OUTPUT
}
5 changes: 4 additions & 1 deletion .github/labels.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Automation Labels
- name: "automation"
- name: "automated"
color: "C0C0C0"
description: "Automatically generated by CI/CD workflows"
- name: "needs-attention"
Expand All @@ -8,6 +8,9 @@
- name: "promotion: blocked"
color: "FF4500"
description: "Promotion is blocked and requires manual intervention"
- name: "model-verification"
color: "00FF00"
description: "Model verification workflow"

# Type: Priority
- name: "priority: critical"
Expand Down
1 change: 0 additions & 1 deletion .github/workflows/chore-update-copyright-year.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ jobs:
base: dev
delete-branch: true
labels: |
chore
automated

- name: Assign PR to Milestone
Expand Down
136 changes: 136 additions & 0 deletions .github/workflows/chore-update-provider-models.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
name: 🔄 Update Provider Models

# Description: Scheduled CI that queries OpenRouter's unified /models endpoint as the
# single source of truth, then updates each provider's *ProviderModels.cs file.
# Auto-inserts new models with capabilities mapped from OpenRouter metadata
# (architecture.modalities, supported_parameters, context_length), marks models
# with expiration_date < 1 year as deprecated, and flags disappeared models.
#
# Triggers:
# - workflow_dispatch: manual run with optional provider filter
# - schedule: every Sunday 5:00 UTC

on:
schedule:
- cron: '0 5 * * 0'
workflow_dispatch:
inputs:
provider_filter:
description: 'Comma-separated provider(s) to process (empty = all)'
required: false
default: ''

permissions:
contents: write
pull-requests: write

jobs:
fetch-and-update:
name: ${{ matrix.provider }}
runs-on: windows-latest
concurrency:
group: provider-models-${{ matrix.provider }}
cancel-in-progress: false
strategy:
fail-fast: false
matrix:
include:
- provider: OpenAI
- provider: MistralAI
- provider: Anthropic
- provider: OpenRouter
- provider: DeepSeek
steps:
- name: Skip if secret is absent or filtered out
id: check
shell: bash
env:
API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
FILTER: ${{ github.event.inputs.provider_filter || '' }}
run: |
if [ -z "$API_KEY" ]; then
echo "skipped=true" >> "$GITHUB_OUTPUT"
echo "Secret OPENROUTER_API_KEY is not configured. Skipping ${{ matrix.provider }}."
elif [ -n "$FILTER" ]; then
normalized="${FILTER// /}"
if [[ ",${normalized}," != *",${{ matrix.provider }},"* ]]; then
echo "skipped=true" >> "$GITHUB_OUTPUT"
echo "Provider ${{ matrix.provider }} not in filter '$FILTER'. Skipping."
else
echo "skipped=false" >> "$GITHUB_OUTPUT"
fi
else
echo "skipped=false" >> "$GITHUB_OUTPUT"
fi

- name: Checkout main
if: steps.check.outputs.skipped == 'false'
uses: actions/checkout@v4
with:
ref: ${{ github.event.repository.default_branch }}
fetch-depth: 1

- name: Fetch and compare models for ${{ matrix.provider }}
if: steps.check.outputs.skipped == 'false'
id: models
uses: ./.github/actions/ai/fetch-models
with:
provider: ${{ matrix.provider }}
api-key: ${{ secrets.OPENROUTER_API_KEY }}
provider-api-key: ${{ (matrix.provider == 'OpenAI' && secrets.OPENAI_API_KEY) || (matrix.provider == 'MistralAI' && secrets.MISTRAL_API_KEY) || (matrix.provider == 'Anthropic' && secrets.ANTHROPIC_API_KEY) || (matrix.provider == 'DeepSeek' && secrets.DEEPSEEK_API_KEY) || '' }}
update-file: true

- name: Emit step summary
if: steps.check.outputs.skipped == 'false' && steps.models.outputs.success == 'true'
shell: pwsh
run: |
$reportJson = '${{ steps.models.outputs.report }}'
$report = $reportJson | ConvertFrom-Json
Write-Output "## ${{ matrix.provider }} model scan" >> $env:GITHUB_STEP_SUMMARY
Write-Output "- API models: $($report.apiModels.Count)" >> $env:GITHUB_STEP_SUMMARY
Write-Output "- Source models: $($report.sourceModels.Count)" >> $env:GITHUB_STEP_SUMMARY
if ($report.newModels.Count -gt 0) {
Write-Output "- **New models:** ``$($report.newModels -join ', ')``" >> $env:GITHUB_STEP_SUMMARY
}
if ($report.deprecatedModels.Count -gt 0) {
Write-Output "- **Deprecated models:** ``$($report.deprecatedModels -join ', ')``" >> $env:GITHUB_STEP_SUMMARY
}

- name: Emit no-changes summary
if: steps.check.outputs.skipped == 'false' && steps.models.outputs.success == 'true' && steps.models.outputs.changed == 'false'
shell: pwsh
run: |
Write-Output "## ${{ matrix.provider }} model scan" >> $env:GITHUB_STEP_SUMMARY
Write-Output "- API models: $($env:MODEL_COUNT)" >> $env:GITHUB_STEP_SUMMARY
Write-Output "- **No changes** detected in source file; no PR created." >> $env:GITHUB_STEP_SUMMARY
env:
MODEL_COUNT: ${{ steps.models.outputs.count }}

- name: Create Pull Request
if: steps.check.outputs.skipped == 'false' && steps.models.outputs.changed == 'true'
uses: peter-evans/create-pull-request@v6
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: "chore(models): update ${{ matrix.provider }} model list [ci skip]"
title: "chore(models): auto-add new and deprecate stale ${{ matrix.provider }} models"
body: |
Auto-generated PR from `.github/workflows/chore-update-provider-models.yml`.

### Scan results for `${{ matrix.provider }}`
````json
${{ steps.models.outputs.report }}
````

**Actions taken:**
- New models discovered via OpenRouter are auto-inserted with capabilities mapped from `architecture.modalities` and `supported_parameters`.
- Disappeared models (or models with `expiration_date` < 1 year) are marked `Deprecated = true`.
- Existing model `Capabilities` and `ContextLimit` are refreshed from OpenRouter metadata.
- `Rank` values are auto-computed from OpenRouter data: newer models rank higher, and within the same creation period cheaper output pricing ranks higher.

**Requires manual review:**
- Verify `Default` and `Verified` flags for newly added models.
branch: "chore/update-models-${{ matrix.provider }}"
base: main
delete-branch: true
labels: |
automated
1 change: 0 additions & 1 deletion .github/workflows/chore-version-date.yml
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,6 @@ jobs:
base: ${{ github.ref_name }}
delete-branch: true
labels: |
chore
automated

- name: Assign PR to Milestone
Expand Down
1 change: 0 additions & 1 deletion .github/workflows/chore-version-main-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ jobs:
base: ${{ github.event.pull_request.head.ref }}
delete-branch: true
labels: |
chore
automated

- name: Assign PR to Milestone
Expand Down
Loading
Loading