mirror of
https://github.com/codewhale-hq/Codewhale.git
synced 2026-11-08 17:10:50 -10:00
fix(deepseek): route legacy Flash names to deepseek-flash and price them at Flash rates
DeepSeek's pricing page (https://api-docs.deepseek.com/quick_start/pricing, re-fetched 2026-10-17) now lists only deepseek-flash and deepseek-v4-pro. Footnote 1 reads: "Use deepseek-flash as the model name. The legacy names deepseek-v4-flash and deepseek-v4-flash-vision-exp are still accepted, but the corresponding models have been retired, their requests are served by the DeepSeek-V4.1-Flash model and billed at the Flash price." The 2026-09-10 entry on https://api-docs.deepseek.com/updates calls that routing temporary. Codewhale still sent the retired name in several places and priced it at the old V4 Flash rates. Routing (catalog_corrections.json is the owner; the seed was re-rendered with `scripts/catalog_models_dev.py seed render`): - DEEPSEEK_ALIAS_REPLACEMENT, the rewrite target for deepseek-chat and deepseek-reasoner, is now deepseek-flash. - The flash, deepseek-v4flash, flash-vision and deepseek-v4flashvisionexp shorthands select deepseek-flash. - official_deepseek_aliases gains deepseek-flash, deepseek-ai/deepseek-flash and deepseek/deepseek-flash. The v4-flash spellings are kept and still resolve to deepseek-v4-flash, because aggregators use that table and still host the V4 Flash weights. - The ModelRegistry selections (app-server /v1/chat/completions) restated the same rule: deepseek-chat, deepseek-reasoner, deepseek-r1/v3/v3.2 and the vision shorthands now live on a deepseek-flash row instead of the deepseek-v4-flash and vision-exp rows. - codewhale-config's deepseek_family_model_id no longer hard-codes a second copy of the shorthand map; it reads canonical_model_name from the catalog. - `codewhale model set` (crates/cli canonical_model_for_set) drops its own copy of that map and reads the same catalog group, so `model set flash` and `model set flash-vision` write deepseek-flash. `/provider <host> flash` (commands/groups/core/provider.rs) writes deepseek-flash for the flash and v4-flash shorthands. Both now agree with `model = "flash"` and `/model flash`. - auto_model FLASH_MODEL, the DeepSeek router cheap tier (RouterCandidates::deepseek) and the inventory's inert router label are deepseek-flash, so the subagent Faster lane on DeepSeek picks it too. - Because "flash" now canonicalizes to deepseek-flash, the per-provider wire maps (tui model_for_provider and config normalize_model_for_provider) map deepseek-flash to each host's V4 Flash id, as they already do for deepseek-chat. Without that, `model = "flash"` on NVIDIA NIM, Novita, SiliconFlow, SGLang, vLLM or DeepInfra would have sent deepseek-flash and failed. Fireworks gets the same arm: deepseek-flash is sent as deepseek-v4-flash, the id Codewhale sent for "flash" there before, and fireworks_bundled_fallback_pricing prices it at the hosted V4 Flash rate it had before. Wanjie Ark and Volcengine, the other hosts in the canonicalization list, pass model ids through unchanged, so they have no wire arm to add. - provider_capability treats every official DeepSeek alias as a 1M, thinking-capable route, instead of comparing against DEEPSEEK_ALIAS_REPLACEMENT, so deepseek-v4-flash keeps its caps now that the replacement constant changed. Pricing (crates/tui/src/pricing.rs): - deepseek-v4-flash is priced at the deepseek-flash rates ($0.003 hit, $0.15 miss, $0.60 output per 1M off-peak, doubled at peak) from 2026-09-10 04:00 UTC, the effective time the deepseek-flash doc comment already records. Earlier turns keep the V4 Flash rates they were billed at, so the existing 2026-08-17 rate tests stay as they are. - deepseek-flash is priced through the same time-aware lookup. A turn recorded before 2026-09-10 04:00 UTC under a shorthand that now resolves to deepseek-flash (flash, deepseek-v4flash) was sent as deepseek-v4-flash, since deepseek-flash did not exist yet, so it keeps the V4 Flash rates it was billed at instead of being repriced at Flash rates. - deepseek-v4-flash-vision-exp had no price; it is priced the same way from that instant and stays unpriced before it. It joins the first-party provider-owned allowlist. A pre-2026-09-10 turn recorded under flash-vision or deepseek-v4flashvisionexp was sent as the vision id, so the direct-route audit prices it as that id and it stays unpriced, as it was before this commit. - deepseek_time_tier now derives from the same time-aware lookup as pricing_for_model_at instead of a second hand-written id list, so the peak/off-peak chip and the receipt cannot disagree. - Pre-retirement deepseek-chat/deepseek-reasoner turns are priced as deepseek-v4-flash at their recorded time, the model that served them before 2026-07-24. Pricing them via DEEPSEEK_ALIAS_REPLACEMENT would have repriced those historical turns at Flash rates that did not exist yet. Copy: the deepseek-chat/reasoner deprecation notice now says DeepSeek retired the alias and names deepseek-flash. The Auto network hint names DeepSeek / deepseek-flash in all 15 locale packs, and the /router custom help example writes model = "deepseek-flash", matching the Fast preset. docs/CONFIGURATION.md, docs/PROVIDERS.md, docs/GUIDE.md and their zh_hans copies say the same; the PROVIDERS.md DeepSeek row no longer lists flash-vision and deepseek-v4flashvisionexp as aliases of the vision id. The CHANGELOG gets one [Unreleased] bullet, synced with scripts/sync-changelog.sh. Existing tests updated because they encoded the old ids: config/tests.rs (shorthand and deprecation replacement), lib.rs capability report, model_routing.rs (cheap tier, classifier label, decision selection), scorecard.rs (chat-alias pricing comparison), tools/subagent/tests.rs (three Faster route assertions plus the Scout row of the route matrix), fleet/scout.rs (DeepSeek scout companion), tui/views/router_setup.rs (Fast preset model), commands/groups/core/provider.rs (seven flash-shorthand switch assertions, now deepseek-flash), agent lib.rs (vision alias and reasoner resolution), app-server chat_completions.rs (retired alias target), cli lib.rs model_set_canonicalizes_deepseek_vision_aliases (the vision shorthands now write deepseek-flash), and the reviewed.rs selection count (175 -> 176). scorecard.rs direct_deepseek_compact_aliases_use_canonical_pricing and the pricing.rs alias table are unchanged from the parent commit: a 2026-08-17 "flash" turn still costs what a deepseek-v4-flash turn cost that day. Known limits, not changed here: - An explicit deepseek-v4-flash or deepseek-v4-flash-vision-exp on the direct DeepSeek route is still sent as typed. DeepSeek accepts both today and they are priced correctly, but they break when DeepSeek ends the temporary routing. - The prefixed compact spellings deepseek/deepseek-v4flash and deepseek-ai/deepseek-v4flash still resolve to deepseek-v4-flash on the direct route, while bare deepseek-v4flash resolves to deepseek-flash. - On a host whose wire map does not know deepseek-flash, `model set flash` and `/provider <host> flash` now write deepseek-flash where they wrote deepseek-v4-flash. OpenCode Go's roster has no deepseek-flash, so `/provider opencode-go flash` is now rejected as an invalid model; pass- through hosts such as Ollama or OpenModel receive deepseek-flash as typed. Use the host's own id there. By reading the resolvers (not run), `model = "flash"` and `/model flash` do not resolve to a Go model either. - An explicit deepseek-flash on an aggregator is sent as that host's V4 Flash model, which is not the V4.1 Flash DeepSeek serves; the receipt shows the wire id. - The Chinese-holiday off-peak rule and Search/Fetch per-request billing are separate slices. Verification. Source15f1804fe8plus this diff. The fix-first review changes (historical shorthand pricing, CLI and /provider shorthands, Fireworks, PROVIDERS.md rows) were verified on the final tree: - scripts/dev-test.sh config: 800 tests run, 800 passed, 1 skipped. - scripts/dev-test.sh cli: 501 tests run, 501 passed, 0 skipped (includes tests::model_set_canonicalizes_deepseek_vision_aliases and both model_set route tests). - scripts/dev-test.sh tui pricing scorecard model_routing provider config::tests: 1392 tests run, 1392 passed, 13959 skipped. That set includes scorecard::tests::direct_deepseek_compact_aliases_use_canonical_pricing, pricing::tests::deepseek_pricing_requires_exact_ids_or_explicit_route_aliases, pricing::tests::hosted_flash_and_pro_routes_price_from_bundled_docs_rates, config::tests::fireworks_flash_alias_is_not_mapped_to_undocumented_model and the seven provider.rs flash-switch tests. - A throwaway probe test, run once and deleted before this commit (1 passed), checked on DeepSeek and DeepSeek Anthropic: flash-vision, deepseek-v4flashvisionexp and the vision id are unpriced on 2026-08-17 and priced like deepseek-flash on 2026-09-21; flash, deepseek-v4flash, DEEPSEEK-V4FLASH and deepseek-flash on 2026-08-17 cost the same as deepseek-v4-flash. On Fireworks, "flash" and "deepseek-flash" price at $0.14 per 1M input and go on the wire as deepseek-v4-flash. - CI-form clippy -p codewhale-config -p codewhale-cli -p codewhale-tui --all-targets --all-features --locked -- -D warnings (with the three -A allows): exit 0, no warnings. - cargo fmt --all -- --check: clean. - scripts/sync-changelog.sh and scripts/release/check-versions.sh: ok (Version state OK, workspace 0.10.2). Earlier runs on this slice before the review fixes, not repeated because those fixes touch none of these crates' sources except the one Fireworks arm in codewhale-config, which is covered above: - scripts/dev-test.sh agent: 70 passed; app-server: 177 passed; cargo test -p codewhale-localization --lib: 54 passed; CI-form clippy for codewhale-agent, codewhale-app-server and codewhale-localization: clean. - scripts/dev-test.sh tui (full lib suite): 15326 run, 15323 passed, 3 failed, 25 skipped. The 3 failures are tools::test_runner::tests::{run_tests_succeeds_on_fresh_project, run_tests_reports_failures_without_hard_error, run_tests_cwd_scopes_cargo_to_subdir}: the nested `cargo test` they spawn fails with "Operation not permitted (os error 1)" creating a directory under /Volumes/VIXinSSD/cw-build-cache/build, also outside the agent sandbox. test_runner.rs has no model or pricing code. Not re-verified at the parent commit. - python3 scripts/catalog_models_dev.py seed render --check: ok; python3 scripts/check-provider-registry.py: passed; python3 -m pytest scripts/catalog_models_dev_test.py: 18 passed. The catalog JSON did not change in the review fixes. - Not run: feature_registry (no docs/features.toml row changed). Not regenerated: web/data/agent-docs.generated.json. `node web/scripts/check-facts.mjs` already reported it stale at15f1804fe8, before this slice, and these doc edits add to that drift. - No live DeepSeek or Fireworks request was made; routing and pricing are proven by local tests only. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01NBKbhx19BRbZtvWK8rVKjz
This commit is contained in:
1 parent
d0f6ad3697
commit
9e46b33d82
42 files changed
+245
-176
No files matched your search
@@ -7,6 +7,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
- Direct DeepSeek routes now send `deepseek-flash` for `deepseek-chat`,
|
||||
`deepseek-reasoner`, the `flash`, `deepseek-v4flash`, `flash-vision` and
|
||||
`deepseek-v4flashvisionexp` shorthands, and the Auto router's fast tier.
|
||||
`codewhale model set` and `/provider` now write `deepseek-flash` for those
|
||||
shorthands too, matching what `model = "flash"` and `/model flash` resolve
|
||||
to.
|
||||
DeepSeek has retired the V4 Flash and V4 Flash vision models. It still
|
||||
accepts `deepseek-v4-flash` and `deepseek-v4-flash-vision-exp`, but serves
|
||||
them with V4.1 Flash, bills them at the Flash price, and calls that routing
|
||||
temporary. Turns on either name from 2026-09-10 04:00 UTC are now priced at
|
||||
the Flash rates ($0.003 cache hit, $0.15 cache miss, $0.60 output per
|
||||
million tokens off-peak, doubled at peak) instead of the old V4 Flash rates,
|
||||
which overstated a cache hit by about 2.3 times. The vision name was not
|
||||
priced at all before. Earlier turns keep the rates they were billed at,
|
||||
including turns recorded under a shorthand. On NVIDIA NIM, OpenRouter,
|
||||
Novita, Fireworks, SiliconFlow, SGLang, vLLM, DeepInfra and Together,
|
||||
`deepseek-flash` selects that host's V4 Flash model, so the `flash`
|
||||
shorthand keeps working there.
|
||||
- When a `tool_search` activation pushes an earlier deferred tool out of the
|
||||
bounded conversation toolbox (8 tools, 16 KiB of schemas), the search
|
||||
result now names it under `evicted_tool_references`. Before, the tool
|
||||
|
||||
+11
-12
@@ -690,22 +690,21 @@ mod tests {
|
||||
assert!(listed.iter().any(|model| {
|
||||
model.provider == ProviderKind::Deepseek
|
||||
&& model.id == "deepseek-v4-flash-vision-exp"
|
||||
&& model.aliases
|
||||
== [
|
||||
"flash-vision".to_string(),
|
||||
"deepseek-v4flashvisionexp".to_string(),
|
||||
]
|
||||
&& model.aliases.is_empty()
|
||||
}));
|
||||
|
||||
for selector in [
|
||||
"deepseek-v4-flash-vision-exp",
|
||||
"flash-vision",
|
||||
"deepseek-v4flashvisionexp",
|
||||
for (selector, expected) in [
|
||||
(
|
||||
"deepseek-v4-flash-vision-exp",
|
||||
"deepseek-v4-flash-vision-exp",
|
||||
),
|
||||
("flash-vision", "deepseek-flash"),
|
||||
("deepseek-v4flashvisionexp", "deepseek-flash"),
|
||||
] {
|
||||
let resolved = registry.resolve_ok(Some(selector), Some(ProviderKind::Deepseek));
|
||||
assert_eq!(
|
||||
resolved.resolved.id, "deepseek-v4-flash-vision-exp",
|
||||
"{selector} must resolve to the experimental vision model"
|
||||
resolved.resolved.id, expected,
|
||||
"{selector} must resolve to {expected}"
|
||||
);
|
||||
assert_eq!(resolved.resolved.provider, ProviderKind::Deepseek);
|
||||
assert!(!resolved.used_fallback, "{selector} must not fall back");
|
||||
@@ -1565,7 +1564,7 @@ mod tests {
|
||||
let resolved = registry.resolve_ok(Some("deepseek-reasoner"), Some(ProviderKind::Deepseek));
|
||||
|
||||
assert_eq!(resolved.resolved.provider, ProviderKind::Deepseek);
|
||||
assert_eq!(resolved.resolved.id, "deepseek-v4-flash");
|
||||
assert_eq!(resolved.resolved.id, "deepseek-flash");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -1270,7 +1270,7 @@ api_key = {provider_api_key:?}
|
||||
let endpoint = resolve_endpoint(&config, ®istry, Some(alias))
|
||||
.expect("official DeepSeek route");
|
||||
assert_eq!(endpoint.provider, ProviderKind::Deepseek, "{base_url}");
|
||||
assert_eq!(endpoint.model, "deepseek-v4-flash", "{base_url} {alias}");
|
||||
assert_eq!(endpoint.model, "deepseek-flash", "{base_url} {alias}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
-10
@@ -5729,13 +5729,12 @@ fn provider_source_label(source: ProviderSource) -> String {
|
||||
}
|
||||
|
||||
fn canonical_model_for_set(model: &str) -> &str {
|
||||
match model.to_ascii_lowercase().as_str() {
|
||||
"pro" | "deepseek-v4pro" => "deepseek-v4-pro",
|
||||
"flash" | "deepseek-v4flash" => "deepseek-v4-flash",
|
||||
"flash-vision" | "deepseek-v4flashvisionexp" => "deepseek-v4-flash-vision-exp",
|
||||
"auto" => "auto",
|
||||
_ => model,
|
||||
let lower = model.to_ascii_lowercase();
|
||||
if lower == "auto" {
|
||||
return "auto";
|
||||
}
|
||||
codewhale_config::catalog::reviewed::compatibility_alias("canonical_model_name", &lower)
|
||||
.unwrap_or(model)
|
||||
}
|
||||
|
||||
/// The provider (and its endpoint) whose model `model set` writes.
|
||||
@@ -7822,10 +7821,7 @@ verbosity = "concise"
|
||||
#[test]
|
||||
fn model_set_canonicalizes_deepseek_vision_aliases() {
|
||||
for alias in ["flash-vision", "deepseek-v4flashvisionexp"] {
|
||||
assert_eq!(
|
||||
canonical_model_for_set(alias),
|
||||
"deepseek-v4-flash-vision-exp"
|
||||
);
|
||||
assert_eq!(canonical_model_for_set(alias), "deepseek-flash");
|
||||
}
|
||||
assert_eq!(
|
||||
canonical_model_for_set("deepseek-v4-flash-vision-exp"),
|
||||
|
||||
@@ -1617,6 +1617,9 @@
|
||||
"deepseek-ai/deepseek-v4pro": "deepseek-v4-pro",
|
||||
"deepseek/deepseek-v4-pro": "deepseek-v4-pro",
|
||||
"deepseek/deepseek-v4pro": "deepseek-v4-pro",
|
||||
"deepseek-flash": "deepseek-flash",
|
||||
"deepseek-ai/deepseek-flash": "deepseek-flash",
|
||||
"deepseek/deepseek-flash": "deepseek-flash",
|
||||
"deepseek-v4-flash": "deepseek-v4-flash",
|
||||
"deepseek-v4flash": "deepseek-v4-flash",
|
||||
"deepseek-ai/deepseek-v4-flash": "deepseek-v4-flash",
|
||||
@@ -1657,24 +1660,30 @@
|
||||
"provider": "deepseek"
|
||||
},
|
||||
{
|
||||
"id": "deepseek-v4-flash",
|
||||
"id": "deepseek-flash",
|
||||
"aliases": [
|
||||
"deepseek-chat",
|
||||
"deepseek-reasoner",
|
||||
"deepseek-r1",
|
||||
"deepseek-v3",
|
||||
"deepseek-v3.2"
|
||||
"deepseek-v3.2",
|
||||
"flash-vision",
|
||||
"deepseek-v4flashvisionexp"
|
||||
],
|
||||
"supports_tools": true,
|
||||
"supports_reasoning": true,
|
||||
"provider": "deepseek"
|
||||
},
|
||||
{
|
||||
"id": "deepseek-v4-flash",
|
||||
"aliases": [],
|
||||
"supports_tools": true,
|
||||
"supports_reasoning": true,
|
||||
"provider": "deepseek"
|
||||
},
|
||||
{
|
||||
"id": "deepseek-v4-flash-vision-exp",
|
||||
"aliases": [
|
||||
"flash-vision",
|
||||
"deepseek-v4flashvisionexp"
|
||||
],
|
||||
"aliases": [],
|
||||
"supports_tools": true,
|
||||
"supports_reasoning": true,
|
||||
"provider": "deepseek"
|
||||
@@ -4068,7 +4077,7 @@
|
||||
"XAI_GROK_COMPOSER_2_5_FAST_MODEL": "grok-composer-2.5-fast",
|
||||
"XAI_GROK_4_20_0309_REASONING_MODEL": "grok-4.20-0309-reasoning",
|
||||
"XAI_GROK_4_20_0309_NON_REASONING_MODEL": "grok-4.20-0309-non-reasoning",
|
||||
"DEEPSEEK_ALIAS_REPLACEMENT": "deepseek-v4-flash"
|
||||
"DEEPSEEK_ALIAS_REPLACEMENT": "deepseek-flash"
|
||||
},
|
||||
"groups": {
|
||||
"RECENT_OPENROUTER_LARGE_MODELS": [
|
||||
@@ -5725,10 +5734,10 @@
|
||||
"canonical_model_name": {
|
||||
"pro": "deepseek-v4-pro",
|
||||
"deepseek-v4pro": "deepseek-v4-pro",
|
||||
"flash": "deepseek-v4-flash",
|
||||
"deepseek-v4flash": "deepseek-v4-flash",
|
||||
"flash-vision": "deepseek-v4-flash-vision-exp",
|
||||
"deepseek-v4flashvisionexp": "deepseek-v4-flash-vision-exp"
|
||||
"flash": "deepseek-flash",
|
||||
"deepseek-v4flash": "deepseek-flash",
|
||||
"flash-vision": "deepseek-flash",
|
||||
"deepseek-v4flashvisionexp": "deepseek-flash"
|
||||
},
|
||||
"canonical_direct_deepseek_model_id": {
|
||||
"deepseek-chat": "$DEEPSEEK_ALIAS_REPLACEMENT",
|
||||
|
||||
@@ -6960,6 +6960,9 @@
|
||||
"deepseek-ai/deepseek-v4pro": "deepseek-v4-pro",
|
||||
"deepseek/deepseek-v4-pro": "deepseek-v4-pro",
|
||||
"deepseek/deepseek-v4pro": "deepseek-v4-pro",
|
||||
"deepseek-flash": "deepseek-flash",
|
||||
"deepseek-ai/deepseek-flash": "deepseek-flash",
|
||||
"deepseek/deepseek-flash": "deepseek-flash",
|
||||
"deepseek-v4-flash": "deepseek-v4-flash",
|
||||
"deepseek-v4flash": "deepseek-v4-flash",
|
||||
"deepseek-ai/deepseek-v4-flash": "deepseek-v4-flash",
|
||||
@@ -7000,24 +7003,30 @@
|
||||
"provider": "deepseek"
|
||||
},
|
||||
{
|
||||
"id": "deepseek-v4-flash",
|
||||
"id": "deepseek-flash",
|
||||
"aliases": [
|
||||
"deepseek-chat",
|
||||
"deepseek-reasoner",
|
||||
"deepseek-r1",
|
||||
"deepseek-v3",
|
||||
"deepseek-v3.2"
|
||||
"deepseek-v3.2",
|
||||
"flash-vision",
|
||||
"deepseek-v4flashvisionexp"
|
||||
],
|
||||
"supports_tools": true,
|
||||
"supports_reasoning": true,
|
||||
"provider": "deepseek"
|
||||
},
|
||||
{
|
||||
"id": "deepseek-v4-flash",
|
||||
"aliases": [],
|
||||
"supports_tools": true,
|
||||
"supports_reasoning": true,
|
||||
"provider": "deepseek"
|
||||
},
|
||||
{
|
||||
"id": "deepseek-v4-flash-vision-exp",
|
||||
"aliases": [
|
||||
"flash-vision",
|
||||
"deepseek-v4flashvisionexp"
|
||||
],
|
||||
"aliases": [],
|
||||
"supports_tools": true,
|
||||
"supports_reasoning": true,
|
||||
"provider": "deepseek"
|
||||
@@ -9411,7 +9420,7 @@
|
||||
"XAI_GROK_COMPOSER_2_5_FAST_MODEL": "grok-composer-2.5-fast",
|
||||
"XAI_GROK_4_20_0309_REASONING_MODEL": "grok-4.20-0309-reasoning",
|
||||
"XAI_GROK_4_20_0309_NON_REASONING_MODEL": "grok-4.20-0309-non-reasoning",
|
||||
"DEEPSEEK_ALIAS_REPLACEMENT": "deepseek-v4-flash"
|
||||
"DEEPSEEK_ALIAS_REPLACEMENT": "deepseek-flash"
|
||||
},
|
||||
"groups": {
|
||||
"RECENT_OPENROUTER_LARGE_MODELS": [
|
||||
@@ -11068,10 +11077,10 @@
|
||||
"canonical_model_name": {
|
||||
"pro": "deepseek-v4-pro",
|
||||
"deepseek-v4pro": "deepseek-v4-pro",
|
||||
"flash": "deepseek-v4-flash",
|
||||
"deepseek-v4flash": "deepseek-v4-flash",
|
||||
"flash-vision": "deepseek-v4-flash-vision-exp",
|
||||
"deepseek-v4flashvisionexp": "deepseek-v4-flash-vision-exp"
|
||||
"flash": "deepseek-flash",
|
||||
"deepseek-v4flash": "deepseek-flash",
|
||||
"flash-vision": "deepseek-flash",
|
||||
"deepseek-v4flashvisionexp": "deepseek-flash"
|
||||
},
|
||||
"canonical_direct_deepseek_model_id": {
|
||||
"deepseek-chat": "$DEEPSEEK_ALIAS_REPLACEMENT",
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
//!
|
||||
//! - **`deepseek-v4-pro`** — complex tasks (debugging, refactoring, design,
|
||||
//! security review, multi-file changes, code generation, …).
|
||||
//! - **`deepseek-v4-flash`** — simple tasks (lookups, formatting, small edits,
|
||||
//! - **`deepseek-flash`** — simple tasks (lookups, formatting, small edits,
|
||||
//! translation, Q&A, …).
|
||||
//!
|
||||
//! This is a pure rule-based classifier. It lives in the config crate because
|
||||
@@ -19,7 +19,7 @@
|
||||
pub const PRO_MODEL: &str = "deepseek-v4-pro";
|
||||
|
||||
/// The resolved model name for the flash tier.
|
||||
pub const FLASH_MODEL: &str = "deepseek-v4-flash";
|
||||
pub const FLASH_MODEL: &str = "deepseek-flash";
|
||||
|
||||
/// The threshold score above which a task is classified as complex (pro).
|
||||
/// Score ≥ 2 → pro, else → flash.
|
||||
|
||||
@@ -592,7 +592,7 @@ mod tests {
|
||||
fn reviewed_selection_and_transport_preserve_separate_scopes() {
|
||||
let reviewed = bundled_reviewed();
|
||||
reviewed.validate().expect("committed data");
|
||||
assert_eq!(reviewed.selections.len(), 175);
|
||||
assert_eq!(reviewed.selections.len(), 176);
|
||||
assert_eq!(reviewed.transports.len(), 123);
|
||||
let go = reviewed_transport("opencode-go", "gpt-5.6-luna").unwrap();
|
||||
assert_eq!(go.endpoint_key, "responses");
|
||||
|
||||
+26
-28
@@ -4041,16 +4041,12 @@ fn deepseek_family_model_id(model: &str) -> Option<String> {
|
||||
if trimmed.is_empty() {
|
||||
return None;
|
||||
}
|
||||
match trimmed.to_ascii_lowercase().as_str() {
|
||||
"pro" | "deepseek-v4pro" => return Some("deepseek-v4-pro".to_string()),
|
||||
"flash" | "deepseek-v4flash" => return Some("deepseek-v4-flash".to_string()),
|
||||
"flash-vision" | "deepseek-v4flashvisionexp" => {
|
||||
return Some("deepseek-v4-flash-vision-exp".to_string());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let normalized = trimmed.to_ascii_lowercase();
|
||||
if let Some(canonical) =
|
||||
crate::catalog::reviewed::compatibility_alias("canonical_model_name", &normalized)
|
||||
{
|
||||
return Some(canonical.to_string());
|
||||
}
|
||||
if !normalized.starts_with("deepseek") && !normalized.contains("/deepseek") {
|
||||
return None;
|
||||
}
|
||||
@@ -4253,43 +4249,45 @@ fn normalize_model_for_provider(provider: ProviderKind, model: &str) -> String {
|
||||
}
|
||||
(
|
||||
ProviderKind::NvidiaNim,
|
||||
"deepseek-v4-flash" | "deepseek-v4flash" | "deepseek-chat" | "deepseek-reasoner"
|
||||
| "deepseek-r1" | "deepseek-v3" | "deepseek-v3.2",
|
||||
"deepseek-flash" | "deepseek-v4-flash" | "deepseek-v4flash" | "deepseek-chat"
|
||||
| "deepseek-reasoner" | "deepseek-r1" | "deepseek-v3" | "deepseek-v3.2",
|
||||
) => DEFAULT_NVIDIA_NIM_FLASH_MODEL.to_string(),
|
||||
(ProviderKind::Openrouter, "deepseek-v4-pro" | "deepseek-v4pro") => {
|
||||
DEFAULT_OPENROUTER_MODEL.to_string()
|
||||
}
|
||||
(
|
||||
ProviderKind::Openrouter,
|
||||
"deepseek-v4-flash" | "deepseek-v4flash" | "deepseek-chat" | "deepseek-reasoner"
|
||||
| "deepseek-r1" | "deepseek-v3" | "deepseek-v3.2",
|
||||
"deepseek-flash" | "deepseek-v4-flash" | "deepseek-v4flash" | "deepseek-chat"
|
||||
| "deepseek-reasoner" | "deepseek-r1" | "deepseek-v3" | "deepseek-v3.2",
|
||||
) => DEFAULT_OPENROUTER_FLASH_MODEL.to_string(),
|
||||
(ProviderKind::Orcarouter, "deepseek-v4-pro" | "deepseek-v4pro") => {
|
||||
DEFAULT_ORCAROUTER_MODEL.to_string()
|
||||
}
|
||||
(
|
||||
ProviderKind::Orcarouter,
|
||||
"deepseek-v4-flash" | "deepseek-v4flash" | "deepseek-chat" | "deepseek-reasoner"
|
||||
| "deepseek-r1" | "deepseek-v3" | "deepseek-v3.2",
|
||||
"deepseek-flash" | "deepseek-v4-flash" | "deepseek-v4flash" | "deepseek-chat"
|
||||
| "deepseek-reasoner" | "deepseek-r1" | "deepseek-v3" | "deepseek-v3.2",
|
||||
) => DEFAULT_ORCAROUTER_FLASH_MODEL.to_string(),
|
||||
(ProviderKind::Novita, "deepseek-v4-pro" | "deepseek-v4pro") => {
|
||||
DEFAULT_NOVITA_MODEL.to_string()
|
||||
}
|
||||
(
|
||||
ProviderKind::Novita,
|
||||
"deepseek-v4-flash" | "deepseek-v4flash" | "deepseek-chat" | "deepseek-reasoner"
|
||||
| "deepseek-r1" | "deepseek-v3" | "deepseek-v3.2",
|
||||
"deepseek-flash" | "deepseek-v4-flash" | "deepseek-v4flash" | "deepseek-chat"
|
||||
| "deepseek-reasoner" | "deepseek-r1" | "deepseek-v3" | "deepseek-v3.2",
|
||||
) => DEFAULT_NOVITA_FLASH_MODEL.to_string(),
|
||||
(ProviderKind::Fireworks, "deepseek-v4-pro" | "deepseek-v4pro") => {
|
||||
DEFAULT_FIREWORKS_MODEL.to_string()
|
||||
}
|
||||
(ProviderKind::Fireworks, "deepseek-flash") => "deepseek-v4-flash".to_string(),
|
||||
(
|
||||
ProviderKind::Siliconflow | ProviderKind::SiliconflowCN,
|
||||
"deepseek-v4-pro" | "deepseek-v4pro" | "deepseek-reasoner" | "deepseek-r1",
|
||||
) => DEFAULT_SILICONFLOW_MODEL.to_string(),
|
||||
(
|
||||
ProviderKind::Siliconflow | ProviderKind::SiliconflowCN,
|
||||
"deepseek-v4-flash" | "deepseek-v4flash" | "deepseek-chat" | "deepseek-v3",
|
||||
"deepseek-flash" | "deepseek-v4-flash" | "deepseek-v4flash" | "deepseek-chat"
|
||||
| "deepseek-v3",
|
||||
) => DEFAULT_SILICONFLOW_FLASH_MODEL.to_string(),
|
||||
(
|
||||
ProviderKind::Arcee,
|
||||
@@ -4320,40 +4318,40 @@ fn normalize_model_for_provider(provider: ProviderKind, model: &str) -> String {
|
||||
}
|
||||
(
|
||||
ProviderKind::Sglang,
|
||||
"deepseek-v4-flash" | "deepseek-v4flash" | "deepseek-chat" | "deepseek-reasoner"
|
||||
| "deepseek-r1" | "deepseek-v3" | "deepseek-v3.2",
|
||||
"deepseek-flash" | "deepseek-v4-flash" | "deepseek-v4flash" | "deepseek-chat"
|
||||
| "deepseek-reasoner" | "deepseek-r1" | "deepseek-v3" | "deepseek-v3.2",
|
||||
) => DEFAULT_SGLANG_FLASH_MODEL.to_string(),
|
||||
(ProviderKind::Vllm, "deepseek-v4-pro" | "deepseek-v4pro") => {
|
||||
DEFAULT_VLLM_MODEL.to_string()
|
||||
}
|
||||
(
|
||||
ProviderKind::Vllm,
|
||||
"deepseek-v4-flash" | "deepseek-v4flash" | "deepseek-chat" | "deepseek-reasoner"
|
||||
| "deepseek-r1" | "deepseek-v3" | "deepseek-v3.2",
|
||||
"deepseek-flash" | "deepseek-v4-flash" | "deepseek-v4flash" | "deepseek-chat"
|
||||
| "deepseek-reasoner" | "deepseek-r1" | "deepseek-v3" | "deepseek-v3.2",
|
||||
) => DEFAULT_VLLM_FLASH_MODEL.to_string(),
|
||||
(ProviderKind::Huggingface, "deepseek-v4-pro" | "deepseek-v4pro") => {
|
||||
DEFAULT_HUGGINGFACE_MODEL.to_string()
|
||||
}
|
||||
(
|
||||
ProviderKind::Huggingface,
|
||||
"deepseek-v4-flash" | "deepseek-v4flash" | "deepseek-chat" | "deepseek-reasoner"
|
||||
| "deepseek-r1" | "deepseek-v3" | "deepseek-v3.2",
|
||||
"deepseek-flash" | "deepseek-v4-flash" | "deepseek-v4flash" | "deepseek-chat"
|
||||
| "deepseek-reasoner" | "deepseek-r1" | "deepseek-v3" | "deepseek-v3.2",
|
||||
) => DEFAULT_HUGGINGFACE_FLASH_MODEL.to_string(),
|
||||
(ProviderKind::Together, "deepseek-v4-pro" | "deepseek-v4pro") => {
|
||||
DEFAULT_TOGETHER_MODEL.to_string()
|
||||
}
|
||||
(
|
||||
ProviderKind::Together,
|
||||
"deepseek-v4-flash" | "deepseek-v4flash" | "deepseek-chat" | "deepseek-reasoner"
|
||||
| "deepseek-r1" | "deepseek-v3" | "deepseek-v3.2",
|
||||
"deepseek-flash" | "deepseek-v4-flash" | "deepseek-v4flash" | "deepseek-chat"
|
||||
| "deepseek-reasoner" | "deepseek-r1" | "deepseek-v3" | "deepseek-v3.2",
|
||||
) => DEFAULT_TOGETHER_FLASH_MODEL.to_string(),
|
||||
(ProviderKind::Deepinfra, "deepseek-v4-pro" | "deepseek-v4pro") => {
|
||||
DEFAULT_DEEPINFRA_MODEL.to_string()
|
||||
}
|
||||
(
|
||||
ProviderKind::Deepinfra,
|
||||
"deepseek-v4-flash" | "deepseek-v4flash" | "deepseek-chat" | "deepseek-reasoner"
|
||||
| "deepseek-r1" | "deepseek-v3" | "deepseek-v3.2",
|
||||
"deepseek-flash" | "deepseek-v4-flash" | "deepseek-v4flash" | "deepseek-chat"
|
||||
| "deepseek-reasoner" | "deepseek-r1" | "deepseek-v3" | "deepseek-v3.2",
|
||||
) => DEFAULT_DEEPINFRA_FLASH_MODEL.to_string(),
|
||||
_ => model.to_string(),
|
||||
}
|
||||
|
||||
@@ -418,7 +418,7 @@
|
||||
"ConfigActionChoose": "Enter obre les opcions",
|
||||
"ConfigActionEdit": "Enter edita",
|
||||
"ConfigActionReadOnly": "només lectura",
|
||||
"ModelPickerAutoNetworkHint": "per torn · proveïdors disponibles · petició + context recent → DeepSeek / deepseek-v4-flash",
|
||||
"ModelPickerAutoNetworkHint": "per torn · proveïdors disponibles · petició + context recent → DeepSeek / deepseek-flash",
|
||||
"ModelPickerAutoLocalHint": "per torn · heurística local · sense petició al router",
|
||||
"ModelPickerAutoLastRoute": "última {provider} · {model}",
|
||||
"AutoRouteSelectedToast": "Auto: {provider} / {model} via {source} · Ctrl+O: detalls de la ruta",
|
||||
|
||||
@@ -418,7 +418,7 @@
|
||||
"ConfigActionChoose": "Enter öffnet Auswahl",
|
||||
"ConfigActionEdit": "Enter bearbeitet",
|
||||
"ConfigActionReadOnly": "schreibgeschützt",
|
||||
"ModelPickerAutoNetworkHint": "pro Zug · lauffähige Provider · Anfrage + letzter Kontext → DeepSeek / deepseek-v4-flash",
|
||||
"ModelPickerAutoNetworkHint": "pro Zug · lauffähige Provider · Anfrage + letzter Kontext → DeepSeek / deepseek-flash",
|
||||
"ModelPickerAutoLocalHint": "pro Zug · lokale Heuristik · keine Router-Anfrage",
|
||||
"ModelPickerAutoLastRoute": "zuletzt {provider} · {model}",
|
||||
"AutoRouteSelectedToast": "Auto: {provider} / {model} via {source} · Ctrl+O: Routendetails",
|
||||
|
||||
@@ -420,7 +420,7 @@
|
||||
"ConfigActionChoose": "Enter opens choices",
|
||||
"ConfigActionEdit": "Enter edits",
|
||||
"ConfigActionReadOnly": "read only",
|
||||
"ModelPickerAutoNetworkHint": "per turn · runnable providers · request + recent context → DeepSeek / deepseek-v4-flash",
|
||||
"ModelPickerAutoNetworkHint": "per turn · runnable providers · request + recent context → DeepSeek / deepseek-flash",
|
||||
"ModelPickerAutoNetworkActiveProviderHint": "per turn · active provider only · request + recent context → {provider} / {model}",
|
||||
"ModelPickerAutoLocalHint": "per turn · local heuristic · no router request",
|
||||
"ModelPickerAutoLastRoute": "last {provider} · {model}",
|
||||
|
||||
@@ -420,7 +420,7 @@
|
||||
"ConfigActionChoose": "Enter abre las opciones",
|
||||
"ConfigActionEdit": "Enter edita",
|
||||
"ConfigActionReadOnly": "solo lectura",
|
||||
"ModelPickerAutoNetworkHint": "por turno · proveedores disponibles · solicitud + contexto reciente → DeepSeek / deepseek-v4-flash",
|
||||
"ModelPickerAutoNetworkHint": "por turno · proveedores disponibles · solicitud + contexto reciente → DeepSeek / deepseek-flash",
|
||||
"ModelPickerAutoNetworkActiveProviderHint": "por turno · solo el proveedor activo · solicitud + contexto reciente → {provider} / {model}",
|
||||
"ModelPickerAutoLocalHint": "por turno · heurística local · sin solicitud al enrutador",
|
||||
"ModelPickerAutoLastRoute": "última {provider} · {model}",
|
||||
|
||||
@@ -418,7 +418,7 @@
|
||||
"ConfigActionChoose": "Enter ouvre les choix",
|
||||
"ConfigActionEdit": "Enter modifie",
|
||||
"ConfigActionReadOnly": "lecture seule",
|
||||
"ModelPickerAutoNetworkHint": "par tour · fournisseurs exécutables · requête + contexte récent → DeepSeek / deepseek-v4-flash",
|
||||
"ModelPickerAutoNetworkHint": "par tour · fournisseurs exécutables · requête + contexte récent → DeepSeek / deepseek-flash",
|
||||
"ModelPickerAutoLocalHint": "par tour · heuristique locale · pas de requête au routeur",
|
||||
"ModelPickerAutoLastRoute": "dernière {provider} · {model}",
|
||||
"AutoRouteSelectedToast": "Auto : {provider} / {model} via {source} · Ctrl+O : détails de la route",
|
||||
|
||||
@@ -418,7 +418,7 @@
|
||||
"ConfigActionChoose": "Enter विकल्प खोलता है",
|
||||
"ConfigActionEdit": "Enter संपादित करता है",
|
||||
"ConfigActionReadOnly": "केवल पठन",
|
||||
"ModelPickerAutoNetworkHint": "प्रति टर्न · चलाने योग्य प्रोवाइडर · अनुरोध + हालिया संदर्भ → DeepSeek / deepseek-v4-flash",
|
||||
"ModelPickerAutoNetworkHint": "प्रति टर्न · चलाने योग्य प्रोवाइडर · अनुरोध + हालिया संदर्भ → DeepSeek / deepseek-flash",
|
||||
"ModelPickerAutoLocalHint": "प्रति टर्न · लोकल ह्यूरिस्टिक · कोई राउटर अनुरोध नहीं",
|
||||
"ModelPickerAutoLastRoute": "अंतिम {provider} · {model}",
|
||||
"AutoRouteSelectedToast": "Auto: {provider} / {model} ({source} द्वारा) · Ctrl+O: रूट विवरण",
|
||||
|
||||
@@ -418,7 +418,7 @@
|
||||
"ConfigActionChoose": "Enter membuka pilihan",
|
||||
"ConfigActionEdit": "Enter mengedit",
|
||||
"ConfigActionReadOnly": "hanya baca",
|
||||
"ModelPickerAutoNetworkHint": "per giliran · penyedia yang dapat dijalankan · permintaan + konteks terbaru → DeepSeek / deepseek-v4-flash",
|
||||
"ModelPickerAutoNetworkHint": "per giliran · penyedia yang dapat dijalankan · permintaan + konteks terbaru → DeepSeek / deepseek-flash",
|
||||
"ModelPickerAutoLocalHint": "per giliran · heuristik lokal · tanpa permintaan router",
|
||||
"ModelPickerAutoLastRoute": "terakhir {provider} · {model}",
|
||||
"AutoRouteSelectedToast": "Auto: {provider} / {model} via {source} · Ctrl+O: detail rute",
|
||||
|
||||
@@ -420,7 +420,7 @@
|
||||
"ConfigActionChoose": "Enter で選択肢を開く",
|
||||
"ConfigActionEdit": "Enter で編集",
|
||||
"ConfigActionReadOnly": "読み取り専用",
|
||||
"ModelPickerAutoNetworkHint": "ターンごと · 実行可能なプロバイダー · リクエスト+直近のコンテキスト → DeepSeek / deepseek-v4-flash",
|
||||
"ModelPickerAutoNetworkHint": "ターンごと · 実行可能なプロバイダー · リクエスト+直近のコンテキスト → DeepSeek / deepseek-flash",
|
||||
"ModelPickerAutoNetworkActiveProviderHint": "ターンごと · アクティブなプロバイダーのみ · リクエスト+直近のコンテキスト → {provider} / {model}",
|
||||
"ModelPickerAutoLocalHint": "ターンごと · ローカル判定 · ルーター送信なし",
|
||||
"ModelPickerAutoLastRoute": "前回 {provider} · {model}",
|
||||
|
||||
@@ -420,7 +420,7 @@
|
||||
"ConfigActionChoose": "Enter로 선택 항목 열기",
|
||||
"ConfigActionEdit": "Enter로 편집",
|
||||
"ConfigActionReadOnly": "읽기 전용",
|
||||
"ModelPickerAutoNetworkHint": "턴별 · 실행 가능한 제공자 · 요청 + 최근 컨텍스트 → DeepSeek / deepseek-v4-flash",
|
||||
"ModelPickerAutoNetworkHint": "턴별 · 실행 가능한 제공자 · 요청 + 최근 컨텍스트 → DeepSeek / deepseek-flash",
|
||||
"ModelPickerAutoNetworkActiveProviderHint": "턴별 · 활성 제공자만 · 요청 + 최근 컨텍스트 → {provider} / {model}",
|
||||
"ModelPickerAutoLocalHint": "턴별 · 로컬 휴리스틱 · 라우터 요청 없음",
|
||||
"ModelPickerAutoLastRoute": "최근 {provider} · {model}",
|
||||
|
||||
@@ -420,7 +420,7 @@
|
||||
"ConfigActionChoose": "Enter abre as opções",
|
||||
"ConfigActionEdit": "Enter edita",
|
||||
"ConfigActionReadOnly": "somente leitura",
|
||||
"ModelPickerAutoNetworkHint": "por turno · provedores executáveis · solicitação + contexto recente → DeepSeek / deepseek-v4-flash",
|
||||
"ModelPickerAutoNetworkHint": "por turno · provedores executáveis · solicitação + contexto recente → DeepSeek / deepseek-flash",
|
||||
"ModelPickerAutoNetworkActiveProviderHint": "por turno · apenas o provedor ativo · solicitação + contexto recente → {provider} / {model}",
|
||||
"ModelPickerAutoLocalHint": "por turno · heurística local · sem solicitação ao roteador",
|
||||
"ModelPickerAutoLastRoute": "última {provider} · {model}",
|
||||
|
||||
@@ -418,7 +418,7 @@
|
||||
"ConfigActionChoose": "Enter — открыть варианты",
|
||||
"ConfigActionEdit": "Enter — изменить",
|
||||
"ConfigActionReadOnly": "только чтение",
|
||||
"ModelPickerAutoNetworkHint": "на ход · готовые провайдеры · запрос + недавний контекст → DeepSeek / deepseek-v4-flash",
|
||||
"ModelPickerAutoNetworkHint": "на ход · готовые провайдеры · запрос + недавний контекст → DeepSeek / deepseek-flash",
|
||||
"ModelPickerAutoLocalHint": "на ход · локальная эвристика · без запроса к маршрутизатору",
|
||||
"ModelPickerAutoLastRoute": "последний {provider} · {model}",
|
||||
"AutoRouteSelectedToast": "Auto: {provider} / {model} через {source} · Ctrl+O: детали маршрута",
|
||||
|
||||
@@ -418,7 +418,7 @@
|
||||
"ConfigActionChoose": "Enter відкриває варіанти",
|
||||
"ConfigActionEdit": "Enter редагує",
|
||||
"ConfigActionReadOnly": "лише читання",
|
||||
"ModelPickerAutoNetworkHint": "за крок · доступні провайдери · запит + недавній контекст → DeepSeek / deepseek-v4-flash",
|
||||
"ModelPickerAutoNetworkHint": "за крок · доступні провайдери · запит + недавній контекст → DeepSeek / deepseek-flash",
|
||||
"ModelPickerAutoLocalHint": "за крок · локальна евристика · без запиту до маршрутизатора",
|
||||
"ModelPickerAutoLastRoute": "останній {provider} · {model}",
|
||||
"AutoRouteSelectedToast": "Auto: {provider} / {model} через {source} · Ctrl+O: деталі маршруту",
|
||||
|
||||
@@ -420,7 +420,7 @@
|
||||
"ConfigActionChoose": "Enter mở các lựa chọn",
|
||||
"ConfigActionEdit": "Enter để sửa",
|
||||
"ConfigActionReadOnly": "chỉ đọc",
|
||||
"ModelPickerAutoNetworkHint": "mỗi lượt · nhà cung cấp khả dụng · yêu cầu + ngữ cảnh gần đây → DeepSeek / deepseek-v4-flash",
|
||||
"ModelPickerAutoNetworkHint": "mỗi lượt · nhà cung cấp khả dụng · yêu cầu + ngữ cảnh gần đây → DeepSeek / deepseek-flash",
|
||||
"ModelPickerAutoNetworkActiveProviderHint": "mỗi lượt · chỉ nhà cung cấp đang dùng · yêu cầu + ngữ cảnh gần đây → {provider} / {model}",
|
||||
"ModelPickerAutoLocalHint": "mỗi lượt · heuristic cục bộ · không gửi yêu cầu định tuyến",
|
||||
"ModelPickerAutoLastRoute": "lần trước {provider} · {model}",
|
||||
|
||||
@@ -420,7 +420,7 @@
|
||||
"ConfigActionChoose": "按 Enter 打开选项",
|
||||
"ConfigActionEdit": "按 Enter 编辑",
|
||||
"ConfigActionReadOnly": "只读",
|
||||
"ModelPickerAutoNetworkHint": "每回合 · 可用提供商 · 请求及近期上下文 → DeepSeek / deepseek-v4-flash",
|
||||
"ModelPickerAutoNetworkHint": "每回合 · 可用提供商 · 请求及近期上下文 → DeepSeek / deepseek-flash",
|
||||
"ModelPickerAutoNetworkActiveProviderHint": "每回合 · 仅当前提供商 · 请求及近期上下文 → {provider} / {model}",
|
||||
"ModelPickerAutoLocalHint": "每回合 · 本地启发式 · 不发送路由请求",
|
||||
"ModelPickerAutoLastRoute": "上次 {provider} · {model}",
|
||||
|
||||
@@ -418,7 +418,7 @@
|
||||
"ConfigActionChoose": "按 Enter 開啟選項",
|
||||
"ConfigActionEdit": "按 Enter 編輯",
|
||||
"ConfigActionReadOnly": "唯讀",
|
||||
"ModelPickerAutoNetworkHint": "每回合 · 可用供應商 · 請求與近期上下文 → DeepSeek / deepseek-v4-flash",
|
||||
"ModelPickerAutoNetworkHint": "每回合 · 可用供應商 · 請求與近期上下文 → DeepSeek / deepseek-flash",
|
||||
"ModelPickerAutoNetworkActiveProviderHint": "每回合 · 僅目前供應商 · 請求與近期上下文 → {provider} / {model}",
|
||||
"ModelPickerAutoLocalHint": "每回合 · 本機啟發式 · 不傳送路由請求",
|
||||
"ModelPickerAutoLastRoute": "上次 {provider} · {model}",
|
||||
|
||||
@@ -7,6 +7,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
- Direct DeepSeek routes now send `deepseek-flash` for `deepseek-chat`,
|
||||
`deepseek-reasoner`, the `flash`, `deepseek-v4flash`, `flash-vision` and
|
||||
`deepseek-v4flashvisionexp` shorthands, and the Auto router's fast tier.
|
||||
`codewhale model set` and `/provider` now write `deepseek-flash` for those
|
||||
shorthands too, matching what `model = "flash"` and `/model flash` resolve
|
||||
to.
|
||||
DeepSeek has retired the V4 Flash and V4 Flash vision models. It still
|
||||
accepts `deepseek-v4-flash` and `deepseek-v4-flash-vision-exp`, but serves
|
||||
them with V4.1 Flash, bills them at the Flash price, and calls that routing
|
||||
temporary. Turns on either name from 2026-09-10 04:00 UTC are now priced at
|
||||
the Flash rates ($0.003 cache hit, $0.15 cache miss, $0.60 output per
|
||||
million tokens off-peak, doubled at peak) instead of the old V4 Flash rates,
|
||||
which overstated a cache hit by about 2.3 times. The vision name was not
|
||||
priced at all before. Earlier turns keep the rates they were billed at,
|
||||
including turns recorded under a shorthand. On NVIDIA NIM, OpenRouter,
|
||||
Novita, Fireworks, SiliconFlow, SGLang, vLLM, DeepInfra and Together,
|
||||
`deepseek-flash` selects that host's V4 Flash model, so the `flash`
|
||||
shorthand keeps working there.
|
||||
- When a `tool_search` activation pushes an earlier deferred tool out of the
|
||||
bounded conversation toolbox (8 tools, 16 KiB of schemas), the search
|
||||
result now names it under `evicted_tool_references`. Before, the tool
|
||||
|
||||
@@ -227,7 +227,7 @@ fn expand_model_alias_for_provider(provider: ProviderKind, name: &str) -> String
|
||||
|
||||
match lower.as_str() {
|
||||
"pro" | "v4-pro" => "deepseek-v4-pro".to_string(),
|
||||
"flash" | "v4-flash" => "deepseek-v4-flash".to_string(),
|
||||
"flash" | "v4-flash" => "deepseek-flash".to_string(),
|
||||
// Not a shorthand: keep the id as typed (case preserved for opaque
|
||||
// model tags on passthrough providers like Ollama/HuggingFace).
|
||||
_ => trimmed.to_string(),
|
||||
@@ -537,7 +537,7 @@ mod tests {
|
||||
match result.action {
|
||||
Some(AppAction::SwitchProvider { provider, model }) => {
|
||||
assert_eq!(provider.as_str(), ProviderKind::Siliconflow.as_str());
|
||||
assert_eq!(model.as_deref(), Some("deepseek-v4-flash"));
|
||||
assert_eq!(model.as_deref(), Some("deepseek-flash"));
|
||||
}
|
||||
other => panic!("expected SwitchProvider, got {other:?}"),
|
||||
}
|
||||
@@ -550,7 +550,7 @@ mod tests {
|
||||
match result.action {
|
||||
Some(AppAction::SwitchProvider { provider, model }) => {
|
||||
assert_eq!(provider.as_str(), ProviderKind::SiliconflowCN.as_str());
|
||||
assert_eq!(model.as_deref(), Some("deepseek-v4-flash"));
|
||||
assert_eq!(model.as_deref(), Some("deepseek-flash"));
|
||||
}
|
||||
other => panic!("expected SwitchProvider, got {other:?}"),
|
||||
}
|
||||
@@ -576,7 +576,7 @@ mod tests {
|
||||
match result.action {
|
||||
Some(AppAction::SwitchProvider { provider, model }) => {
|
||||
assert_eq!(provider.as_str(), ProviderKind::Together.as_str());
|
||||
assert_eq!(model.as_deref(), Some("deepseek-v4-flash"));
|
||||
assert_eq!(model.as_deref(), Some("deepseek-flash"));
|
||||
}
|
||||
other => panic!("expected SwitchProvider, got {other:?}"),
|
||||
}
|
||||
@@ -589,7 +589,7 @@ mod tests {
|
||||
match result.action {
|
||||
Some(AppAction::SwitchProvider { provider, model }) => {
|
||||
assert_eq!(provider.as_str(), ProviderKind::Sglang.as_str());
|
||||
assert_eq!(model.as_deref(), Some("deepseek-v4-flash"));
|
||||
assert_eq!(model.as_deref(), Some("deepseek-flash"));
|
||||
}
|
||||
other => panic!("expected SwitchProvider, got {other:?}"),
|
||||
}
|
||||
@@ -602,7 +602,7 @@ mod tests {
|
||||
match result.action {
|
||||
Some(AppAction::SwitchProvider { provider, model }) => {
|
||||
assert_eq!(provider.as_str(), ProviderKind::Vllm.as_str());
|
||||
assert_eq!(model.as_deref(), Some("deepseek-v4-flash"));
|
||||
assert_eq!(model.as_deref(), Some("deepseek-flash"));
|
||||
}
|
||||
other => panic!("expected SwitchProvider, got {other:?}"),
|
||||
}
|
||||
@@ -651,7 +651,7 @@ mod tests {
|
||||
match result.action {
|
||||
Some(AppAction::SwitchProvider { provider, model }) => {
|
||||
assert_eq!(provider.as_str(), ProviderKind::NvidiaNim.as_str());
|
||||
assert_eq!(model.as_deref(), Some("deepseek-v4-flash"));
|
||||
assert_eq!(model.as_deref(), Some("deepseek-flash"));
|
||||
}
|
||||
other => panic!("expected SwitchProvider action, got {other:?}"),
|
||||
}
|
||||
@@ -677,7 +677,7 @@ mod tests {
|
||||
match result.action {
|
||||
Some(AppAction::SwitchProvider { provider, model }) => {
|
||||
assert_eq!(provider.as_str(), ProviderKind::Deepseek.as_str());
|
||||
assert_eq!(model.as_deref(), Some("deepseek-v4-flash"));
|
||||
assert_eq!(model.as_deref(), Some("deepseek-flash"));
|
||||
}
|
||||
other => panic!("expected SwitchProvider action, got {other:?}"),
|
||||
}
|
||||
|
||||
+27
-21
@@ -366,10 +366,8 @@ pub fn provider_capability_with_wire(
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let exact_deepseek = canonical_official_deepseek_model_id(&model_lower);
|
||||
let is_v4_pro = exact_deepseek == Some("deepseek-v4-pro");
|
||||
let is_v4_flash =
|
||||
exact_deepseek == Some(DEEPSEEK_ALIAS_REPLACEMENT) || alias_deprecation.is_some();
|
||||
let official_deepseek =
|
||||
canonical_official_deepseek_model_id(&model_lower).is_some() || alias_deprecation.is_some();
|
||||
let is_reasoner = matches!(provider, ProviderKind::WanjieArk)
|
||||
&& (model_lower.contains("reasoner") || model_lower.contains("r1"));
|
||||
|
||||
@@ -377,7 +375,7 @@ pub fn provider_capability_with_wire(
|
||||
// model-only row. Reuse those facts before conservative fallback budgets.
|
||||
let offering =
|
||||
crate::provider_lake::bundled_catalog_offering_for_model(provider, resolved_model);
|
||||
let context_window = if is_v4_pro || is_v4_flash {
|
||||
let context_window = if official_deepseek {
|
||||
codewhale_models::DEEPSEEK_V4_CONTEXT_WINDOW_TOKENS
|
||||
} else if let Some(window) = codewhale_models::context_window_for_model(resolved_model) {
|
||||
window
|
||||
@@ -424,8 +422,7 @@ pub fn provider_capability_with_wire(
|
||||
});
|
||||
|
||||
// Exact catalog reasoning facts and recognized compatibility aliases only.
|
||||
let thinking_supported = is_v4_pro
|
||||
|| is_v4_flash
|
||||
let thinking_supported = official_deepseek
|
||||
|| is_reasoner
|
||||
|| offering
|
||||
.as_ref()
|
||||
@@ -467,7 +464,7 @@ fn deepseek_alias_deprecation(model_lower: &str) -> Option<ModelAliasDeprecation
|
||||
retirement_date: DEEPSEEK_ALIAS_RETIREMENT_DATE.to_string(),
|
||||
retirement_utc: DEEPSEEK_ALIAS_RETIREMENT_UTC.to_string(),
|
||||
notice: format!(
|
||||
"{model_lower} is a compatibility alias for {DEEPSEEK_ALIAS_REPLACEMENT} and is scheduled to retire on {DEEPSEEK_ALIAS_RETIREMENT_DATE}."
|
||||
"DeepSeek retired {model_lower} on {DEEPSEEK_ALIAS_RETIREMENT_DATE}; Codewhale sends {DEEPSEEK_ALIAS_REPLACEMENT} instead."
|
||||
),
|
||||
}),
|
||||
_ => None,
|
||||
@@ -476,9 +473,9 @@ fn deepseek_alias_deprecation(model_lower: &str) -> Option<ModelAliasDeprecation
|
||||
|
||||
/// Canonicalize compact DeepSeek model aliases to stable IDs.
|
||||
///
|
||||
/// Already-valid model IDs pass through unchanged. Only the compact
|
||||
/// `v4pro`/`v4flash` spellings and the experimental vision shorthand are
|
||||
/// rewritten to their hyphenated forms.
|
||||
/// Already-valid model IDs pass through unchanged. The compact `v4pro`
|
||||
/// spelling is rewritten to its hyphenated form, and the Flash and retired
|
||||
/// vision shorthands select `deepseek-flash`.
|
||||
#[must_use]
|
||||
pub fn canonical_model_name(model: &str) -> Option<&'static str> {
|
||||
codewhale_config::catalog::reviewed::compatibility_alias(
|
||||
@@ -10319,40 +10316,49 @@ fn model_for_provider(provider: ProviderKind, normalized: String) -> String {
|
||||
let lowered = normalized.to_ascii_lowercase();
|
||||
match (provider, lowered.as_str()) {
|
||||
(ProviderKind::NvidiaNim, "deepseek-v4-pro") => DEFAULT_NVIDIA_NIM_MODEL.to_string(),
|
||||
(ProviderKind::NvidiaNim, "deepseek-v4-flash") => {
|
||||
(ProviderKind::NvidiaNim, "deepseek-flash" | "deepseek-v4-flash") => {
|
||||
DEFAULT_NVIDIA_NIM_FLASH_MODEL.to_string()
|
||||
}
|
||||
(ProviderKind::Openrouter, "deepseek-v4-pro") => DEFAULT_OPENROUTER_MODEL.to_string(),
|
||||
(ProviderKind::Openrouter, "deepseek-v4-flash") => {
|
||||
(ProviderKind::Openrouter, "deepseek-flash" | "deepseek-v4-flash") => {
|
||||
DEFAULT_OPENROUTER_FLASH_MODEL.to_string()
|
||||
}
|
||||
(ProviderKind::Novita, "deepseek-v4-pro") => DEFAULT_NOVITA_MODEL.to_string(),
|
||||
(ProviderKind::Novita, "deepseek-v4-flash") => DEFAULT_NOVITA_FLASH_MODEL.to_string(),
|
||||
(ProviderKind::Novita, "deepseek-flash" | "deepseek-v4-flash") => {
|
||||
DEFAULT_NOVITA_FLASH_MODEL.to_string()
|
||||
}
|
||||
(ProviderKind::Fireworks, "deepseek-v4-pro") => DEFAULT_FIREWORKS_MODEL.to_string(),
|
||||
(ProviderKind::Fireworks, "deepseek-flash") => "deepseek-v4-flash".to_string(),
|
||||
(
|
||||
ProviderKind::Siliconflow | ProviderKind::SiliconflowCN,
|
||||
"deepseek-v4-pro" | "deepseek-reasoner" | "deepseek-r1",
|
||||
) => DEFAULT_SILICONFLOW_MODEL.to_string(),
|
||||
(
|
||||
ProviderKind::Siliconflow | ProviderKind::SiliconflowCN,
|
||||
"deepseek-v4-flash" | "deepseek-chat" | "deepseek-v3",
|
||||
"deepseek-flash" | "deepseek-v4-flash" | "deepseek-chat" | "deepseek-v3",
|
||||
) => DEFAULT_SILICONFLOW_FLASH_MODEL.to_string(),
|
||||
(ProviderKind::Sglang, "deepseek-v4-pro") => DEFAULT_SGLANG_MODEL.to_string(),
|
||||
(ProviderKind::Sglang, "deepseek-v4-flash") => DEFAULT_SGLANG_FLASH_MODEL.to_string(),
|
||||
(ProviderKind::Sglang, "deepseek-flash" | "deepseek-v4-flash") => {
|
||||
DEFAULT_SGLANG_FLASH_MODEL.to_string()
|
||||
}
|
||||
(ProviderKind::Vllm, "deepseek-v4-pro") => DEFAULT_VLLM_MODEL.to_string(),
|
||||
(ProviderKind::Vllm, "deepseek-v4-flash") => DEFAULT_VLLM_FLASH_MODEL.to_string(),
|
||||
(ProviderKind::Vllm, "deepseek-flash" | "deepseek-v4-flash") => {
|
||||
DEFAULT_VLLM_FLASH_MODEL.to_string()
|
||||
}
|
||||
(ProviderKind::Deepinfra, "deepseek-v4-pro" | "deepseek-v4pro") => {
|
||||
DEFAULT_DEEPINFRA_MODEL.to_string()
|
||||
}
|
||||
(ProviderKind::Deepinfra, "deepseek-v4-flash" | "deepseek-chat" | "deepseek-reasoner") => {
|
||||
DEFAULT_DEEPINFRA_FLASH_MODEL.to_string()
|
||||
}
|
||||
(
|
||||
ProviderKind::Deepinfra,
|
||||
"deepseek-flash" | "deepseek-v4-flash" | "deepseek-chat" | "deepseek-reasoner",
|
||||
) => DEFAULT_DEEPINFRA_FLASH_MODEL.to_string(),
|
||||
(ProviderKind::Together, "deepseek-v4-pro" | "deepseek-v4pro") => {
|
||||
DEFAULT_TOGETHER_MODEL.to_string()
|
||||
}
|
||||
(
|
||||
ProviderKind::Together,
|
||||
"deepseek-v4-flash" | "deepseek-v4flash" | "deepseek-chat" | "deepseek-reasoner",
|
||||
"deepseek-flash" | "deepseek-v4-flash" | "deepseek-v4flash" | "deepseek-chat"
|
||||
| "deepseek-reasoner",
|
||||
) => DEFAULT_TOGETHER_FLASH_MODEL.to_string(),
|
||||
(ProviderKind::Together, "inkling" | "together-inkling" | "thinkingmachines/inkling") => {
|
||||
TOGETHER_INKLING_MODEL.to_string()
|
||||
|
||||
@@ -7549,20 +7549,17 @@ fn normalize_model_name_preserves_v_series_snapshots() {
|
||||
);
|
||||
assert_eq!(
|
||||
normalize_model_name("flash").as_deref(),
|
||||
Some("deepseek-v4-flash")
|
||||
Some("deepseek-flash")
|
||||
);
|
||||
for alias in ["flash-vision", "deepseek-v4flashvisionexp"] {
|
||||
assert_eq!(
|
||||
canonical_model_name(alias),
|
||||
Some("deepseek-v4-flash-vision-exp")
|
||||
);
|
||||
assert_eq!(canonical_model_name(alias), Some("deepseek-flash"));
|
||||
assert_eq!(
|
||||
normalize_model_name(alias).as_deref(),
|
||||
Some("deepseek-v4-flash-vision-exp")
|
||||
Some("deepseek-flash")
|
||||
);
|
||||
assert_eq!(
|
||||
normalize_model_name_for_provider(ProviderKind::Deepseek, alias).as_deref(),
|
||||
Some("deepseek-v4-flash-vision-exp")
|
||||
Some("deepseek-flash")
|
||||
);
|
||||
assert!(validate_route(ProviderKind::Deepseek, alias).is_ok());
|
||||
}
|
||||
@@ -12746,7 +12743,7 @@ fn provider_capability_scenario() {
|
||||
.as_ref()
|
||||
.expect("alias deprecation metadata");
|
||||
assert_eq!(deprecation.alias, "deepseek-chat");
|
||||
assert_eq!(deprecation.replacement, "deepseek-v4-flash");
|
||||
assert_eq!(deprecation.replacement, "deepseek-flash");
|
||||
assert_eq!(deprecation.retirement_date, "2026-07-24");
|
||||
assert_eq!(deprecation.retirement_utc, "2026-07-24T15:59:00Z");
|
||||
}
|
||||
@@ -12766,7 +12763,7 @@ fn provider_capability_scenario() {
|
||||
.as_ref()
|
||||
.expect("alias deprecation metadata");
|
||||
assert_eq!(deprecation.alias, "deepseek-reasoner");
|
||||
assert_eq!(deprecation.replacement, "deepseek-v4-flash");
|
||||
assert_eq!(deprecation.replacement, "deepseek-flash");
|
||||
}
|
||||
// from provider_capability_deepseek_v4_flash_has_no_alias_deprecation
|
||||
{
|
||||
|
||||
@@ -166,11 +166,11 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn unpinned_scout_gets_verified_catalog_companion_or_inherits() {
|
||||
// DeepSeek's documented cheap sibling is deepseek-v4-flash and it is
|
||||
// DeepSeek's documented cheap sibling is deepseek-flash and it is
|
||||
// in the bundled catalog — a verified suggestion.
|
||||
let resolution = resolve_scout_route(None, "deepseek", "deepseek-v4-pro");
|
||||
assert_eq!(resolution.provider, "deepseek");
|
||||
assert_eq!(resolution.model, "deepseek-v4-flash");
|
||||
assert_eq!(resolution.model, "deepseek-flash");
|
||||
assert_eq!(resolution.source, ScoutSource::CatalogSuggestion);
|
||||
|
||||
// Anthropic's Claude models have a documented cheap sibling
|
||||
@@ -224,7 +224,7 @@ mod tests {
|
||||
fn receipt_line_names_the_source() {
|
||||
let resolution = resolve_scout_route(None, "deepseek", "deepseek-v4-pro");
|
||||
let line = resolution.receipt_line();
|
||||
assert!(line.contains("deepseek-v4-flash"), "{line}");
|
||||
assert!(line.contains("deepseek-flash"), "{line}");
|
||||
assert!(line.contains("catalog suggestion"), "{line}");
|
||||
}
|
||||
}
|
||||
@@ -16499,14 +16499,11 @@ mod doctor_endpoint_tests {
|
||||
|
||||
let report = provider_capability_report(&config);
|
||||
|
||||
assert_eq!(report["resolved_model"], "deepseek-v4-flash");
|
||||
assert_eq!(report["resolved_model"], "deepseek-flash");
|
||||
assert_eq!(report["context_window"], 1_000_000);
|
||||
assert_eq!(report["thinking_supported"], true);
|
||||
assert_eq!(report["alias_deprecation"]["alias"], "deepseek-chat");
|
||||
assert_eq!(
|
||||
report["alias_deprecation"]["replacement"],
|
||||
"deepseek-v4-flash"
|
||||
);
|
||||
assert_eq!(report["alias_deprecation"]["replacement"], "deepseek-flash");
|
||||
assert_eq!(
|
||||
report["alias_deprecation"]["retirement_utc"],
|
||||
"2026-07-24T15:59:00Z"
|
||||
|
||||
@@ -472,7 +472,7 @@ impl ModelInventory {
|
||||
(
|
||||
ProviderKind::Deepseek,
|
||||
None,
|
||||
"deepseek-v4-flash".to_string(),
|
||||
"deepseek-flash".to_string(),
|
||||
None,
|
||||
)
|
||||
});
|
||||
|
||||
@@ -39,7 +39,7 @@ impl RouterCandidates {
|
||||
pub(crate) fn deepseek() -> Self {
|
||||
Self {
|
||||
big: "deepseek-v4-pro".to_string(),
|
||||
cheap: Some("deepseek-v4-flash".to_string()),
|
||||
cheap: Some("deepseek-flash".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2798,7 +2798,7 @@ mod tests {
|
||||
AutoRouteDataPath::Classifier {
|
||||
provider: "deepseek".into(),
|
||||
provider_kind: ProviderKind::Deepseek,
|
||||
model: "deepseek-v4-flash".to_string(),
|
||||
model: "deepseek-flash".to_string(),
|
||||
}
|
||||
);
|
||||
assert_eq!(receipt.reason, AutoRouteReason::ClassifierRecommendation);
|
||||
@@ -2973,7 +2973,7 @@ mod tests {
|
||||
ref provider,
|
||||
ref model,
|
||||
..
|
||||
} if provider.as_str() == "deepseek" && model == "deepseek-v4-flash"
|
||||
} if provider.as_str() == "deepseek" && model == "deepseek-flash"
|
||||
));
|
||||
assert_eq!(
|
||||
receipt.reason,
|
||||
@@ -3184,7 +3184,7 @@ mod tests {
|
||||
|
||||
let deepseek = provider_router_candidates(ProviderKind::Deepseek, "deepseek-v4-pro");
|
||||
assert_eq!(deepseek.big, "deepseek-v4-pro");
|
||||
assert_eq!(deepseek.cheap.as_deref(), Some("deepseek-v4-flash"));
|
||||
assert_eq!(deepseek.cheap.as_deref(), Some("deepseek-flash"));
|
||||
|
||||
let openrouter =
|
||||
provider_router_candidates(ProviderKind::Openrouter, "deepseek/deepseek-v4-pro");
|
||||
@@ -3763,7 +3763,7 @@ mod decision_router_tests {
|
||||
let raw = String::from_utf8(requests[0].body.clone()).expect("utf8 body");
|
||||
assert!(!raw.contains(TYPESAFE_TEST_KEY), "TypeSafe key leaked");
|
||||
|
||||
assert_eq!(selection.model, "deepseek-v4-flash");
|
||||
assert_eq!(selection.model, "deepseek-flash");
|
||||
let receipt = receipt(&selection);
|
||||
assert_eq!(receipt.reason, AutoRouteReason::ClassifierRecommendation);
|
||||
assert_eq!(
|
||||
|
||||
+35
-13
@@ -14,8 +14,8 @@ use codewhale_config::pricing::{
|
||||
#[cfg(test)]
|
||||
use crate::config::DEFAULT_STEPFUN_MODEL;
|
||||
use crate::config::{
|
||||
DEEPSEEK_ALIAS_REPLACEMENT, DEEPSEEK_ALIAS_RETIREMENT_UTC, DEFAULT_STEPFUN_BASE_URL,
|
||||
DEFAULT_STEPFUN_PLAN_BASE_URL, ProviderKind, canonical_model_id_for_provider,
|
||||
DEEPSEEK_ALIAS_RETIREMENT_UTC, DEFAULT_STEPFUN_BASE_URL, DEFAULT_STEPFUN_PLAN_BASE_URL,
|
||||
ProviderKind, canonical_model_id_for_provider,
|
||||
};
|
||||
use codewhale_models::{Usage, has_date_snapshot_suffix};
|
||||
|
||||
@@ -721,10 +721,16 @@ fn pricing_for_model_at(model: &str, now: DateTime<Utc>) -> Option<ModelPricing>
|
||||
}
|
||||
// A new or expiring model ID does not inherit a neighboring model's
|
||||
// rates. Keep this metadata lookup as exact as the billing route owner.
|
||||
match lower.as_str() {
|
||||
deepseek_time_aware_pricing(&lower, now)
|
||||
}
|
||||
|
||||
fn deepseek_time_aware_pricing(model_lower: &str, now: DateTime<Utc>) -> Option<ModelPricing> {
|
||||
match model_lower {
|
||||
"deepseek-v4-pro" => Some(deepseek_v4_pro_pricing(now)),
|
||||
"deepseek-v4-flash" => Some(deepseek_v4_flash_pricing(now)),
|
||||
"deepseek-flash" => Some(deepseek_flash_pricing(now)),
|
||||
"deepseek-v4-flash" | "deepseek-flash" => Some(deepseek_v4_flash_pricing(now)),
|
||||
"deepseek-v4-flash-vision-exp" => {
|
||||
(now >= deepseek_flash_effective_from()).then(|| deepseek_flash_pricing(now))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@@ -965,11 +971,7 @@ fn deepseek_is_peak(now: DateTime<Utc>) -> bool {
|
||||
#[must_use]
|
||||
pub(crate) fn deepseek_time_tier(model: &str, now: DateTime<Utc>) -> Option<bool> {
|
||||
let lower = model.trim().to_ascii_lowercase();
|
||||
matches!(
|
||||
lower.as_str(),
|
||||
"deepseek-v4-pro" | "deepseek-v4-flash" | "deepseek-flash"
|
||||
)
|
||||
.then(|| deepseek_is_peak(now))
|
||||
deepseek_time_aware_pricing(&lower, now).map(|_| deepseek_is_peak(now))
|
||||
}
|
||||
|
||||
fn deepseek_v4_pro_pricing(now: DateTime<Utc>) -> ModelPricing {
|
||||
@@ -1045,7 +1047,16 @@ fn deepseek_flash_pricing(now: DateTime<Utc>) -> ModelPricing {
|
||||
}
|
||||
}
|
||||
|
||||
fn deepseek_flash_effective_from() -> DateTime<Utc> {
|
||||
Utc.with_ymd_and_hms(2026, 9, 10, 4, 0, 0)
|
||||
.single()
|
||||
.expect("2026-09-10T04:00Z is a valid UTC instant")
|
||||
}
|
||||
|
||||
fn deepseek_v4_flash_pricing(now: DateTime<Utc>) -> ModelPricing {
|
||||
if now >= deepseek_flash_effective_from() {
|
||||
return deepseek_flash_pricing(now);
|
||||
}
|
||||
let peak = deepseek_is_peak(now);
|
||||
let (hit, miss, out) = if peak {
|
||||
(0.014, 0.44, 1.32)
|
||||
@@ -1566,7 +1577,15 @@ fn audit_turn_cost_for_provider_on_endpoint_for_identity_at(
|
||||
if recorded_at >= retirement.with_timezone(&Utc) {
|
||||
return TurnCostAudit::unpriced(UnpricedReason::RetiredAlias);
|
||||
}
|
||||
DEEPSEEK_ALIAS_REPLACEMENT.to_string()
|
||||
"deepseek-v4-flash".to_string()
|
||||
} else if direct_deepseek
|
||||
&& matches!(
|
||||
model_lower.as_str(),
|
||||
"flash-vision" | "deepseek-v4flashvisionexp"
|
||||
)
|
||||
&& recorded_at < deepseek_flash_effective_from()
|
||||
{
|
||||
"deepseek-v4-flash-vision-exp".to_string()
|
||||
} else {
|
||||
canonical_model
|
||||
};
|
||||
@@ -2361,7 +2380,10 @@ fn provider_owned_hand_pricing_at(
|
||||
// just because DeepSeek does.
|
||||
matches!(
|
||||
model_lower.as_str(),
|
||||
"deepseek-v4-pro" | "deepseek-v4-flash" | "deepseek-flash"
|
||||
"deepseek-v4-pro"
|
||||
| "deepseek-v4-flash"
|
||||
| "deepseek-v4-flash-vision-exp"
|
||||
| "deepseek-flash"
|
||||
)
|
||||
}
|
||||
ProviderKind::Openai => matches!(
|
||||
@@ -2465,7 +2487,7 @@ fn provider_owned_hand_pricing_at(
|
||||
/// DeepSeek's $0.0028 cache-hit card — Fireworks publishes $0.028.
|
||||
fn fireworks_bundled_fallback_pricing(model_lower: &str) -> Option<ModelPricing> {
|
||||
match fireworks_deployment_id(model_lower) {
|
||||
"deepseek-v4-flash" | "deepseek-v4-flash-0731" => {
|
||||
"deepseek-flash" | "deepseek-v4-flash" | "deepseek-v4-flash-0731" => {
|
||||
Some(hosted_deepseek_v4_flash_standard_pricing())
|
||||
}
|
||||
"deepseek-v4-pro" => Some(hosted_deepseek_v4_pro_standard_pricing()),
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::config::ProviderKind;
|
||||
#[cfg(test)]
|
||||
use crate::config::{DEEPSEEK_ALIAS_REPLACEMENT, DEEPSEEK_ALIAS_RETIREMENT_UTC};
|
||||
use crate::config::DEEPSEEK_ALIAS_RETIREMENT_UTC;
|
||||
use crate::config::ProviderKind;
|
||||
use crate::pricing::{
|
||||
CostEstimate, TurnCostAudit, audit_turn_cost_for_route_at, token_usage_for_pricing,
|
||||
};
|
||||
@@ -1537,7 +1537,7 @@ mod tests {
|
||||
created_at: Some(&before_retirement),
|
||||
provider: Some("deepseek"),
|
||||
billing_surface: Some(crate::pricing::FIRST_PARTY_PAYG_BILLING_SURFACE),
|
||||
model: DEEPSEEK_ALIAS_REPLACEMENT.into(),
|
||||
model: "deepseek-v4-flash".into(),
|
||||
usage: &u,
|
||||
},
|
||||
TurnInput {
|
||||
|
||||
@@ -7765,7 +7765,7 @@ fn subagent_model_strength_faster_uses_known_family_sibling() {
|
||||
SubAgentThinking::Inherit,
|
||||
);
|
||||
assert_eq!(route.model_route, ModelRoute::Faster);
|
||||
assert_eq!(route.model, "deepseek-v4-flash");
|
||||
assert_eq!(route.model, "deepseek-flash");
|
||||
assert_eq!(route.reasoning_effort.as_deref(), Some("off"));
|
||||
}
|
||||
|
||||
@@ -7797,7 +7797,7 @@ fn explicit_child_thinking_overrides_faster_default_off() {
|
||||
ModelRoute::Faster,
|
||||
SubAgentThinking::Effort(ReasoningEffort::High),
|
||||
);
|
||||
assert_eq!(route.model, "deepseek-v4-flash");
|
||||
assert_eq!(route.model, "deepseek-flash");
|
||||
assert_eq!(route.reasoning_effort.as_deref(), Some("high"));
|
||||
assert_eq!(route.tuning.reasoning_effort, Some(ReasoningEffort::High));
|
||||
}
|
||||
@@ -7847,7 +7847,7 @@ async fn route_resolution_matrix_uses_explicit_model_strength_routes() {
|
||||
configured_model: None,
|
||||
requested_route: ModelRoute::Faster,
|
||||
expected_route: ModelRoute::Faster,
|
||||
expected_model: "deepseek-v4-flash",
|
||||
expected_model: "deepseek-flash",
|
||||
expected_reasoning: Some("off"),
|
||||
expected_tuning_effort: Some(ReasoningEffort::Off),
|
||||
},
|
||||
@@ -17921,7 +17921,7 @@ fn faster_route_uses_known_deepseek_and_glm_family_siblings() {
|
||||
ModelRoute::Faster,
|
||||
SubAgentThinking::Inherit,
|
||||
);
|
||||
assert_eq!(route.model, "deepseek-v4-flash");
|
||||
assert_eq!(route.model, "deepseek-flash");
|
||||
|
||||
let mut zai = stub_runtime_for_provider("zai");
|
||||
zai.model = "GLM-5.2".to_string();
|
||||
|
||||
@@ -489,7 +489,7 @@ fn custom_router_help(config: &Config, locale: Locale) -> String {
|
||||
[auto.router]\n\
|
||||
kind = \"chat\" # or \"decision\" for Jev\n\
|
||||
provider = \"deepseek\" # decision: \"openrouter\" or \"typesafe\"\n\
|
||||
model = \"deepseek-v4-flash\"\n\
|
||||
model = \"deepseek-flash\"\n\
|
||||
thinking = \"off\" # chat routers only\n\
|
||||
timeout_secs = 4\n\
|
||||
# min_confidence = 0.5 # decision routers only\n\n\
|
||||
@@ -885,7 +885,7 @@ mod tests {
|
||||
.expect("fast writes a table");
|
||||
assert_eq!(fast.kind.as_deref(), Some("chat"));
|
||||
assert_eq!(fast.provider.as_deref(), Some("deepseek"));
|
||||
assert_eq!(fast.model.as_deref(), Some("deepseek-v4-flash"));
|
||||
assert_eq!(fast.model.as_deref(), Some("deepseek-flash"));
|
||||
assert_eq!(fast.thinking.as_deref(), Some("off"));
|
||||
|
||||
assert!(matches!(
|
||||
|
||||
@@ -2117,7 +2117,7 @@ If you are upgrading from older releases:
|
||||
- Old: `/codewhale`
|
||||
New: `/links` (aliases: `/dashboard`, `/api`)
|
||||
- Old: `/set model deepseek-reasoner`
|
||||
New: `/config` and edit the `model` row to `deepseek-v4-pro` or `deepseek-v4-flash`
|
||||
New: `/config` and edit the `model` row to `deepseek-v4-pro` or `deepseek-flash`
|
||||
- Old: visible `Normal` mode or `default_mode = "normal"`
|
||||
New: use `Agent` / `default_mode = "agent"`; legacy `normal` still maps to `agent`
|
||||
- Old: discover `/set` in slash UX/help
|
||||
@@ -2153,7 +2153,7 @@ reasoning contract, and all four membership ids omit generic sampling fields.
|
||||
- `reasoning_stream_style` (string, optional provider-table key): override how streaming reasoning is separated from answer text for the active provider route. Use `separate_field` for `reasoning_content` / `reasoning` deltas, `inline_tags` for gateways that stream `<think>...</think>` inside `delta.content`, or `none` to render incoming content exactly as answer text. When unset, every Chat Completions route uses `separate_field` (Mistral's first-party route uses its typed thinking blocks); set `none` only for a gateway that streams its answer inside `reasoning_content`.
|
||||
- `[providers.<name>.auth]` (table, optional): provider-scoped auth source metadata. `source = "command"` stores a command argv plus optional `timeout_ms`; `source = "secret"` stores a `secret_id`. This slice lets provider readiness, `/provider`, and doctor JSON report the auth source class without exposing command argv output or secret values; executing commands and resolving external secret material is handled by the follow-up resolver work.
|
||||
- `insecure_skip_tls_verify` (bool, optional provider-table key): legacy compatibility key, disabled by default. When true on the active provider table, provider clients reject the configuration instead of skipping TLS certificate verification. Use `SSL_CERT_FILE` for corporate or private CA bundles; `codewhale doctor` reports stale uses of this setting.
|
||||
- `default_text_model` (string, optional): defaults to `deepseek-flash` for DeepSeek and `deepseek-anthropic`, `gpt-5.6` for OpenAI, `grok-4.6` for xAI, `deepseek-ai/deepseek-v4-pro` for NVIDIA NIM, `deepseek-ai/deepseek-v4-flash` for AtlasCloud, `deepseek-reasoner` for Wanjie Ark, `DeepSeek-V4-Pro` for Volcengine Ark, `deepseek/deepseek-v4-pro` for OpenRouter and Novita, `mimo-v2.5-pro` for Xiaomi MiMo, `accounts/fireworks/models/deepseek-v4-pro` for Fireworks, `deepseek-ai/DeepSeek-V4-Pro` for SiliconFlow and DeepInfra, `trinity-large-thinking` for Arcee AI, `kimi-k2.7-code` for Moonshot, `MiniMax-M3` for MiniMax, `GLM-5.3` for Z.ai, `step-3.7-flash` for StepFun, `ernie-4.0-turbo-8k` for Qianfan, `fugu` for Sakana AI, `deepseek-ai/DeepSeek-V4-Pro` for SGLang/vLLM, no fixed id for local Ollama (Codewhale adopts a chat-capable tag from the live local catalog — coder or tool-capable tags first, then the largest context — and never an embedding or reranker model), and `gpt-oss:120b` for Ollama Cloud. Hugging Face and Together AI both default to `deepseek-ai/DeepSeek-V4-Pro`; `openai-codex` defaults to `gpt-5.6`; `anthropic` defaults to `claude-sonnet-4-6`; `openmodel` defaults to `deepseek-v4-flash`. Current public DeepSeek IDs include `deepseek-v4-pro` and `deepseek-flash` (V4.1 Flash, shipped as the unversioned id), both with 1M context windows, 384K max output, and thinking mode enabled by default. DeepSeek's live pricing/model page now labels the Pro backend `DeepSeek-V4-Pro-0813`; the callable API ID remains `deepseek-v4-pro`, so Codewhale does not send the backend label or the Claude Code-specific `deepseek-v4-pro[1m]` selector. DeepSeek retires `deepseek-chat` and `deepseek-reasoner` on July 24, 2026; direct first-party routes migrate both to `deepseek-v4-flash`, with omitted reasoning settings preserving their former non-thinking (`off`) and thinking (`high`) intent. Explicit `reasoning_effort` wins, and provider-owned ids on Wanjie Ark, aggregators, self-hosted runtimes, and custom endpoints are not globally rewritten. SiliconFlow retains its own mapping: `deepseek-reasoner` and `deepseek-r1` select its Pro model while `deepseek-chat` and `deepseek-v3` select Flash. Provider-specific mappings translate `deepseek-v4-pro` / `deepseek-v4-flash` to each provider's model ID where supported. OpenRouter also recognizes recent large IDs such as `arcee-ai/trinity-large-thinking`, `minimax/minimax-m3`, `minimax/minimax-m2.7`, `xiaomi/mimo-v2.5-pro`, `qwen/qwen3.6-flash`, `qwen/qwen3.6-35b-a3b`, `qwen/qwen3.6-max-preview`, `qwen/qwen3.6-27b`, `qwen/qwen3.6-plus`, `qwen/qwen3.7-max`, `google/gemma-4-31b-it`, `moonshotai/kimi-k2.7-code`, `moonshotai/kimi-k2.6`, `nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free`, and `nvidia/nemotron-3-ultra-550b-a55b`; direct Arcee uses bare IDs such as `trinity-large-thinking` and `trinity-large-preview`; direct Moonshot recognizes `kimi-k3`, `kimi-k2.7-code`, and `kimi-k2.6`. The exact Kimi Code endpoint recognizes bare `k3` for K3 and `kimi-for-coding` for K2.7; those membership IDs are distinct from the direct Moonshot IDs and are never rewritten across routes. Direct MiniMax recognizes `MiniMax-M3` and the documented M2.x chat model IDs; direct Z.ai recognizes `GLM-5.3` (the default), `GLM-5.2`, `GLM-5.1`, and `GLM-5-Turbo`, and OpenRouter recognizes the matching `z-ai/glm-5.1`, `z-ai/glm-5.2`, `z-ai/glm-5.3`, and `z-ai/glm-5-turbo` IDs — `GLM-5.3` has been live on the Z.ai Coding Plan since 2026-08-13; it inherits its catalog metadata from `GLM-5.2` until Z.ai publishes distinct 5.3 numbers and carries no price, and an explicit `GLM-5.2` selection keeps its own id; direct Sakana recognizes `fugu` and `fugu-ultra-20260615`; direct Xiaomi MiMo recognizes chat IDs `mimo-v2.5-pro`, `mimo-v2.5-pro-ultraspeed`, and `mimo-v2.5`, while TTS IDs are selected through `codewhale speech` / `tts`. Generic `openai`, `atlascloud`, `wanjie-ark`, `xiaomi-mimo`, `arcee`, `moonshot`, `minimax`, `openmodel`, `zai`, `stepfun`, `qianfan`, `sakana`, local Ollama, and Ollama Cloud model IDs are passed through unchanged after known aliases are normalized. OpenRouter and SiliconFlow provider configs with a custom `base_url` also preserve explicit model values, which lets OpenAI-compatible gateways accept bare model IDs. Use `/models` or `codewhale models` to discover live IDs from your configured endpoint. `CODEWHALE_MODEL` overrides this for a single process; `DEEPSEEK_MODEL` is the legacy alias.
|
||||
- `default_text_model` (string, optional): defaults to `deepseek-flash` for DeepSeek and `deepseek-anthropic`, `gpt-5.6` for OpenAI, `grok-4.6` for xAI, `deepseek-ai/deepseek-v4-pro` for NVIDIA NIM, `deepseek-ai/deepseek-v4-flash` for AtlasCloud, `deepseek-reasoner` for Wanjie Ark, `DeepSeek-V4-Pro` for Volcengine Ark, `deepseek/deepseek-v4-pro` for OpenRouter and Novita, `mimo-v2.5-pro` for Xiaomi MiMo, `accounts/fireworks/models/deepseek-v4-pro` for Fireworks, `deepseek-ai/DeepSeek-V4-Pro` for SiliconFlow and DeepInfra, `trinity-large-thinking` for Arcee AI, `kimi-k2.7-code` for Moonshot, `MiniMax-M3` for MiniMax, `GLM-5.3` for Z.ai, `step-3.7-flash` for StepFun, `ernie-4.0-turbo-8k` for Qianfan, `fugu` for Sakana AI, `deepseek-ai/DeepSeek-V4-Pro` for SGLang/vLLM, no fixed id for local Ollama (Codewhale adopts a chat-capable tag from the live local catalog — coder or tool-capable tags first, then the largest context — and never an embedding or reranker model), and `gpt-oss:120b` for Ollama Cloud. Hugging Face and Together AI both default to `deepseek-ai/DeepSeek-V4-Pro`; `openai-codex` defaults to `gpt-5.6`; `anthropic` defaults to `claude-sonnet-4-6`; `openmodel` defaults to `deepseek-v4-flash`. Current public DeepSeek IDs include `deepseek-v4-pro` and `deepseek-flash` (V4.1 Flash, shipped as the unversioned id), both with 1M context windows, 384K max output, and thinking mode enabled by default. DeepSeek's live pricing/model page now labels the Pro backend `DeepSeek-V4-Pro-0813`; the callable API ID remains `deepseek-v4-pro`, so Codewhale does not send the backend label or the Claude Code-specific `deepseek-v4-pro[1m]` selector. DeepSeek retired `deepseek-chat` and `deepseek-reasoner` on July 24, 2026; direct first-party routes migrate both to `deepseek-flash`, with omitted reasoning settings preserving their former non-thinking (`off`) and thinking (`high`) intent. DeepSeek has also retired the `deepseek-v4-flash` and `deepseek-v4-flash-vision-exp` models: it still accepts both names, serves them with V4.1 Flash, and bills them at the `deepseek-flash` price, which Codewhale applies to turns from 2026-09-10 04:00 UTC. The `flash`, `deepseek-v4flash`, `flash-vision`, and `deepseek-v4flashvisionexp` shorthands select `deepseek-flash`. Explicit `reasoning_effort` wins, and provider-owned ids on Wanjie Ark, aggregators, self-hosted runtimes, and custom endpoints are not globally rewritten. SiliconFlow retains its own mapping: `deepseek-reasoner` and `deepseek-r1` select its Pro model while `deepseek-chat` and `deepseek-v3` select Flash. Provider-specific mappings translate `deepseek-v4-pro` / `deepseek-v4-flash` to each provider's model ID where supported. OpenRouter also recognizes recent large IDs such as `arcee-ai/trinity-large-thinking`, `minimax/minimax-m3`, `minimax/minimax-m2.7`, `xiaomi/mimo-v2.5-pro`, `qwen/qwen3.6-flash`, `qwen/qwen3.6-35b-a3b`, `qwen/qwen3.6-max-preview`, `qwen/qwen3.6-27b`, `qwen/qwen3.6-plus`, `qwen/qwen3.7-max`, `google/gemma-4-31b-it`, `moonshotai/kimi-k2.7-code`, `moonshotai/kimi-k2.6`, `nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free`, and `nvidia/nemotron-3-ultra-550b-a55b`; direct Arcee uses bare IDs such as `trinity-large-thinking` and `trinity-large-preview`; direct Moonshot recognizes `kimi-k3`, `kimi-k2.7-code`, and `kimi-k2.6`. The exact Kimi Code endpoint recognizes bare `k3` for K3 and `kimi-for-coding` for K2.7; those membership IDs are distinct from the direct Moonshot IDs and are never rewritten across routes. Direct MiniMax recognizes `MiniMax-M3` and the documented M2.x chat model IDs; direct Z.ai recognizes `GLM-5.3` (the default), `GLM-5.2`, `GLM-5.1`, and `GLM-5-Turbo`, and OpenRouter recognizes the matching `z-ai/glm-5.1`, `z-ai/glm-5.2`, `z-ai/glm-5.3`, and `z-ai/glm-5-turbo` IDs — `GLM-5.3` has been live on the Z.ai Coding Plan since 2026-08-13; it inherits its catalog metadata from `GLM-5.2` until Z.ai publishes distinct 5.3 numbers and carries no price, and an explicit `GLM-5.2` selection keeps its own id; direct Sakana recognizes `fugu` and `fugu-ultra-20260615`; direct Xiaomi MiMo recognizes chat IDs `mimo-v2.5-pro`, `mimo-v2.5-pro-ultraspeed`, and `mimo-v2.5`, while TTS IDs are selected through `codewhale speech` / `tts`. Generic `openai`, `atlascloud`, `wanjie-ark`, `xiaomi-mimo`, `arcee`, `moonshot`, `minimax`, `openmodel`, `zai`, `stepfun`, `qianfan`, `sakana`, local Ollama, and Ollama Cloud model IDs are passed through unchanged after known aliases are normalized. OpenRouter and SiliconFlow provider configs with a custom `base_url` also preserve explicit model values, which lets OpenAI-compatible gateways accept bare model IDs. Use `/models` or `codewhale models` to discover live IDs from your configured endpoint. `CODEWHALE_MODEL` overrides this for a single process; `DEEPSEEK_MODEL` is the legacy alias.
|
||||
- TelecomJS uses `deepseek-v4-pro` only as a conservative pre-refresh fallback. Once its key-scoped `/models` catalog is available, the picker uses those live rows; Codewhale omits unsupported reasoning request fields on this route.
|
||||
- `reasoning_effort` (string, optional): `auto`, `off`, `minimal`, `low`, `medium`, `high`, `xhigh`, `ultra` (`ultracode` is an alias of `ultra`), or `max`; defaults to the configured UI tier. DeepSeek Platform receives top-level `thinking` / `reasoning_effort` fields. Ollama Cloud's OpenAI-compatible Chat Completions route preserves its documented `none` / `low` / `medium` / `high` / `max` ladder (`off` is sent as `none`; `xhigh` and `ultracode` normalize to `max`). Direct xAI `grok-4.7` and `grok-4.6` on exact `https://api.x.ai/v1` receive top-level `reasoning_effort = "low" | "medium" | "high" | "xhigh"` (the ladder comes from the bundled catalog row; `grok-4.5` maps `xhigh` to `high`, and rows without a documented effort such as `grok-4.3` get no field); Grok reasoning cannot be disabled, so `off` normalizes to `high`, `max`/`ultracode` to `xhigh`, and `auto` leaves the field omitted so xAI's documented default `high` applies. A custom xAI-compatible `base_url` does not inherit that dialect. Direct Moonshot `kimi-k3` on exact `https://api.moonshot.ai/v1` is always-thinking and receives only top-level `reasoning_effort = "low" | "high" | "max"`; `off` normalizes to `low`, and `medium` to `high`. Kimi Code membership `k3` on exact `https://api.kimi.com/coding/v1` instead receives nested `thinking.effort`, and its `off` setting also normalizes to enabled `low`. Normal dispatched `auto` uses Codewhale's auto-reasoning selector and sends a concrete route-normalized tier; only an omitted reasoning setting leaves the provider default in control. Neighboring gateways and model/endpoint combinations retain the generic Moonshot contract. OpenAI Codex normalizes stale `off` to `low` and sends `max` / `ultracode` as Responses `xhigh`. Z.ai receives documented `thinking` controls and treats enabled thinking as the GLM coding high/max lane. NVIDIA NIM receives equivalent settings through `chat_template_kwargs`.
|
||||
- `verbosity` (string, optional): `normal` or `concise`. `normal` keeps the
|
||||
|
||||
+1
-1
@@ -425,7 +425,7 @@ level per turn. When the DeepSeek routing model is available, Auto may select
|
||||
any runnable provider/model pair in the redacted inventory. That classification
|
||||
sends the latest request (capped at 4,000 characters) plus a bounded summary of
|
||||
up to six recent context rows (900 characters each) to
|
||||
`DeepSeek / deepseek-v4-flash`. Credentials, endpoints, and provider error text
|
||||
`DeepSeek / deepseek-flash`. Credentials, endpoints, and provider error text
|
||||
are not included in the inventory. Without that router, Auto uses a local,
|
||||
provider-aware heuristic and sends no routing request. If a classifier attempt
|
||||
fails validation or errors, Auto falls back to that heuristic while retaining
|
||||
|
||||
+3
-3
@@ -817,7 +817,7 @@ overlay and lets DSH resolve its own keys.
|
||||
|
||||
| Provider ID | TOML table | Auth env | Base URL env and default | Default or static models | Notes |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `deepseek` | `[providers.deepseek]` | `DEEPSEEK_API_KEY` | `CODEWHALE_BASE_URL` / `DEEPSEEK_BASE_URL`; default `https://api.deepseek.com/beta` | `deepseek-flash` (shipped default; V4.1 Flash, unversioned id), `deepseek-v4-pro`, `deepseek-v4-flash`, experimental `deepseek-v4-flash-vision-exp`; vision aliases `flash-vision`, `deepseek-v4flashvisionexp`; compatibility aliases `deepseek-chat`, `deepseek-reasoner` | First-class default. The live Pro backend is labeled `DeepSeek-V4-Pro-0813`; the callable API ID remains `deepseek-v4-pro`. Beta URL enables strict tool mode, chat prefix completion, and FIM completion. The documented V4 routes can use provider-native web search through a separate bounded Responses request; compatible custom endpoints do not inherit that capability. Set `https://api.deepseek.com` or `/v1` explicitly to opt out of beta-only features. The shipped default `deepseek-flash` speaks the Responses API (DeepSeek's documented path for Codex-style integration, since the 2026-07-31 Flash production update); the Chat-only controls (the `thinking` toggle and strict-tool `/beta` routing) apply to Chat Completions routes, and `deepseek-v4-pro` stays on Chat Completions until its announced Responses rollout. Reasoning effort follows DeepSeek's documented requested-to-actual mapping: `minimal`/`low` land on `low`, `medium`/`xhigh` on `high`, and `max`/`ultra` on `max`; `off` disables thinking (`thinking: {"type":"disabled"}` on Chat, `reasoning.effort: "none"` on Responses). The experimental vision ID was observed in the authenticated `/models` roster on 2026-08-21 and is advertised as image-input capable on the direct Chat Completions route only. Its limits, reasoning, and tool-call flags provisionally inherit Flash; pricing remains unknown, and no funded image round trip was made during this release work. |
|
||||
| `deepseek` | `[providers.deepseek]` | `DEEPSEEK_API_KEY` | `CODEWHALE_BASE_URL` / `DEEPSEEK_BASE_URL`; default `https://api.deepseek.com/beta` | `deepseek-flash` (shipped default; V4.1 Flash, unversioned id), `deepseek-v4-pro`, `deepseek-v4-flash`, experimental `deepseek-v4-flash-vision-exp`; compatibility aliases `deepseek-chat`, `deepseek-reasoner` | First-class default. The live Pro backend is labeled `DeepSeek-V4-Pro-0813`; the callable API ID remains `deepseek-v4-pro`. Beta URL enables strict tool mode, chat prefix completion, and FIM completion. The documented V4 routes can use provider-native web search through a separate bounded Responses request; compatible custom endpoints do not inherit that capability. Set `https://api.deepseek.com` or `/v1` explicitly to opt out of beta-only features. The shipped default `deepseek-flash` speaks the Responses API (DeepSeek's documented path for Codex-style integration, since the 2026-07-31 Flash production update); the Chat-only controls (the `thinking` toggle and strict-tool `/beta` routing) apply to Chat Completions routes, and `deepseek-v4-pro` stays on Chat Completions until its announced Responses rollout. Reasoning effort follows DeepSeek's documented requested-to-actual mapping: `minimal`/`low` land on `low`, `medium`/`xhigh` on `high`, and `max`/`ultra` on `max`; `off` disables thinking (`thinking: {"type":"disabled"}` on Chat, `reasoning.effort: "none"` on Responses). The experimental vision ID was observed in the authenticated `/models` roster on 2026-08-21 and is advertised as image-input capable on the direct Chat Completions route only. Its limits, reasoning, and tool-call flags provisionally inherit Flash, and no funded image round trip was made during this release work. DeepSeek has since retired both `deepseek-v4-flash` and the vision ID; it still accepts them, serves them with V4.1 Flash, and bills them at the `deepseek-flash` price, which Codewhale applies from 2026-09-10 04:00 UTC. The `flash`, `deepseek-v4flash`, `flash-vision`, and `deepseek-v4flashvisionexp` shorthands now select `deepseek-flash`. |
|
||||
| `deepseek-anthropic` | `[providers.deepseek_anthropic]` | `DEEPSEEK_API_KEY` | `DEEPSEEK_ANTHROPIC_BASE_URL`; default `https://api.deepseek.com/anthropic` | `deepseek-v4-pro`, `deepseek-v4-flash`; compatibility aliases `deepseek-chat`, `deepseek-reasoner` | Opt-in DeepSeek route for the Anthropic Messages wire protocol. Uses `/v1/messages`, `x-api-key`, and `anthropic-version: 2023-06-01`. Keep `provider = "deepseek"` for the default Chat Completions path. |
|
||||
| `nvidia-nim` | `[providers.nvidia_nim]` | `NVIDIA_API_KEY`, `NVIDIA_NIM_API_KEY` | `NVIDIA_NIM_BASE_URL`, `NIM_BASE_URL`, `NVIDIA_BASE_URL`; default `https://integrate.api.nvidia.com/v1` | `deepseek-ai/deepseek-v4-pro`, `deepseek-ai/deepseek-v4-flash` | Hosted DeepSeek V4 through NVIDIA NIM. `NVIDIA_NIM_MODEL` is accepted by the TUI config path. |
|
||||
| `openai` | `[providers.openai]` | `OPENAI_API_KEY` | `OPENAI_BASE_URL`; default `https://api.openai.com/v1` | `gpt-5.6` (default), `gpt-5.6-sol`, `gpt-5.6-terra`, `gpt-5.6-luna` | Generic OpenAI-compatible route whose built-in endpoint and fallback catalog are native to OpenAI. The [GPT-5.6 family](https://developers.openai.com/api/docs/models/gpt-5.6-sol) uses OpenAI's documented 1.05M context, 128K max output, and reasoning levels. Custom gateways remain free to select an explicit gateway-owned model. `OPENAI_MODEL` is accepted. |
|
||||
@@ -1335,8 +1335,8 @@ Changing `provider`, `base_url`, or `model` can select a route that supports the
|
||||
OpenAI-compatible payload shape, but Codewhale cannot convert arbitrary JSON
|
||||
text into a trusted tool call after the model has emitted it as prose.
|
||||
|
||||
DeepSeek will retire `deepseek-chat` and `deepseek-reasoner` on 2026-07-24 at
|
||||
15:59 UTC. Codewhale migrates either name to `deepseek-v4-flash` before a
|
||||
DeepSeek retired `deepseek-chat` and `deepseek-reasoner` on 2026-07-24 at
|
||||
15:59 UTC. Codewhale migrates either name to `deepseek-flash` before a
|
||||
request reaches DeepSeek's first-party OpenAI or Anthropic endpoint. If no
|
||||
reasoning tier was configured, `deepseek-chat` also migrates to `off` and
|
||||
`deepseek-reasoner` to `high`, preserving their former non-thinking / thinking
|
||||
|
||||
@@ -1152,7 +1152,7 @@ DeepSeek V4 前缀缓存让 token 标签变得重要。这些数量保持分离
|
||||
如果你从更旧的版本升级:
|
||||
|
||||
- 旧:`/codewhale` 新:`/links`(别名:`/dashboard`、`/api`)
|
||||
- 旧:`/set model deepseek-reasoner` 新:`/config` 并把 `model` 行编辑为 `deepseek-v4-pro` 或 `deepseek-v4-flash`
|
||||
- 旧:`/set model deepseek-reasoner` 新:`/config` 并把 `model` 行编辑为 `deepseek-v4-pro` 或 `deepseek-flash`
|
||||
- 旧:可见 `Normal` 模式或 `default_mode = "normal"` 新:使用 `Agent` / `default_mode = "agent"`;旧 `normal` 仍映射到 `agent`
|
||||
- 旧:在斜杠 UX/帮助中发现 `/set` 新:编辑用 `/config`,只读检查用 `/settings`
|
||||
|
||||
@@ -1199,7 +1199,7 @@ DeepSeek V4 前缀缓存让 token 标签变得重要。这些数量保持分离
|
||||
|
||||
- `insecure_skip_tls_verify`(bool,可选的 provider 表键):旧兼容键,默认禁用。活动 provider 表上为 true 时,provider 客户端拒绝该配置,而不是跳过 TLS 证书验证。企业或私有 CA 包用 `SSL_CERT_FILE`;`codewhale doctor` 报告此设置的过期使用。
|
||||
|
||||
- `default_text_model`(字符串,可选):DeepSeek 和 `deepseek-anthropic` 默认 `deepseek-flash`,OpenAI 是 `gpt-5.6`,xAI 是 `grok-4.6`,NVIDIA NIM 是 `deepseek-ai/deepseek-v4-pro`,AtlasCloud 是 `deepseek-ai/deepseek-v4-flash`,Wanjie Ark 是 `deepseek-reasoner`,火山方舟是 `DeepSeek-V4-Pro`,OpenRouter 和 Novita 是 `deepseek/deepseek-v4-pro`,小米 MiMo 是 `mimo-v2.5-pro`,Fireworks 是 `accounts/fireworks/models/deepseek-v4-pro`,SiliconFlow 和 DeepInfra 是 `deepseek-ai/DeepSeek-V4-Pro`,Arcee AI 是 `trinity-large-thinking`,Moonshot 是 `kimi-k2.7-code`,MiniMax 是 `MiniMax-M3`,Z.ai 是 `GLM-5.3`,StepFun 是 `step-3.7-flash`,千帆是 `ernie-4.0-turbo-8k`,Sakana AI 是 `fugu`,SGLang/vLLM 是 `deepseek-ai/DeepSeek-V4-Pro`,本地 Ollama 没有固定 id(Codewhale 会从实时本地目录中选用一个支持聊天的标签——优先选 coder 或支持工具的标签,然后是上下文最大的——绝不会选嵌入模型或重排序模型),Ollama Cloud 是 `gpt-oss:120b`。Hugging Face 和 Together AI 都默认 `deepseek-ai/DeepSeek-V4-Pro`;`openai-codex` 默认 `gpt-5.6`;`anthropic` 默认 `claude-sonnet-4-6`;`openmodel` 默认 `deepseek-v4-flash`。当前公开的 DeepSeek ID 包括 `deepseek-v4-pro` 和 `deepseek-flash`(V4.1 Flash,以不带版本号的 id 发布),两者都是 1M 上下文窗口、384K 最大输出、默认启用思考模式。DeepSeek 的实时定价/模型页现在把 Pro 后端标为 `DeepSeek-V4-Pro-0813`;可调用的 API ID 仍是 `deepseek-v4-pro`,所以 Codewhale 不发送后端标签,也不发送 Claude Code 特有的 `deepseek-v4-pro[1m]` 选择器。DeepSeek 于 2026 年 7 月 24 日退役 `deepseek-chat` 和 `deepseek-reasoner`;直连官方路由把两者都迁移到 `deepseek-v4-flash`,省略推理设置时保留它们此前的不思考(`off`)和思考(`high`)意图。显式的 `reasoning_effort` 优先,Wanjie Ark、聚合器、自托管运行时和自定义端点上由 provider 自己拥有的 id 不会被全局改写。SiliconFlow 保留自己的映射:`deepseek-reasoner` 和 `deepseek-r1` 选择其 Pro 模型,而 `deepseek-chat` 和 `deepseek-v3` 选择 Flash。各 provider 特有的映射在受支持之处把 `deepseek-v4-pro` / `deepseek-v4-flash` 翻译成该 provider 的模型 ID。OpenRouter 还识别最近的大模型 ID,如 `arcee-ai/trinity-large-thinking`、`minimax/minimax-m3`、`minimax/minimax-m2.7`、`xiaomi/mimo-v2.5-pro`、`qwen/qwen3.6-flash`、`qwen/qwen3.6-35b-a3b`、`qwen/qwen3.6-max-preview`、`qwen/qwen3.6-27b`、`qwen/qwen3.6-plus`、`qwen/qwen3.7-max`、`google/gemma-4-31b-it`、`moonshotai/kimi-k2.7-code`、`moonshotai/kimi-k2.6`、`nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free` 和 `nvidia/nemotron-3-ultra-550b-a55b`;直连 Arcee 使用 `trinity-large-thinking` 和 `trinity-large-preview` 这样的裸 ID;直连 Moonshot 识别 `kimi-k3`、`kimi-k2.7-code` 和 `kimi-k2.6`。确切的 Kimi Code 端点识别 K3 的裸 `k3` 和 K2.7 的 `kimi-for-coding`;这些会员 ID 与直连 Moonshot 的 ID 不同,绝不会跨路由改写。直连 MiniMax 识别 `MiniMax-M3` 和有文档记录的 M2.x 聊天模型 ID;直连 Z.ai 识别 `GLM-5.3`(默认)、`GLM-5.2`、`GLM-5.1` 和 `GLM-5-Turbo`,OpenRouter 识别对应的 `z-ai/glm-5.1`、`z-ai/glm-5.2`、`z-ai/glm-5.3` 和 `z-ai/glm-5-turbo` ID——`GLM-5.3` 自 2026-08-13 起已在 Z.ai Coding Plan 上线;在 Z.ai 发布独立的 5.3 数据之前,它继承 `GLM-5.2` 的目录元数据且不带价格,而显式选择 `GLM-5.2` 会保留它自己的 id;直连 Sakana 识别 `fugu` 和 `fugu-ultra-20260615`;直连小米 MiMo 识别聊天 ID `mimo-v2.5-pro`、`mimo-v2.5-pro-ultraspeed` 和 `mimo-v2.5`,而 TTS ID 通过 `codewhale speech` / `tts` 选择。通用 `openai`、`atlascloud`、`wanjie-ark`、`xiaomi-mimo`、`arcee`、`moonshot`、`minimax`、`openmodel`、`zai`、`stepfun`、`qianfan`、`sakana`、本地 Ollama 和 Ollama Cloud 的模型 ID,在已知别名规范化之后原样透传。带自定义 `base_url` 的 OpenRouter 和 SiliconFlow provider 配置也保留显式的模型值,这样 OpenAI 兼容网关就能接受裸模型 ID。用 `/models` 或 `codewhale models` 从你配置的端点发现实时 ID。`CODEWHALE_MODEL` 为单个进程覆盖它;`DEEPSEEK_MODEL` 是旧别名。
|
||||
- `default_text_model`(字符串,可选):DeepSeek 和 `deepseek-anthropic` 默认 `deepseek-flash`,OpenAI 是 `gpt-5.6`,xAI 是 `grok-4.6`,NVIDIA NIM 是 `deepseek-ai/deepseek-v4-pro`,AtlasCloud 是 `deepseek-ai/deepseek-v4-flash`,Wanjie Ark 是 `deepseek-reasoner`,火山方舟是 `DeepSeek-V4-Pro`,OpenRouter 和 Novita 是 `deepseek/deepseek-v4-pro`,小米 MiMo 是 `mimo-v2.5-pro`,Fireworks 是 `accounts/fireworks/models/deepseek-v4-pro`,SiliconFlow 和 DeepInfra 是 `deepseek-ai/DeepSeek-V4-Pro`,Arcee AI 是 `trinity-large-thinking`,Moonshot 是 `kimi-k2.7-code`,MiniMax 是 `MiniMax-M3`,Z.ai 是 `GLM-5.3`,StepFun 是 `step-3.7-flash`,千帆是 `ernie-4.0-turbo-8k`,Sakana AI 是 `fugu`,SGLang/vLLM 是 `deepseek-ai/DeepSeek-V4-Pro`,本地 Ollama 没有固定 id(Codewhale 会从实时本地目录中选用一个支持聊天的标签——优先选 coder 或支持工具的标签,然后是上下文最大的——绝不会选嵌入模型或重排序模型),Ollama Cloud 是 `gpt-oss:120b`。Hugging Face 和 Together AI 都默认 `deepseek-ai/DeepSeek-V4-Pro`;`openai-codex` 默认 `gpt-5.6`;`anthropic` 默认 `claude-sonnet-4-6`;`openmodel` 默认 `deepseek-v4-flash`。当前公开的 DeepSeek ID 包括 `deepseek-v4-pro` 和 `deepseek-flash`(V4.1 Flash,以不带版本号的 id 发布),两者都是 1M 上下文窗口、384K 最大输出、默认启用思考模式。DeepSeek 的实时定价/模型页现在把 Pro 后端标为 `DeepSeek-V4-Pro-0813`;可调用的 API ID 仍是 `deepseek-v4-pro`,所以 Codewhale 不发送后端标签,也不发送 Claude Code 特有的 `deepseek-v4-pro[1m]` 选择器。DeepSeek 已于 2026 年 7 月 24 日退役 `deepseek-chat` 和 `deepseek-reasoner`;直连官方路由把两者都迁移到 `deepseek-flash`,省略推理设置时保留它们此前的不思考(`off`)和思考(`high`)意图。DeepSeek 也已退役 `deepseek-v4-flash` 和 `deepseek-v4-flash-vision-exp` 模型:两个名称仍被接受,由 V4.1 Flash 提供服务,并按 `deepseek-flash` 的价格计费;Codewhale 对 2026-09-10 04:00 UTC 起的回合采用该价格。`flash`、`deepseek-v4flash`、`flash-vision` 和 `deepseek-v4flashvisionexp` 简写选择 `deepseek-flash`。显式的 `reasoning_effort` 优先,Wanjie Ark、聚合器、自托管运行时和自定义端点上由 provider 自己拥有的 id 不会被全局改写。SiliconFlow 保留自己的映射:`deepseek-reasoner` 和 `deepseek-r1` 选择其 Pro 模型,而 `deepseek-chat` 和 `deepseek-v3` 选择 Flash。各 provider 特有的映射在受支持之处把 `deepseek-v4-pro` / `deepseek-v4-flash` 翻译成该 provider 的模型 ID。OpenRouter 还识别最近的大模型 ID,如 `arcee-ai/trinity-large-thinking`、`minimax/minimax-m3`、`minimax/minimax-m2.7`、`xiaomi/mimo-v2.5-pro`、`qwen/qwen3.6-flash`、`qwen/qwen3.6-35b-a3b`、`qwen/qwen3.6-max-preview`、`qwen/qwen3.6-27b`、`qwen/qwen3.6-plus`、`qwen/qwen3.7-max`、`google/gemma-4-31b-it`、`moonshotai/kimi-k2.7-code`、`moonshotai/kimi-k2.6`、`nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free` 和 `nvidia/nemotron-3-ultra-550b-a55b`;直连 Arcee 使用 `trinity-large-thinking` 和 `trinity-large-preview` 这样的裸 ID;直连 Moonshot 识别 `kimi-k3`、`kimi-k2.7-code` 和 `kimi-k2.6`。确切的 Kimi Code 端点识别 K3 的裸 `k3` 和 K2.7 的 `kimi-for-coding`;这些会员 ID 与直连 Moonshot 的 ID 不同,绝不会跨路由改写。直连 MiniMax 识别 `MiniMax-M3` 和有文档记录的 M2.x 聊天模型 ID;直连 Z.ai 识别 `GLM-5.3`(默认)、`GLM-5.2`、`GLM-5.1` 和 `GLM-5-Turbo`,OpenRouter 识别对应的 `z-ai/glm-5.1`、`z-ai/glm-5.2`、`z-ai/glm-5.3` 和 `z-ai/glm-5-turbo` ID——`GLM-5.3` 自 2026-08-13 起已在 Z.ai Coding Plan 上线;在 Z.ai 发布独立的 5.3 数据之前,它继承 `GLM-5.2` 的目录元数据且不带价格,而显式选择 `GLM-5.2` 会保留它自己的 id;直连 Sakana 识别 `fugu` 和 `fugu-ultra-20260615`;直连小米 MiMo 识别聊天 ID `mimo-v2.5-pro`、`mimo-v2.5-pro-ultraspeed` 和 `mimo-v2.5`,而 TTS ID 通过 `codewhale speech` / `tts` 选择。通用 `openai`、`atlascloud`、`wanjie-ark`、`xiaomi-mimo`、`arcee`、`moonshot`、`minimax`、`openmodel`、`zai`、`stepfun`、`qianfan`、`sakana`、本地 Ollama 和 Ollama Cloud 的模型 ID,在已知别名规范化之后原样透传。带自定义 `base_url` 的 OpenRouter 和 SiliconFlow provider 配置也保留显式的模型值,这样 OpenAI 兼容网关就能接受裸模型 ID。用 `/models` 或 `codewhale models` 从你配置的端点发现实时 ID。`CODEWHALE_MODEL` 为单个进程覆盖它;`DEEPSEEK_MODEL` 是旧别名。
|
||||
- TelecomJS 只把 `deepseek-v4-pro` 用作刷新前的保守回退。其 key 作用域的 `/models` 目录可用后,选择器使用那些实时行;Codewhale 在该路由上省略不受支持的推理请求字段。
|
||||
|
||||
- `reasoning_effort`(字符串,可选):`auto`、`off`、`minimal`、`low`、`medium`、`high`、`xhigh`、`ultra`(`ultracode` 是 `ultra` 的别名)或 `max`;默认取已配置的 UI 档位。DeepSeek Platform 收到顶层 `thinking` / `reasoning_effort` 字段。Ollama Cloud 的 OpenAI 兼容 Chat Completions 路由保留其有文档记录的 `none` / `low` / `medium` / `high` / `max` 阶梯(`off` 作为 `none` 发送;`xhigh` 和 `ultracode` 规范化为 `max`)。确切 `https://api.x.ai/v1` 上的直连 xAI `grok-4.7` 和 `grok-4.6` 收到顶层 `reasoning_effort = "low" | "medium" | "high" | "xhigh"`(阶梯来自内置目录行;`grok-4.5` 把 `xhigh` 映射为 `high`,没有文档记录 effort 的行,如 `grok-4.3`,则不发送该字段);Grok 的推理无法关闭,因此 `off` 规范化为 `high`,`max`/`ultracode` 规范化为 `xhigh`,`auto` 让该字段省略,从而使用 xAI 文档记录的默认值 `high`。自定义的 xAI 兼容 `base_url` 不继承该方言。确切 `https://api.moonshot.ai/v1` 上的直连 Moonshot `kimi-k3` 始终思考,只收到顶层 `reasoning_effort = "low" | "high" | "max"`;`off` 规范化为 `low`,`medium` 规范化为 `high`。确切 `https://api.kimi.com/coding/v1` 上的 Kimi Code 会员 `k3` 则收到嵌套的 `thinking.effort`,其 `off` 设置同样规范化为启用的 `low`。正常调度的 `auto` 使用 Codewhale 的自动推理选择器,发送一个具体的、按路由规范化后的档位;只有省略推理设置时,才由 provider 的默认值控制。相邻的网关以及其他模型/端点组合保留通用的 Moonshot 契约。OpenAI Codex 把过期的 `off` 规范化为 `low`,并把 `max` / `ultracode` 作为 Responses 的 `xhigh` 发送。Z.ai 收到有文档记录的 `thinking` 控制,并把启用的思考视为 GLM coding 的 high/max 通道。NVIDIA NIM 通过 `chat_template_kwargs` 收到等效设置。
|
||||
|
||||
@@ -275,7 +275,7 @@ Operate 保持直接的工具面及其审批、沙箱、shell、ask 规则和仓
|
||||
|
||||
Fleet 是持久花名册对外的名称。`codewhale fleet …` 是命令,`/fleet` 是斜杠命令。Fleet 这个名字也用在那些必须跨版本保持稳定的地方:持久账本 `.codewhale/fleet.jsonl`、已保存的花名册 `fleets/<name>.toml`、`[fleet]` 配置表,以及 `codewhale workflow run --fleet` 标志。
|
||||
|
||||
想让 Codewhale 每回合自己选模型和思考级别时,用 `/model auto`。当 DeepSeek 路由模型可用时,Auto 可以在脱敏清单中选取任何可运行的 provider/模型组合。该分类会把最新请求(上限 4,000 字符)加上最多六条最近上下文行的有界摘要(每条 900 字符)发送到 `DeepSeek / deepseek-v4-flash`。凭据、端点和提供商错误文本不会包含在清单里。没有该路由器时,Auto 使用本地的、感知提供商的启发式方法,不发送任何路由请求。如果分类尝试未通过验证或出错,Auto 回退到该启发式方法,同时把尝试过的分类器数据路径保留在回合回执中。
|
||||
想让 Codewhale 每回合自己选模型和思考级别时,用 `/model auto`。当 DeepSeek 路由模型可用时,Auto 可以在脱敏清单中选取任何可运行的 provider/模型组合。该分类会把最新请求(上限 4,000 字符)加上最多六条最近上下文行的有界摘要(每条 900 字符)发送到 `DeepSeek / deepseek-flash`。凭据、端点和提供商错误文本不会包含在清单里。没有该路由器时,Auto 使用本地的、感知提供商的启发式方法,不发送任何路由请求。如果分类尝试未通过验证或出错,Auto 回退到该启发式方法,同时把尝试过的分类器数据路径保留在回合回执中。
|
||||
|
||||
`/model` 选择器会说明哪条数据路径可用,并显示最后解析的路由。`Ctrl+O` 打开所选或当前回合的推理详情;`Ctrl+Alt+O`(或 `/turn inspect`)打开整回合的回合检查器(Turn Inspector),其模型路由区记录具体的 provider/模型、strong/fast 配对、所选层级、选择范围、路由原因,以及分类器是否收到了路由上下文。当你需要可重复的比较、严格的提供商边界或完全不要分类请求时,使用固定模型。
|
||||
|
||||
|
||||
@@ -497,7 +497,7 @@ Kimi 仍然仅支持 API 密钥;对 Kimi 的外部授权被拒绝。
|
||||
|
||||
| 提供商 ID | TOML 表 | 认证环境变量 | Base URL 环境变量和默认值 | 默认或静态模型 | 备注 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `deepseek` | `[providers.deepseek]` | `DEEPSEEK_API_KEY` | `CODEWHALE_BASE_URL` / `DEEPSEEK_BASE_URL`;默认 `https://api.deepseek.com/beta` | `deepseek-flash`(出厂默认;V4.1 Flash,无版本号的 ID), `deepseek-v4-pro`, `deepseek-v4-flash`,实验性的 `deepseek-v4-flash-vision-exp`;视觉别名 `flash-vision`, `deepseek-v4flashvisionexp`;兼容别名 `deepseek-chat`, `deepseek-reasoner` | 一等默认提供商。线上 Pro 后端标记为 `DeepSeek-V4-Pro-0813`;可调用的 API ID 仍是 `deepseek-v4-pro`。Beta URL 启用严格工具模式、chat 前缀补全和 FIM 补全。文档中记载的 V4 路由可以通过单独的、有界的 Responses 请求使用提供商原生的网页搜索;兼容的自定义端点不会继承这一能力。显式设置 `https://api.deepseek.com` 或 `/v1` 可退出仅限 beta 的功能。出厂默认的 `deepseek-flash` 使用 Responses API(自 2026-07-31 的 Flash 生产环境更新起,这是 DeepSeek 文档中记载的 Codex 式集成路径);仅适用于 Chat 的控制项(`thinking` 开关和严格工具的 `/beta` 路由)只作用于 Chat Completions 路由,而 `deepseek-v4-pro` 在其已宣布的 Responses 推出之前仍走 Chat Completions。思考强度遵循 DeepSeek 文档中记载的“请求值到实际值”映射:`minimal`/`low` 落到 `low`,`medium`/`xhigh` 落到 `high`,`max`/`ultra` 落到 `max`;`off` 关闭思考(Chat 上为 `thinking: {"type":"disabled"}`,Responses 上为 `reasoning.effort: "none"`)。该实验性视觉 ID 于 2026-08-21 在已认证的 `/models` 名单中被观察到,仅在直连的 Chat Completions 路由上声明支持图像输入。它的限制、推理和工具调用标志暂时继承自 Flash;价格未知,本次发布工作中也没有做过付费的图像往返测试。 |
|
||||
| `deepseek` | `[providers.deepseek]` | `DEEPSEEK_API_KEY` | `CODEWHALE_BASE_URL` / `DEEPSEEK_BASE_URL`;默认 `https://api.deepseek.com/beta` | `deepseek-flash`(出厂默认;V4.1 Flash,无版本号的 ID), `deepseek-v4-pro`, `deepseek-v4-flash`,实验性的 `deepseek-v4-flash-vision-exp`;兼容别名 `deepseek-chat`, `deepseek-reasoner` | 一等默认提供商。线上 Pro 后端标记为 `DeepSeek-V4-Pro-0813`;可调用的 API ID 仍是 `deepseek-v4-pro`。Beta URL 启用严格工具模式、chat 前缀补全和 FIM 补全。文档中记载的 V4 路由可以通过单独的、有界的 Responses 请求使用提供商原生的网页搜索;兼容的自定义端点不会继承这一能力。显式设置 `https://api.deepseek.com` 或 `/v1` 可退出仅限 beta 的功能。出厂默认的 `deepseek-flash` 使用 Responses API(自 2026-07-31 的 Flash 生产环境更新起,这是 DeepSeek 文档中记载的 Codex 式集成路径);仅适用于 Chat 的控制项(`thinking` 开关和严格工具的 `/beta` 路由)只作用于 Chat Completions 路由,而 `deepseek-v4-pro` 在其已宣布的 Responses 推出之前仍走 Chat Completions。思考强度遵循 DeepSeek 文档中记载的“请求值到实际值”映射:`minimal`/`low` 落到 `low`,`medium`/`xhigh` 落到 `high`,`max`/`ultra` 落到 `max`;`off` 关闭思考(Chat 上为 `thinking: {"type":"disabled"}`,Responses 上为 `reasoning.effort: "none"`)。该实验性视觉 ID 于 2026-08-21 在已认证的 `/models` 名单中被观察到,仅在直连的 Chat Completions 路由上声明支持图像输入。它的限制、推理和工具调用标志暂时继承自 Flash,本次发布工作中也没有做过付费的图像往返测试。DeepSeek 此后已退役 `deepseek-v4-flash` 和该视觉 ID;两者仍被接受,由 V4.1 Flash 提供服务,并按 `deepseek-flash` 的价格计费,Codewhale 从 2026-09-10 04:00 UTC 起采用该价格。`flash`、`deepseek-v4flash`、`flash-vision` 和 `deepseek-v4flashvisionexp` 简写现在选择 `deepseek-flash`。 |
|
||||
| `deepseek-anthropic` | `[providers.deepseek_anthropic]` | `DEEPSEEK_API_KEY` | `DEEPSEEK_ANTHROPIC_BASE_URL`;默认 `https://api.deepseek.com/anthropic` | `deepseek-v4-pro`, `deepseek-v4-flash`;兼容别名 `deepseek-chat`, `deepseek-reasoner` | 面向 Anthropic Messages 线协议的 DeepSeek 显式选择加入路由。使用 `/v1/messages`、`x-api-key` 和 `anthropic-version: 2023-06-01`。默认 Chat Completions 路径请保持 `provider = "deepseek"`。 |
|
||||
| `nvidia-nim` | `[providers.nvidia_nim]` | `NVIDIA_API_KEY`, `NVIDIA_NIM_API_KEY` | `NVIDIA_NIM_BASE_URL`, `NIM_BASE_URL`, `NVIDIA_BASE_URL`;默认 `https://integrate.api.nvidia.com/v1` | `deepseek-ai/deepseek-v4-pro`, `deepseek-ai/deepseek-v4-flash` | 通过 NVIDIA NIM 托管的 DeepSeek V4。TUI 配置路径接受 `NVIDIA_NIM_MODEL`。 |
|
||||
| `openai` | `[providers.openai]` | `OPENAI_API_KEY` | `OPENAI_BASE_URL`;默认 `https://api.openai.com/v1` | `gpt-5.6`(默认), `gpt-5.6-sol`, `gpt-5.6-terra`, `gpt-5.6-luna` | 通用 OpenAI 兼容路由,其内置端点和回退目录均以 OpenAI 原生为准。[GPT-5.6 系列](https://developers.openai.com/api/docs/models/gpt-5.6-sol)使用 OpenAI 文档中记载的 1.05M 上下文、128K 最大输出和推理级别。自定义网关仍可自由选择由网关自己提供的显式模型。接受 `OPENAI_MODEL`。 |
|
||||
@@ -800,7 +800,7 @@ MiniMax M3 使用输入长度和服务层级。Codewhale 省略 `service_tier`
|
||||
|
||||
更改 `provider`、`base_url` 或 `model` 可以选择支持 OpenAI 兼容负载形态的路由,但 Codewhale 无法在模型已将其作为散文发出之后,把任意的 JSON 文本转换成受信的工具调用。
|
||||
|
||||
DeepSeek 将于 2026-07-24 15:59 UTC 退役 `deepseek-chat` 和 `deepseek-reasoner`。在请求到达 DeepSeek 第一方 OpenAI 或 Anthropic 端点之前,Codewhale 会把任一名称迁移到 `deepseek-v4-flash`。如果未配置推理层级,`deepseek-chat` 也会迁移到 `off`,`deepseek-reasoner` 迁移到 `high`,保留它们原先的非思考/思考意图;显式的 `reasoning_effort` 仍然权威。该映射刻意不是全局的:Wanjie Ark、聚合器、自托管运行时和自定义端点继续拥有它们自己的模型 id。
|
||||
DeepSeek 已于 2026-07-24 15:59 UTC 退役 `deepseek-chat` 和 `deepseek-reasoner`。在请求到达 DeepSeek 第一方 OpenAI 或 Anthropic 端点之前,Codewhale 会把任一名称迁移到 `deepseek-flash`。如果未配置推理层级,`deepseek-chat` 也会迁移到 `off`,`deepseek-reasoner` 迁移到 `high`,保留它们原先的非思考/思考意图;显式的 `reasoning_effort` 仍然权威。该映射刻意不是全局的:Wanjie Ark、聚合器、自托管运行时和自定义端点继续拥有它们自己的模型 id。
|
||||
|
||||
## 推理强度
|
||||
|
||||
|
||||
Reference in new issue
Block a user