Parent
Part of meta-issue #325 (expand LLM provider catalog). Architectural decision to land in core (not separate package) is documented there.
Scope
Add Deepseek as a registered LLM backend. Deepseek's chat-completions endpoint is OpenAI-compatible (POST https://api.deepseek.com/v1/chat/completions with OpenAI request/response shape), so implementation is a thin factory over atomic_agents/llm/openai_compat.py mirroring moonshot.py.
Implementation
atomic_agents/llm/deepseek.py (new file, ~50 LOC)
"""DeepseekLLMBackend factory over OpenAICompatibleLLMBackend.
Deepseek's chat-completions API is OpenAI-shape with base URL
https://api.deepseek.com/v1 and model strings like deepseek-chat,
deepseek-reasoner. Mirrors moonshot.py's factory pattern.
Deepseek-reasoner is a thinking model; output may include <think>...</think>
tags depending on API version. Handle gracefully in the openai_compat layer
or in a Deepseek-specific post-processor.
"""
from .openai_compat import OpenAICompatibleLLMBackend, OpenAICompatibleConfig
DEEPSEEK_BASE_URL = "https://api.deepseek.com/v1"
DEEPSEEK_PROVIDER_NAME = "deepseek"
DEEPSEEK_MODEL_CATALOG = ("deepseek-chat", "deepseek-reasoner")
def make_deepseek_backend(api_key: str) -> OpenAICompatibleLLMBackend:
"""Construct a Deepseek backend with Deepseek base URL + catalog."""
return OpenAICompatibleLLMBackend(
config=OpenAICompatibleConfig(
base_url=DEEPSEEK_BASE_URL,
api_key=api_key,
provider_name=DEEPSEEK_PROVIDER_NAME,
model_catalog=DEEPSEEK_MODEL_CATALOG,
)
)
Registration in atomic_agents/llm/__init__.py
Add to _register_default_backends(). Resolve via _llm._get_deepseek_key(); skip silently if no key.
atomic_agents/_llm.py — key resolver
def _get_deepseek_key() -> str:
return _get_key(
env_vars=["ATOMIC_AGENTS_DEEPSEEK_KEY", "DEEPSEEK_API_KEY"],
keychain_name="atomic-agents-deepseek",
config_key="deepseek",
)
atomic_agents/_costs.py — pricing table
# Deepseek pricing as of impl date. Source: https://api-docs.deepseek.com/quick_start/pricing.
"deepseek/deepseek-chat": {"input": 0.27, "output": 1.10}, # USD per 1M tokens (cache-miss)
"deepseek/deepseek-reasoner": {"input": 0.55, "output": 2.19},
Deepseek publishes cache-hit and cache-miss prices separately. Use cache-miss for safety (worst case); document the convention in a _costs.py comment. Verify exact numbers at impl time.
Deepseek-specific quirks to handle
- Reasoner thinking-token output.
deepseek-reasoner returns thinking content. Decide where to surface or strip — possibly add a reasoning_content field to _RawLLMResponse if not already present, or treat as part of normal content. Resolve in plan-eng-review.
- Cache pricing tiers. Cache-hit prices are ~10x lower than cache-miss. If the framework wants to track cache-hit ratios for cost accuracy, that's a cross-cutting concern that affects every provider eventually (Anthropic prompt caching also has this shape). Out of scope here; file separately if pursued.
Doctor integration
Same shape as Grok — extend check_provider_keys iteration.
Spec/31 amendment
Add DeepseekLLMBackend to §"Reference implementations". Note the thinking-token handling decision in §"Open questions" or a new §"Reasoning-model output handling" subsection if it warrants standing reference.
Conformance suite parametrization
Verify parametrization picks up Deepseek. Add Deepseek-specific smoke test for the base URL + request shape.
Acceptance criteria
Out of scope
- Cache-hit pricing tier tracking (cross-cutting; separate issue if pursued).
- Deepseek streaming.
References
Parent
Part of meta-issue #325 (expand LLM provider catalog). Architectural decision to land in core (not separate package) is documented there.
Scope
Add Deepseek as a registered LLM backend. Deepseek's chat-completions endpoint is OpenAI-compatible (
POST https://api.deepseek.com/v1/chat/completionswith OpenAI request/response shape), so implementation is a thin factory overatomic_agents/llm/openai_compat.pymirroringmoonshot.py.Implementation
atomic_agents/llm/deepseek.py(new file, ~50 LOC)Registration in
atomic_agents/llm/__init__.pyAdd to
_register_default_backends(). Resolve via_llm._get_deepseek_key(); skip silently if no key.atomic_agents/_llm.py— key resolveratomic_agents/_costs.py— pricing tableDeepseek publishes cache-hit and cache-miss prices separately. Use cache-miss for safety (worst case); document the convention in a
_costs.pycomment. Verify exact numbers at impl time.Deepseek-specific quirks to handle
deepseek-reasonerreturns thinking content. Decide where to surface or strip — possibly add areasoning_contentfield to_RawLLMResponseif not already present, or treat as part of normal content. Resolve in plan-eng-review.Doctor integration
Same shape as Grok — extend
check_provider_keysiteration.Spec/31 amendment
Add
DeepseekLLMBackendto §"Reference implementations". Note the thinking-token handling decision in §"Open questions" or a new §"Reasoning-model output handling" subsection if it warrants standing reference.Conformance suite parametrization
Verify parametrization picks up Deepseek. Add Deepseek-specific smoke test for the base URL + request shape.
Acceptance criteria
atomic_agents/llm/deepseek.pyshipped withmake_deepseek_backendfactory._get_deepseek_key()resolver in_llm.py._costs.pywith cache-miss convention documented.check_provider_keysenumerates Deepseek.Out of scope
References
atomic_agents/llm/moonshot.py.