feat(cache): enable DeepSeek caching on OpenCode

This commit is contained in:
wz-heng 2026-07-30 20:39:08 +08:00 committed by Teknium
parent 5c45d9c208
commit 6b6435a874
2 changed files with 58 additions and 13 deletions

View File

@ -1860,12 +1860,12 @@ def anthropic_prompt_cache_policy(
gateway implements the Anthropic cache_control contract
(MiniMax, Zhipu GLM, LiteLLM's Anthropic proxy mode all do).
Qwen / Alibaba-family models on OpenCode, OpenCode Go, and direct
Alibaba (DashScope) also honour Anthropic-style ``cache_control``
markers on OpenAI-wire chat completions. Upstream pi-mono #3392 /
pi #3393 documented this for opencode-go Qwen. Without markers
these providers serve zero cache hits, re-billing the full prompt
on every turn.
Qwen models on OpenCode and direct Alibaba (DashScope), plus DeepSeek
models on OpenCode, also honour Anthropic-style ``cache_control`` markers
on OpenAI-wire chat completions. Upstream pi-mono #3392 / pi #3393
documented this for opencode-go Qwen; #24617 reports the same gateway
contract for DeepSeek. Without markers these providers serve zero cache
hits, re-billing the full prompt on every turn.
"""
eff_provider = (provider if provider is not None else agent.provider) or ""
eff_base_url = base_url if base_url is not None else (agent.base_url or "")
@ -1980,16 +1980,22 @@ def anthropic_prompt_cache_policy(
if is_minimax_provider or is_minimax_host:
return True, True
# Qwen/Alibaba on OpenCode (Zen/Go) and native DashScope: OpenAI-wire
# transport that accepts Anthropic-style cache_control markers and
# rewards them with real cache hits. Without this branch
# qwen3.6-plus on opencode-go reports 0% cached tokens and burns
# through the subscription on every turn.
# Qwen on OpenCode (Zen/Go) and native DashScope, plus DeepSeek on
# OpenCode only: OpenAI-wire transports that accept Anthropic-style
# cache_control markers and reward them with real cache hits. Keep direct
# Alibaba specific to Qwen; its catalog does not establish the same
# contract for DeepSeek.
model_is_qwen = "qwen" in model_lower
model_is_deepseek = "deepseek" in model_lower
provider_is_opencode = provider_lower in {
"opencode", "opencode-zen", "opencode-go",
}
provider_is_alibaba_family = provider_lower in {
"opencode", "opencode-zen", "opencode-go", "alibaba",
}
if provider_is_alibaba_family and model_is_qwen:
if (provider_is_alibaba_family and model_is_qwen) or (
provider_is_opencode and model_is_deepseek
):
# Envelope layout (native_anthropic=False): markers on inner
# content parts, not top-level tool messages. Matches
# pi-mono's "alibaba" cacheControlFormat.

View File

@ -10,6 +10,8 @@ from __future__ import annotations
from unittest.mock import MagicMock
import pytest
from run_agent import AIAgent
@ -256,6 +258,44 @@ class TestQwenAlibabaFamily:
assert agent._anthropic_prompt_cache_policy() == (False, False)
class TestDeepSeekOpenCode:
"""DeepSeek uses OpenCode's envelope-layout cache markers (#24617)."""
@pytest.mark.parametrize(
"provider",
["opencode", "opencode-zen", "opencode-go"],
)
def test_deepseek_on_opencode_caches_with_envelope_layout(self, provider):
agent = _make_agent(
provider=provider,
base_url="https://opencode.ai/v1",
api_mode="chat_completions",
model="deepseek-v4-pro",
)
assert agent._anthropic_prompt_cache_policy() == (True, False)
def test_deepseek_on_direct_alibaba_does_not_cache(self):
agent = _make_agent(
provider="alibaba",
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
api_mode="chat_completions",
model="deepseek-v4-pro",
)
assert agent._anthropic_prompt_cache_policy() == (False, False)
def test_deepseek_on_openrouter_does_not_cache(self):
agent = _make_agent(
provider="openrouter",
base_url="https://openrouter.ai/api/v1",
api_mode="chat_completions",
model="deepseek/deepseek-chat",
)
assert agent._anthropic_prompt_cache_policy() == (False, False)
class TestNousPortalAnthropicWire:
def test_portal_claude_on_the_messages_wire_uses_the_native_layout(self):
agent = _make_agent(
@ -315,4 +355,3 @@ class TestExplicitOverrides:
# ─────────────────────────────────────────────────────────────────────
# Long-lived prefix cache policy (cross-session 1h tier)
# ─────────────────────────────────────────────────────────────────────