SPB Git

spb/wp27_uqo

Public
3.1 KB · 56 lines python
1"""Anthropic adapter (official `anthropic` SDK, Messages API with structured output).23Reads ANTHROPIC_API_KEY from the environment only. The frozen system prompt is marked for prompt4caching; the user message carries the volatile market snapshot. `effort` maps to output_config.effort5for models that support it (Claude 4.6+). No thinking parameter is sent (adaptive by default)."""6from __future__ import annotations78import os9import time1011from . import ProviderResult12from ..schema import DECISION_JSON_SCHEMA131415class AnthropicProvider:16    name = "anthropic"1718    def __init__(self, timeout_s: float = 60.0, max_retries: int = 3, **_: object) -> None:19        import anthropic20        if not os.environ.get("ANTHROPIC_API_KEY"):21            raise RuntimeError("ANTHROPIC_API_KEY is not set")22        self._anthropic = anthropic23        self.client = anthropic.Anthropic(timeout=timeout_s, max_retries=max_retries)2425    def complete(self, system: str, user: str, model: str, reasoning_effort: str | None = "low",26                 max_output_tokens: int = 400, **_: object) -> ProviderResult:27        t0 = time.perf_counter()28        kwargs: dict = dict(29            model=model,30            max_tokens=max(max_output_tokens, 256),31            system=[{"type": "text", "text": system, "cache_control": {"type": "ephemeral"}}],32            messages=[{"role": "user", "content": user}],33            output_config={"format": {"type": "json_schema", "schema": DECISION_JSON_SCHEMA}},34        )35        if reasoning_effort:36            kwargs["output_config"]["effort"] = reasoning_effort37        try:38            resp = self.client.messages.create(**kwargs)39        except self._anthropic.RateLimitError as e:40            return ProviderResult(text="", error=f"rate_limit: {e}", latency_s=time.perf_counter() - t0, model=model)41        except self._anthropic.APIStatusError as e:42            return ProviderResult(text="", error=f"status_{e.status_code}: {str(e)[:200]}", latency_s=time.perf_counter() - t0, model=model)43        except self._anthropic.APIConnectionError as e:44            return ProviderResult(text="", error=f"connection: {str(e)[:200]}", latency_s=time.perf_counter() - t0, model=model)45        except Exception as e:  # noqa: BLE00146            return ProviderResult(text="", error=f"other: {type(e).__name__}: {str(e)[:200]}", latency_s=time.perf_counter() - t0, model=model)47        if getattr(resp, "stop_reason", "") == "refusal":48            return ProviderResult(text="", error="refusal", latency_s=time.perf_counter() - t0, model=model)49        text = "".join(b.text for b in resp.content if getattr(b, "type", "") == "text")50        u = resp.usage51        return ProviderResult(text=text, input_tokens=int(u.input_tokens or 0),52                              cached_input_tokens=int(getattr(u, "cache_read_input_tokens", 0) or 0),53                              output_tokens=int(u.output_tokens or 0), latency_s=time.perf_counter() - t0,54                              model=model, request_id=getattr(resp, "_request_id", "") or "",55                              error="" if text else "empty_output")56
Files · main
Menu

Theme