mirror of
https://github.com/coder/coder.git
synced 2026-11-01 04:47:17 +08:00
edd8bf8b9bbec16ec265ea58fb2c2883bf6115dc
5
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
5e0710de92 |
chore: refresh AI model price book (#28365)
## Price book changes 61 models added, 14 models removed, 51 models changed. <details> <summary>Added</summary> - azure/claude-mythos-5 - azure/claude-opus-4-7 - azure/kimi-k2.7-code - bedrock/global.openai.gpt-5.6-luna - bedrock/global.openai.gpt-5.6-sol - bedrock/global.openai.gpt-5.6-terra - bedrock/xai.grok-4.6 - copilot/gemini-3.7-flash - copilot/grok-4.6 - copilot/kimi-k3 - copilot/mai-code-1.1-flash - google/gemini-3.7-flash - openrouter/bytedance-seed/seed-2-1-turbo - openrouter/bytedance-seed/seed-2.0-code - openrouter/deepseek/deepseek-v4-pro-0813 - openrouter/dots-studio/dots-3-note-preview:free - openrouter/google/gemini-3.7-flash - openrouter/inclusionai/ling-3.0-flash - openrouter/liquid/lfm-2.5-2.6b:free - openrouter/meta/muse-glimmer-30b - openrouter/meta/muse-spark-1.2 - openrouter/nvidia/nemotron-3.5-lightning - openrouter/nvidia/nemotron-3.5-lightning:free - openrouter/qwen/qwen3.8-2.4t-a95b - openrouter/qwen/qwen3.8-27b - openrouter/sakana/sakana-namazu - openrouter/upstage/solar-pro4 - openrouter/x-ai/grok-4.6 - openrouter/z-ai/glm-5.2:free - openrouter/z-ai/glm-5.3 - openrouter/~z-ai/glm-latest - vercel/alibaba/qwen3.8-2.4t-a95b - vercel/alibaba/qwen3.8-27b - vercel/deepseek/deepseek-v4-pro-0813 - vercel/google/gemini-3.7-flash - vercel/inclusionai/ling-3.0-flash - vercel/meta/muse-glimmer-30b - vercel/meta/muse-spark-1.2 - vercel/meta/muse-spark-1.2-contributor - vercel/nvidia/nemotron-3.5-lightning - vercel/openai/gpt-4.1-fast - vercel/openai/gpt-4.1-mini-fast - vercel/openai/gpt-4.1-nano-fast - vercel/openai/gpt-4o-fast - vercel/openai/gpt-4o-mini-fast - vercel/openai/gpt-5-fast - vercel/openai/gpt-5-mini-fast - vercel/openai/gpt-5.1-thinking-fast - vercel/openai/gpt-5.2-fast - vercel/openai/gpt-5.3-codex-fast - vercel/openai/gpt-5.4-fast - vercel/openai/gpt-5.4-mini-fast - vercel/openai/gpt-5.5-fast - vercel/openai/gpt-5.6-luna-fast - vercel/openai/gpt-5.6-sol-fast - vercel/openai/gpt-5.6-terra-fast - vercel/openai/o3-fast - vercel/openai/o4-mini-fast - vercel/sakana/namazu - vercel/xai/grok-4.6 - vercel/zai/glm-5.3 </details> <details> <summary>Removed</summary> - anthropic/claude-opus-4-1 - anthropic/claude-opus-4-1-20250805 - google/gemini-2.0-flash - google/gemini-2.0-flash-lite - google/gemini-3-pro-preview - openrouter/ai21/jamba-large-1.7 - openrouter/inclusionai/ling-3.0-flash:free - openrouter/mancer/weaver - openrouter/openai/gpt-5.3-chat - vercel/anthropic/claude-opus-4.1 - vercel/inclusionai/ling-3.0-flash-free - vercel/openai/gpt-5.1-instant - vercel/openai/gpt-5.3-chat - vercel/zai/glm-4.6v </details> <details> <summary>Changed</summary> - azure/gpt-5.6-luna - azure/gpt-5.6-sol - azure/gpt-5.6-terra - bedrock/openai.gpt-5.6-sol - openrouter/deepseek/deepseek-chat-v3-0324 - openrouter/deepseek/deepseek-v3.1-terminus - openrouter/deepseek/deepseek-v4-flash - openrouter/deepseek/deepseek-v4-flash-0731 - openrouter/deepseek/deepseek-v4-pro - openrouter/google/gemini-3.6-flash - openrouter/google/gemma-4-31b-it - openrouter/gryphe/mythomax-l2-13b - openrouter/minimax/minimax-m2.5 - openrouter/minimax/minimax-m2.7 - openrouter/mistralai/mistral-small-3.2-24b-instruct - openrouter/moonshotai/kimi-k2.5 - openrouter/moonshotai/kimi-k2.6 - openrouter/moonshotai/kimi-k2.7-code - openrouter/openai/gpt-5.6-luna - openrouter/openai/gpt-5.6-luna-pro - openrouter/openai/gpt-5.6-sol - openrouter/openai/gpt-5.6-sol-pro - openrouter/openai/gpt-5.6-terra - openrouter/openai/gpt-5.6-terra-pro - openrouter/openai/gpt-oss-120b - openrouter/qwen/qwen-plus-2025-07-28:thinking - openrouter/qwen/qwen2.5-vl-72b-instruct - openrouter/qwen/qwen3-14b - openrouter/qwen/qwen3-235b-a22b-2507 - openrouter/qwen/qwen3-30b-a3b - openrouter/qwen/qwen3-coder-30b-a3b-instruct - openrouter/qwen/qwen3-vl-235b-a22b-thinking - openrouter/qwen/qwen3-vl-30b-a3b-instruct - openrouter/qwen/qwen3.5-35b-a3b - openrouter/qwen/qwen3.6-27b - openrouter/qwen/qwen3.6-35b-a3b - openrouter/tencent/hy3-preview - openrouter/thinkingmachines/inkling - openrouter/thinkingmachines/inkling-small - openrouter/z-ai/glm-5 - openrouter/z-ai/glm-5.2 - openrouter/~deepseek/deepseek-v4-flash-latest - openrouter/~google/gemini-flash-latest - openrouter/~moonshotai/kimi-latest - openrouter/~openai/gpt-latest - openrouter/~x-ai/grok-latest - vercel/deepseek/deepseek-v4-flash - vercel/deepseek/deepseek-v4-pro - vercel/google/gemini-3.6-flash - vercel/openai/gpt-5.6-sol - vercel/zai/glm-5.2 </details> ## Review notes Regenerated by `make gen/aibridge-prices` from the live [models.dev](https://models.dev) catalog. Both artifacts come from one snapshot, so they ship together: - `coderd/aibridge/prices/data/prices.json` - `site/src/pages/AgentsPage/components/ChatModelAdminPanel/knownModels/knownModelsGenerated.json` These are customer-visible cost numbers taken from upstream data, so this PR is never merged automatically. The summary above lists what moved; check the diff for exact figures before approving. Opened automatically by the [aigateway-prices-refresh workflow](https://github.com/coder/coder/actions/runs/32352560765). Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> |
||
|
|
60161fd375 |
chore: update model prices to include more providers (#27837)
Adds the full set of supported provider types to `scripts/aibridgepricesgen` and updates stored model prices. Notes: * We need to rename a few keys from models.dev JSON to match our internal provider types. * `prices.json` is now marked as generated. --------- Co-authored-by: Susana Ferreira <susana@coder.com> |
||
|
|
d57965ee7f |
chore: regenerate prices.json from models.dev (#27549)
Implements: https://linear.app/codercom/issue/AIGOV-493/update-pricesjson-with-current-model-rates-before-cost-control-release Run `make gen/aibridge-prices` to regenerate `prices.json` from `models.dev`. This update: - adds support for the upstream `claude-opus-5` model; - removes older `openai` models that have been removed upstream, keeping us in sync with `models.dev`. |
||
|
|
8eaf4f507b |
feat: generate the known-models catalog and aigateway prices (#27146)
- Regenerates `prices.json` from models.dev. The seeder only upserts, so existing deployments keep delisted models. - Generate the frontend known-models catalog instead of hand-writing it. `make gen/aibridge-prices` fetches models.dev once - Moved patches to model definitions to separate `overrides.jq` which handles both `claude-sonnet-4-5` 200k context and 'aliasing' Fable 5 as Mythos 5. - Editorial choices of selection, order, aliases, and reasoning defaults live in `curation.json`. - Adds golden join tests with one error case per validation, a no-network drift test comparing curation to the checked-in artifact, and pinned invariants for the Anthropic thinking-mode split (the wrong side returns HTTP 400) and the sonnet-4-5 context pin. Adding a model is now one `curation.json` entry plus `make gen/aibridge-prices`, assuming it is present on models.dev. > This PR was authored by Coder Agents on Cian's behalf. --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> |
||
|
|
4124d1137d |
feat: add ai_model_prices table (#24932)
# Summary Implements https://linear.app/codercom/issue/AIGOV-282/add-ai-model-price-table-and-seed-generator This PR lays the groundwork for AI Bridge cost controls (per the AI Governance RFC). It adds the foundation needed for future cost tracking: a place to store per-model token prices, a way to keep those prices in sync with upstream pricing data, and a startup mechanism that ensures every deployment has prices loaded before AI Bridge starts processing requests. The price data comes from [models.dev](https://models.dev/), a community-maintained catalogue of AI provider pricing. A generator script fetches the latest prices, filters to Anthropic and OpenAI for now, and produces a seed file checked into the repository. On every server startup the seed is applied to the database, so new releases automatically pick up any price corrections that landed since the previous one. Existing rows are overwritten with the latest prices; rows for models no longer in the seed are left untouched. # Batching the AI model price seed: three approaches Context: at server startup we seed the `ai_model_prices` table from an embedded JSON price book (~70 rows today, will grow as we add providers, potentially 4000+). Each row is: ```text (provider, model, input_price, output_price, cache_read_price, cache_write_price) ``` Any of the four price columns can be: - `NULL` → “price unknown for this dimension” - explicit `0` → “free” The batch must be an UPSERT so re-running is idempotent and existing rows pick up new prices. We considered three implementations. --- ## Approach 1 — Per-row UPSERT in a Go loop ```go for _, row := range rows { if err := db.UpsertAIModelPrice(ctx, database.UpsertAIModelPriceParams{ Provider: row.Provider, Model: row.Model, InputPrice: nullInt64(row.InputPrice), // ... }); err != nil { return err } } ``` ### Pros - Trivial. - NULL handling falls out naturally from `sql.NullInt64`. ### Cons - `N` round-trips per seed. - With ~70 rows that means ~70 statement executions on every startup, even inside a transaction. - Doesn't scale gracefully as the price book grows, potentially 4000+. --- ## Approach 2 — `UNNEST` with parallel arrays Pass each column as a separate Go slice. Postgres unnests them in parallel into a virtual table, then `INSERT ... SELECT`. ```sql INSERT INTO ai_model_prices ( provider, model, input_price, output_price, cache_read_price, cache_write_price ) SELECT UNNEST(@providers::text[]), UNNEST(@models::text[]), NULLIF(UNNEST(@input_prices::bigint[]), -1), NULLIF(UNNEST(@output_prices::bigint[]), -1), NULLIF(UNNEST(@cache_read_prices::bigint[]), -1), NULLIF(UNNEST(@cache_write_prices::bigint[]), -1) ON CONFLICT (provider, model) DO UPDATE SET input_price = EXCLUDED.input_price, output_price = EXCLUDED.output_price, cache_read_price = EXCLUDED.cache_read_price, cache_write_price = EXCLUDED.cache_write_price, updated_at = NOW(); ``` Go side: flatten rows into six parallel slices. Use a sentinel (`-1`) for “missing”, since `lib/pq` can't encode `NULL` into a `bigint[]` element. ```go providers := make([]string, len(rows)) models := make([]string, len(rows)) inputs := make([]int64, len(rows)) outputs := make([]int64, len(rows)) cacheR := make([]int64, len(rows)) cacheW := make([]int64, len(rows)) for i, r := range rows { providers[i] = r.Provider models[i] = r.Model inputs[i] = -1 if r.InputPrice != nil { inputs[i] = *r.InputPrice } outputs[i] = -1 if r.OutputPrice != nil { outputs[i] = *r.OutputPrice } cacheR[i] = -1 if r.CacheReadPrice != nil { cacheR[i] = *r.CacheReadPrice } cacheW[i] = -1 if r.CacheWritePrice != nil { cacheW[i] = *r.CacheWritePrice } } return db.UpsertAIModelPrices(ctx, database.UpsertAIModelPricesParams{ Providers: providers, Models: models, InputPrices: inputs, OutputPrices: outputs, CacheReadPrices: cacheR, CacheWritePrices: cacheW, }) ``` ### Pros - Single round-trip. ### Cons - The generated `sqlc` params become plain `[]int64`, which can't represent `NULL`. --- ## Approach 3 — `jsonb_array_elements` over a single `@seed::jsonb` (chosen) Pass the raw seed JSON as one parameter; let Postgres expand and parse it. ```sql INSERT INTO ai_model_prices ( provider, model, input_price, output_price, cache_read_price, cache_write_price ) SELECT elem->>'provider', elem->>'model', (elem->>'input_price')::bigint, (elem->>'output_price')::bigint, (elem->>'cache_read_price')::bigint, (elem->>'cache_write_price')::bigint FROM jsonb_array_elements(@seed::jsonb) AS elem ON CONFLICT (provider, model) DO UPDATE SET input_price = EXCLUDED.input_price, output_price = EXCLUDED.output_price, cache_read_price = EXCLUDED.cache_read_price, cache_write_price = EXCLUDED.cache_write_price, updated_at = NOW(); ``` Go side reduces to: ```go return db.UpsertAIModelPrices(ctx, seedJSON) ``` ### Pros - Single round-trip. - NULLs fall out naturally: - `(elem->>'cache_write_price')::bigint` becomes `NULL` - no sentinels - The seed is already JSON: - Existing precedent: - `jsonb_array_elements` is already used elsewhere in the codebase ### Cons - Less type-safe at the SQL boundary than `UNNEST` - Slightly less standard than `UNNEST` - Readers need familiarity with: - `jsonb_array_elements` - `->>` extraction syntax - Postgres pays JSON parse cost - negligible at our scale --- --- # Decision We picked Approach 3. It collapses the round-trips like `UNNEST` does, but without: - nullable-array workarounds - sentinel values |