diff --git a/cmd/odek/serve_api_test.go b/cmd/odek/serve_api_test.go index 2a1863f9..ea7a2522 100644 --- a/cmd/odek/serve_api_test.go +++ b/cmd/odek/serve_api_test.go @@ -457,6 +457,25 @@ func TestHandleModelList_ReturnsOnlyConfiguredModel(t *testing.T) { if models[0]["description"] == "" { t.Error("description should be non-empty for a known model") } + if ctx, ok := models[0]["max_context"].(float64); !ok || ctx != 1_000_000 { + t.Errorf("max_context = %v, want 1000000 (deepseek-v4 1M window)", models[0]["max_context"]) + } +} + +func TestHandleModelList_DeepSeekV41UsesV4Window(t *testing.T) { + handler := handleModelList("deepseek-v4.1-flash-expires-on-0910", nil) + w := httptest.NewRecorder() + handler(w, httptest.NewRequest(http.MethodGet, "/api/models", nil)) + var models []modelEntry + if err := json.NewDecoder(w.Body).Decode(&models); err != nil { + t.Fatal(err) + } + if len(models) != 1 { + t.Fatalf("len = %d, want 1", len(models)) + } + if models[0].MaxContext != 1_000_000 { + t.Errorf("v4.1 last-resort ctx = %d, want 1000000", models[0].MaxContext) + } } func TestHandleModelList_EmptyConfigModel_ReturnsEmptyList(t *testing.T) { diff --git a/docs/MIGRATION.md b/docs/MIGRATION.md index ca576f12..b0abc8bc 100644 --- a/docs/MIGRATION.md +++ b/docs/MIGRATION.md @@ -67,7 +67,7 @@ DeepSeek-only leftover: when `provider` is `deepseek`, `ODEK_API_KEY` → `DEEPS - Thinking: set `--thinking medium` (or `low`/`high`/`disabled`; `enabled` still works as an alias for `medium`). - Timeout: default **300s** for every model. Raise with `llm.request_timeout_seconds`. -- Context window: `llm.context_window` → `ListModels` → last-resort table for shipped ids (`deepseek-v4-flash` 128K, `deepseek-v4-pro` 1M, GLM/Kimi/OpenAI prefixes) → else 0 (no trim). +- Context window: `llm.context_window` → last-resort table for shipped ids (`deepseek-v4*` 1M, `deepseek-` 128K, GLM/Kimi/OpenAI prefixes) → `ListModels` → else 0 (no trim). `ProfileLabel` now returns the model id. diff --git a/docs/PROVIDERS.md b/docs/PROVIDERS.md index 00a9ff0a..eb0b6d0d 100644 --- a/docs/PROVIDERS.md +++ b/docs/PROVIDERS.md @@ -71,8 +71,8 @@ window. **No auto-thinking and no auto-timeout.** | Prefix | Tokens | |---|---| -| `deepseek-v4-pro` | 1M | -| `deepseek-v4-flash` / `deepseek-` | 128K | +| `deepseek-v4` (pro, flash, v4.1-*) | 1M | +| `deepseek-` (v3 chat / reasoner) | 128K | | `glm-5.3` / `glm-5.2` | 1M | | `glm-5-turbo` | 200K | | `glm-` | 128K | diff --git a/internal/llmclient/client.go b/internal/llmclient/client.go index ed513cdc..aff36ec6 100644 --- a/internal/llmclient/client.go +++ b/internal/llmclient/client.go @@ -647,9 +647,8 @@ func LastResortContext(model string) int { {"kimi-", 262_144}, {"k3-256k", 262_144}, {"k3", 1_000_000}, - {"deepseek-v4-pro", 1_000_000}, - {"deepseek-v4-flash", 131_072}, - {"deepseek-", 131_072}, + {"deepseek-v4", 1_000_000}, // pro, flash, v4.1-* (official 1M window) + {"deepseek-", 131_072}, // v3 chat / reasoner // OpenAI — api.openai.com ListModels omits context_length. {"gpt-6", 1_050_000}, {"gpt-5.6", 1_050_000}, diff --git a/internal/llmclient/client_test.go b/internal/llmclient/client_test.go index 39eef9d0..06263905 100644 --- a/internal/llmclient/client_test.go +++ b/internal/llmclient/client_test.go @@ -78,8 +78,12 @@ func TestLastResortContext(t *testing.T) { model string want int }{ - {"deepseek-v4-flash", 131_072}, + {"deepseek-v4-flash", 1_000_000}, {"deepseek-v4-pro", 1_000_000}, + {"deepseek-v4.1", 1_000_000}, + {"deepseek-v4.1-flash-expires-on-0910", 1_000_000}, + {"deepseek-chat", 131_072}, + {"deepseek-reasoner", 131_072}, {"gpt-6-astra", 1_050_000}, {"gpt-6", 1_050_000}, {"gpt-5.6-luna", 1_050_000},