Skip to content

v0.5.0 (beta)

Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 12 Oct 06:18
51b834e

thunc 0.5.0 makes code that uses thunc testable and extensible. thunc.testing gives your tests a scripted fake model and pytest fixtures, thunc.register_backend plugs in a backend of your own, and the docs cover Ollama. With record and replay from 0.4, you can test code that uses thunc with no model at all. A program that uses none of these behaves as in 0.4.0.

pip install --upgrade thunc

A fake model for your tests: thunc.testing

from thunc import testing


def test_triage():
    with testing.fake_model({"urgency": 4, "category": "bug"}) as model:
        assert triage("I was charged twice") == ("bug", 4)
    assert model.calls[0].inputs == {"ticket": "I was charged twice"}


def test_triage_with_pytest(thunc_model):  # the same, as a fixture that comes with thunc
    thunc_model.reply({"urgency": 4, "category": "bug"})
    assert triage("I was charged twice") == ("bug", 4)
  • Every call and agent run goes to the fake model while it's active, whatever backend= it names, and the recordings are left alone.
  • Replies go by function name, in order, or come from a function of the request. A string is the model's text as it is, so "high" for an int makes the call retry as a real one would. Anything else is sent as JSON, so 4, Priority.HIGH or a dataclass work as written.
  • model.calls keeps every request: its function, inputs, return type, the prompt sent, and which attempt or step it was.
  • Agents: [testing.act("read", path="config.py"), testing.finish(60)]. The tools run for real.
  • testing.isolated(), or the thunc_isolated fixture, puts thunc's settings back after a block.

Your own backend: thunc.register_backend

def local(text, *, system, model, api_key, timeout):
    return my_client.complete(system=system, prompt=text, model=model or "small", timeout=timeout)


thunc.register_backend("local", local, default_model="small")
thunc.configure(backend="local")
  • Usable as backend=, configure(backend=...) and THUNC_BACKEND. Agents run on it through the JSON text protocol.
  • Its signature is checked when it's registered. An agent's effort= is only passed to a backend that takes it.
  • typed=True registers a backend that answers typed questions, as jev does. thunc.TextBackend and thunc.TypedBackend are the two shapes, for type hints. Raise thunc.TransientError for errors worth asking again.

Ollama

  • Ollama 0.13.3 and later serve the OpenAI Responses API the openai backend uses: set OPENAI_BASE_URL=http://localhost:11434/v1 and OPENAI_API_KEY=ollama, then configure(backend="openai", model="qwen3:8b").
  • live_tests/test_ollama.py checks a model end to end: text, typed answers, and an agent on both protocols. It hasn't been run for this release; results are welcome in issues.

Tested

  • Offline tests run on Python 3.10–3.14 on Ubuntu, and on Windows, with new tests for the fake model, its fixtures (loaded through the entry point, in a separate pytest run, as yours are) and register_backend. The type checks in tests/test_typing.py cover the new API under mypy and basedpyright.

Behavior changes

  • None for existing programs. thunc now registers a pytest plugin (the thunc_model and thunc_isolated fixtures), loaded by pytest when thunc is installed; it adds nothing else to your test runs.

Full changelog: v0.4.0...v0.5.0