fix(context): persist NVIDIA DeepSeek endpoint limit

This commit is contained in:
Gille 2026-07-30 20:26:46 -06:00 committed by Teknium
parent 2f2d90344c
commit 29eac371d1
4 changed files with 117 additions and 4 deletions

View File

@ -4746,6 +4746,13 @@ def run_conversation(
provider=agent.provider,
api_mode=agent.api_mode,
)
# Persist an explicit provider-reported limit before
# compression/retry. The next request can be rate
# limited, omit usage, or the process can restart; none
# of those should discard metadata the provider already
# confirmed. Keep the probe flags as a best-effort
# post-success retry if this write cannot complete.
save_context_length(agent.model, agent.base_url, new_ctx)
# Context probing flags — only set on built-in
# compressor (plugin engines manage their own). This
# value came from the provider, so it is safe to cache.

View File

@ -634,12 +634,17 @@ def _is_known_provider_base_url(base_url: str) -> bool:
def _endpoint_scoped_context_length(model: str, base_url: str) -> Optional[int]:
"""Return metadata confirmed only for the Kimi Coding endpoint.
"""Return context metadata confirmed for one provider endpoint.
Kimi Coding serves K3 under the bare slug ``k3``, but users may also
configure or select the public-facing aliases ``kimi-k3`` and
``kimi-k3-cot``. Only canonical ``https://api.kimi.com/coding`` endpoints
(legacy Moonshot keys do not serve K3) get the 1 Mi context window.
NVIDIA NIM serves ``deepseek-ai/deepseek-v4-pro`` with a 262,144-token
window even though DeepSeek's native endpoint serves the V4 family with a
1M window. Keep the lower limit scoped to NVIDIA instead of weakening the
global model-family metadata.
"""
normalized = _normalize_base_url(base_url)
try:
@ -659,6 +664,18 @@ def _endpoint_scoped_context_length(model: str, base_url: str) -> Optional[int]:
and model.strip().lower() in {"k3", "kimi-k3", "kimi-k3-cot"}
):
return 1_048_576
if (
parsed.scheme.lower() == "https"
and (parsed.hostname or "").lower() == "integrate.api.nvidia.com"
and port in (None, 443)
and parsed.username is None
and parsed.password is None
and parsed.path.rstrip("/") == "/v1"
and not parsed.query
and not parsed.fragment
and model.strip().lower() == "deepseek-ai/deepseek-v4-pro"
):
return 262_144
return None

View File

@ -134,6 +134,42 @@ class TestEstimateRequestTokensRough:
# =========================================================================
class TestDefaultContextLengths:
def test_nvidia_deepseek_v4_pro_context_is_endpoint_scoped(self):
"""NVIDIA's 262K NIM window must not lower DeepSeek V4 globally."""
with patch("agent.model_metadata.get_cached_context_length", return_value=None), \
patch("agent.model_metadata.fetch_model_metadata", return_value={}), \
patch("agent.model_metadata.fetch_endpoint_model_metadata", return_value={}), \
patch("agent.model_metadata._query_ollama_api_show", return_value=None), \
patch("agent.models_dev.lookup_models_dev_context", return_value=None):
accepted_urls = (
"https://integrate.api.nvidia.com/v1",
"https://INTEGRATE.API.NVIDIA.COM/v1/",
"https://integrate.api.nvidia.com:443/v1",
)
rejected_urls = (
"http://integrate.api.nvidia.com/v1",
"https://integrate.api.nvidia.com:8443/v1",
"https://integrate.api.nvidia.com/v1/other",
"https://integrate.api.nvidia.com/v1?route=other",
"https://example.invalid/v1",
"https://api.deepseek.com/v1",
"https://openrouter.ai/api/v1",
)
for base_url in accepted_urls:
assert get_model_context_length(
"deepseek-ai/deepseek-v4-pro",
provider="nvidia",
base_url=base_url,
) == 262_144
for base_url in rejected_urls:
assert get_model_context_length(
"deepseek-ai/deepseek-v4-pro",
provider="nvidia",
base_url=base_url,
) == 1_000_000
def test_k3_context_is_scoped_to_confirmed_coding_endpoint(self):
"""The bare ``k3`` slug's 1 Mi context must not leak to unverified endpoints.
@ -1076,4 +1112,3 @@ class TestMoAContextLength:
assert compressor.context_length == configured_context
assert compressor.threshold_tokens == configured_context // 2
endpoint_probe.assert_not_called()

View File

@ -327,6 +327,62 @@ class TestHTTP413Compression:
assert result["final_response"] == "Recovered after compression"
def test_provider_context_limit_is_cached_before_retry_succeeds(self, agent):
"""A confirmed limit survives when the recovery response omits usage."""
err_400 = Exception(
"Error code: 400 - {'error': {'message': "
"\"This model's maximum context length is 262144 tokens. "
"However, your messages resulted in 271877 tokens.\", 'code': 400}}"
)
err_400.status_code = 400
# NVIDIA-compatible endpoints can omit usage. Before the fix, caching
# happened only in the successful-response usage block, so this lost
# the provider-confirmed limit across a restart.
ok_resp = _mock_response(
content="Recovered without usage metadata",
finish_reason="stop",
usage=None,
)
agent.model = "deepseek-ai/deepseek-v4-pro"
agent.provider = "nvidia"
agent.base_url = "https://integrate.api.nvidia.com/v1"
agent.context_compressor.update_model(
model=agent.model,
context_length=1_000_000,
base_url=agent.base_url,
api_key=agent.api_key,
provider=agent.provider,
api_mode=agent.api_mode,
)
agent.client.chat.completions.create.side_effect = [err_400, ok_resp]
with (
patch.object(agent, "_compress_context") as mock_compress,
patch.object(agent, "_persist_session"),
patch.object(agent, "_save_trajectory"),
patch.object(agent, "_cleanup_task_resources"),
patch("agent.conversation_loop.save_context_length") as mock_save,
):
mock_compress.return_value = (
[{"role": "user", "content": "compressed summary"}],
"compressed prompt",
)
result = agent.run_conversation(
"continue",
conversation_history=[
{"role": "user", "content": "previous question"},
{"role": "assistant", "content": "previous answer"},
],
)
assert result["completed"] is True
mock_save.assert_called_once_with(
"deepseek-ai/deepseek-v4-pro",
"https://integrate.api.nvidia.com/v1",
262_144,
)
def test_context_length_retry_rebuilds_request_after_compression(self, agent):
"""Retry must send the compressed transcript, not the stale oversized payload."""
err_400 = Exception(
@ -1132,5 +1188,3 @@ class TestOverflowWithCompactionDisabled:
assert result.get("failed") is True
assert result.get("compaction_disabled") is True
assert "auto-compaction is disabled" in result["error"]