0
0
Fork 0
mirror of https://github.com/discourse/discourse.git synced 2026-08-05 16:23:34 +08:00
discourse/.skills/discourse-ai-llm-presets/SKILL.md
Rafael dos Santos Silva 78a791852b
DEV: Refresh default LLM presets and pricing (#39673)
Previously, the shipped LLM presets in `LlmPresets` had stale pricing
for `gpt-5.4` and `grok-4-fast`, missing newer models like `gpt-5.5`,
and stale OpenRouter selections.

This change refreshes context windows, pricing, vision flags, and the
OpenRouter top-weekly selection across Anthropic, Google, OpenAI, and
OpenRouter providers, and updates the corresponding `model_description`
i18n keys.

### Notable changes
- **Anthropic**: Opus 4.7 and Sonnet 4.6 context bumped to 1M.
- **Google**: `gemini-3-pro` → `gemini-3.1-pro`.
- **OpenAI**: added `gpt-5.5`; corrected `gpt-5.4` pricing (was using
gpt-5 prices); `gpt-5-nano` → `gpt-5.4-nano`; dropped `gpt-5.4-mini` to
match the 3-tier shape used by the other providers.
- **OpenRouter**: refreshed to top-weekly paid models (skipping `:free`
since those rotate out): `kimi-k2.5` → `kimi-k2.6`, `deepseek-v3.2` →
`deepseek-v4-flash`, `grok-4-fast` → `grok-4.1-fast` (also fixed pricing
— was set to grok-4 prices), `arcee-ai/trinity-large-preview:free` →
`qwen/qwen3.6-plus`. Updated pricing/vision flags on `minimax-m2.7` and
`glm-5.1`.

Pricing data sourced from `https://www.llm-prices.com/current-v1.json`
and `https://catwalk.charm.land/v2/providers`; OpenRouter selection from
the top-weekly list at
`https://openrouter.ai/models?fmt=cards&order=top-weekly&output_modalities=text`.
2026-04-30 17:02:32 -03:00

144 lines
8.9 KiB
Markdown
Vendored
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
name: discourse-ai-llm-presets
description: Use when refreshing the default LLM presets shipped with Discourse AI — model versions, pricing, context windows, vision flags, and the matching `model_description` i18n keys.
---
# Updating Discourse AI Default LLM Presets
## Overview
Discourse AI ships a curated set of LLM model presets in `plugins/discourse-ai/lib/completions/llm_presets.rb` so admins can create new LLM configurations with one click. This skill keeps them current — refreshing model IDs, pricing, context windows, and vision flags as providers evolve.
## When to Use
- A user asks to "update", "refresh", or "bump" the default LLM model presets in Discourse AI.
- A new flagship model has been released by a major provider (e.g. new GPT, Claude, or Gemini version).
- Pricing on a provider has changed and the shipped presets are stale.
## Files Involved
| Path | What lives there |
| --- | --- |
| `plugins/discourse-ai/lib/completions/llm_presets.rb` | The four provider preset blocks: `anthropic_preset`, `google_preset`, `open_ai_preset`, `open_router_preset`. |
| `plugins/discourse-ai/config/locales/client.en.yml` | One-line `model_description` strings keyed by `<provider_id>-<model_name>` with `.`/`/`/`:` replaced by `-`. Every preset model needs a matching key. |
**Out of scope for this skill:**
- `plugins/discourse-ai/config/eval-llms.yml` — internal evaluation suite. May reference older models intentionally; do not auto-update.
- Other locale files (`client.de.yml`, `client.es.yml`, …) — translations are managed via Crowdin. Only update `client.en.yml`; stale keys in other locales clean up automatically.
- Existing `LlmModel` DB rows. Preset changes only affect *new* one-click creations; previously-configured models keep working under their original names.
## Data Sources
Two primary sources, cross-reference both:
1. **`https://www.llm-prices.com/current-v1.json`** — curated pricing for first-party APIs (Anthropic, OpenAI, Google, xAI, etc.). Has `input`, `output`, and `input_cached` per 1M tokens.
2. **`https://catwalk.charm.land/v2/providers`** — broader catalog with context windows, max output tokens, vision flags, cached pricing, and provider defaults (`default_large_model_id`, `default_small_model_id`). Use for context windows and vision support that `llm-prices` omits.
For the OpenRouter provider list specifically, also use:
3. **OpenRouter top-weekly** — fetch via the frontend API since the HTML page is JS-rendered:
```
curl -s "https://openrouter.ai/api/frontend/models/find?order=top-weekly&limit=30"
```
The user's reference URL is `https://openrouter.ai/models?fmt=cards&order=top-weekly&output_modalities=text` but `WebFetch` cannot read it — go straight to the API.
## Provider Preset Structure
Each preset block is a hash with `id`, `models` (array), `tokenizer`, `endpoint`, and `provider`. Each model entry uses the `model(...)` helper:
```ruby
model(
name: "claude-sonnet-4-6", # API model name — also the lookup key
tokens: 1_000_000, # context window in tokens
display_name: "Claude Sonnet 4.6",
max_output_tokens: 64_000,
input_cost: 3.0, # USD per 1M input tokens
cached_input_cost: 0.30, # USD per 1M cached input tokens
cache_write_cost: 3.75, # Anthropic-specific
output_cost: 15.0,
vision_enabled: true,
endpoint: "...", # only when the model needs a different endpoint than the provider default
)
```
Notes:
- `cache_write_cost` is currently only set on Anthropic models (Anthropic has a separate write price).
- `vision_enabled` defaults to `false` and is only added when `true`. Trust catwalk's `supports_attachments` flag — it has been wrong in the file before (e.g. `minimax-m2.7` and `glm-5.1` were marked vision-capable but are text-only).
- Google models override `endpoint` per model because the API path encodes the model name.
- The OpenAI provider-level `endpoint:` is `chat/completions` but every model overrides it with `/responses` — leave the provider-level value alone.
## Selection Rules
### Anthropic, Google, OpenAI
- Ship a small tiered set: flagship / standard / small. Anthropic ships 3 (Opus / Sonnet / Haiku); OpenAI follows the same 3-tier pattern (e.g. GPT-5.5 / GPT-5.4 / GPT-5.4-nano). Google ships 2 (Pro / Flash).
- Avoid mid-tier overlap (e.g. shipping both `gpt-5.4` and `gpt-5.4-mini` is redundant when `gpt-5.4-nano` already covers the cheap end).
- Prefer the catwalk `default_large_model_id` and `default_small_model_id` as a hint for what the provider currently considers canonical.
### OpenRouter
- Pick the **top ~56 paid models by weekly usage** from the OpenRouter top-weekly list.
- **Skip `:free` variants** — they rotate out of OpenRouter within weeks and break presets.
- **Skip router/`~latest` aliases** (slug starts with `~`, e.g. `~anthropic/claude-sonnet-latest`) — those redirect and the underlying model can change.
- **Skip first-party Anthropic, Google, and OpenAI models** — they belong in their own provider blocks. The OpenRouter preset is for everything else (DeepSeek, Moonshot, MiniMax, Z.AI, xAI, Qwen, Arcee, etc.).
- Prefer models with vision and a sane cached-input price when ranking is close.
## i18n Keys
Every preset model needs a one-line description in `config/locales/client.en.yml` under `discourse_ai.llms.model_description`. The key format is:
```
<provider_id>-<model_name>
```
…with `.`, `/`, and `:` all replaced by `-` (handled in JS by `llm.id.replace(/[.:\/]/g, "-")` in `ai-llms-list-editor.gjs`).
Examples:
| Provider | Model `name` | i18n key |
| --- | --- | --- |
| `anthropic` | `claude-opus-4-7` | `anthropic-claude-opus-4-7` |
| `open_ai` | `gpt-5.4` | `open_ai-gpt-5-4` |
| `open_router` | `deepseek/deepseek-v4-flash` | `open_router-deepseek-deepseek-v4-flash` |
| `open_router` | `moonshotai/kimi-k2.6` | `open_router-moonshotai-kimi-k2-6` |
Whenever a model is added, renamed, or removed in `llm_presets.rb`, the matching key must be added/renamed/removed in `client.en.yml`. Missing keys silently fall through to an empty description (`I18n.lookup(..., { ignoreMissing: true })`).
## Steps
1. **Fetch source data** in parallel:
```bash
curl -s https://www.llm-prices.com/current-v1.json -o /tmp/llm_prices.json
curl -s https://catwalk.charm.land/v2/providers -o /tmp/catwalk.json
curl -s "https://openrouter.ai/api/frontend/models/find?order=top-weekly&limit=30" -o /tmp/or_top.json
```
2. **Read the current presets file** at `plugins/discourse-ai/lib/completions/llm_presets.rb`.
3. **For each first-party provider block (Anthropic / Google / OpenAI)**: cross-reference each model's `tokens`, `max_output_tokens`, all `*_cost` fields, and `vision_enabled` against catwalk + llm-prices. Catwalk wins on context windows and vision flags; llm-prices wins on first-party API pricing.
4. **For the OpenRouter block**: parse `/tmp/or_top.json`, filter out `:free`, slugs starting with `~`, and first-party Anthropic/Google/OpenAI models. Take the top 56 remaining as the new list. Pricing comes from each entry's `endpoint.pricing` (multiply by 1_000_000 for per-1M tokens).
5. **Apply edits to `llm_presets.rb`** — prefer targeted `Edit` calls per model rather than rewriting whole blocks.
6. **Update `client.en.yml`** — add/rename/remove `model_description` keys to exactly match the new model set. Diff the model `name` list before/after to make sure no key is left orphaned.
7. **Validate**:
```bash
bundle exec rubocop --force-exclusion plugins/discourse-ai/lib/completions/llm_presets.rb
ruby -ryaml -e "YAML.load_file('plugins/discourse-ai/config/locales/client.en.yml'); puts 'YAML OK'"
```
Also grep for orphaned references to any removed model names elsewhere in the plugin:
```bash
grep -rn "<old-model-name>" plugins/discourse-ai --include="*.rb" --include="*.js" --include="*.gjs" --include="*.yml" \
| grep -v lib/completions/llm_presets.rb
```
8. **Summarise the diff** to the user grouped by provider, calling out any pricing corrections (these are usually the most consequential — e.g. a model whose price had drifted vs. the provider's current price).
## Common Pitfalls
- **Forgetting the i18n keys.** Easy to miss because nothing breaks at runtime — the descriptions just go blank in the admin UI. Always update `client.en.yml` in the same commit.
- **Trusting OpenRouter pricing for first-party models.** OpenRouter aggregates many backends; for Anthropic / OpenAI / Google, prefer `llm-prices` or catwalk's first-party listing.
- **Inheriting wrong vision flags.** `vision_enabled` has been incorrect in the past — verify against catwalk every refresh.
- **Renaming a model without checking specs.** `spec/system/llms/ai_llm_spec.rb` and `lib/completions/endpoints/aws_bedrock.rb` reference Anthropic model names by string. Grep before renaming.
- **Picking unstable OpenRouter slugs.** `:free` and `~latest` alias slugs both churn faster than the release cycle of this file. Always skip them.