Skip to content

Providers

narratoflow ships adapters for three providers and a Mock for tests. All adapters implement the same surface so the pipeline does not care which one you pick.

provider sync async streaming JSON mode prompt cache
Anthropic ✅ ✅ not in narrato tool-use opt-in (cache=True)
OpenAI ✅ ✅ not in narrato response_format JSON schema automatic (≥1024 tok)
Ollama ✅ ✅ not in narrato format=json n/a
Mock ✅ ✅ n/a canned payloads n/a

Anthropic

from narrato.providers import get_provider
p = get_provider("anthropic", cache=True)
  • Reads ANTHROPIC_API_KEY from env.
  • JSON mode uses a forced tool call named emit so the model must emit a structured payload.
  • When cache=True, the system prompt (schema instructions + legend) is marked as an ephemeral cache breakpoint (5-min TTL). Cache reads are surfaced on ProviderResponse.cached_input_tokens.

OpenAI

from narrato.providers import get_provider
p = get_provider("openai")
  • Reads OPENAI_API_KEY from env.
  • JSON mode uses response_format = {"type": "json_schema", ...} (loose strictness) so any Pydantic schema works.
  • OpenAI's prompt cache is automatic for prompts ≥ 1024 tokens. The adapter reads usage.prompt_tokens_details.cached_tokens and exposes it on ProviderResponse.cached_input_tokens.

Ollama (local models)

from narrato.providers import get_provider
p = get_provider("ollama")  # uses OLLAMA_HOST or http://localhost:11434
  • Requires a running Ollama daemon. ollama pull <model> first.
  • JSON mode uses format=json plus a system-prompt schema reminder; small open models may produce loose JSON — the pipeline reports a validation_error instead of crashing.
  • No API key required.

Example with the Compressor:

from narrato import Compressor
c = Compressor(
    provider="ollama",
    extractor_model="llama3",
    target_model="llama3",
    source_lang="en",
    schema="qa",
)

Mock (testing)

from narrato.providers import MockProvider
from narrato import Compressor

mock = MockProvider(payload={"summary": "...", "claims": ["..."]})
c = Compressor(provider=mock, schema="qa", layers=["extract"])

MockProvider accepts a static dict, a callable that takes the user prompt and returns a payload, or a sequence of canned responses. It tracks calls_complete and calls_complete_json so tests can assert on number of LLM calls.

Bring your own provider

Subclass-by-protocol — implement complete, complete_json (and optionally the acomplete* async variants for Compressor.acompress support):

from narrato.providers import Provider, ProviderResponse

class MyProvider:
    name = "myco"

    def complete(self, system, user, model, max_tokens=2048, temperature=0.0):
        text = call_my_api(system, user, model)
        return ProviderResponse(text=text, input_tokens=0, output_tokens=0, model=model)

    def complete_json(self, system, user, model, schema=None, max_tokens=2048, temperature=0.0):
        ...

c = Compressor(provider=MyProvider(), ...)