curated_feed.claude =================== .. py:module:: curated_feed.claude .. autoapi-nested-parse:: The Anthropic-backed scorer: the one place that talks to a model. Everything the API needs is decided here — the cache split, the token ceiling, what counts as a failed response — so that `score.py` stays a protocol, a retry loop and a failure policy, and the rest of the pipeline never learns that a provider exists. Three choices are worth knowing about. **The policy documents are the system prompt, the candidates are the user turn.** That is the boundary `policy.py` already draws: the documents are byte-identical every run and are most of the tokens, so they carry the cache breakpoint and are read back at a tenth of the price. Interpolating anything volatile above them would silently cost full price on every run. **Responses stream.** `max_tokens` is deliberately generous — truncation is a hard failure rather than a short day — and the SDK refuses a non-streaming request it estimates will outrun the HTTP timeout. **No `thinking` parameter is sent.** Models differ in how thinking is configured and which values they accept; the default is the portable choice, and `effort` (when the configured model supports it) is the knob that matters. Attributes ---------- .. autoapisummary:: curated_feed.claude.CACHE_CONTROL curated_feed.claude.TRUNCATED curated_feed.claude.REFUSED curated_feed.claude.RETRY_INSTRUCTION Classes ------- .. autoapisummary:: curated_feed.claude.TokenUsage curated_feed.claude.AnthropicScorer Functions --------- .. autoapisummary:: curated_feed.claude.build_client Module Contents --------------- .. py:data:: CACHE_CONTROL .. py:data:: TRUNCATED :value: 'max_tokens' .. py:data:: REFUSED :value: 'refusal' .. py:data:: RETRY_INSTRUCTION :value: Multiline-String .. raw:: html
Show Value .. code-block:: python """Your previous response did not validate: {feedback} Return the whole response again as valid JSON, corrected.""" .. raw:: html
.. py:class:: TokenUsage What a day of scoring cost, in tokens. Accumulated across attempts, so a day that needed a retry reports what the retry actually cost rather than what the successful call did. .. py:attribute:: calls :type: int :value: 0 .. py:attribute:: input_tokens :type: int :value: 0 .. py:attribute:: output_tokens :type: int :value: 0 .. py:attribute:: cache_read_tokens :type: int :value: 0 .. py:attribute:: cache_write_tokens :type: int :value: 0 .. py:method:: add(usage: object) -> None Fold one response's usage into the running total. .. py:method:: format() -> str One line for the run report. >>> TokenUsage(calls=1, input_tokens=2, output_tokens=3).format() '1 call, 2 in (0 cached), 3 out' .. py:class:: AnthropicScorer(*, model: str, max_tokens: int, effort: str = '', timeout_seconds: float | None = None, client: anthropic.Anthropic | None = None) Scores a day of candidates with Claude. .. py:attribute:: name :value: 'anthropic' .. py:attribute:: model .. py:attribute:: max_tokens .. py:attribute:: effort :value: '' .. py:attribute:: usage .. py:method:: generate(candidates: collections.abc.Sequence[curated_feed.models.Candidate], prompt: curated_feed.policy.Prompt, *, feedback: str | None = None) -> str One call: the day's prompt in, the raw response text out. .. py:function:: build_client(timeout_seconds: float | None) -> anthropic.Anthropic A client with credentials resolved by the SDK. No key is read here on purpose: the SDK also accepts an `ant auth login` profile and workload identity, so an unset `ANTHROPIC_API_KEY` does not mean there are no credentials. An actual failure surfaces on the first call. Public because it is the seam. A scorer built by hand takes its client directly, but the one the pipeline builds cannot: `score.make_scorer` reads configuration, and a client is not something configuration should hold. This factory is therefore what a test substitutes to run the whole chain against a fake, and a default nobody can substitute is the thing `deploy.py` already learned to avoid.