Repository navigation
v0.5.0 (beta)
Pre-release
Pre-release
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 thuncA 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 anintmakes the call retry as a real one would. Anything else is sent as JSON, so4,Priority.HIGHor a dataclass work as written. model.callskeeps 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 thethunc_isolatedfixture, 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=...)andTHUNC_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=Trueregisters a backend that answers typed questions, asjevdoes.thunc.TextBackendandthunc.TypedBackendare the two shapes, for type hints. Raisethunc.TransientErrorfor errors worth asking again.
Ollama
- Ollama 0.13.3 and later serve the OpenAI Responses API the
openaibackend uses: setOPENAI_BASE_URL=http://localhost:11434/v1andOPENAI_API_KEY=ollama, thenconfigure(backend="openai", model="qwen3:8b"). live_tests/test_ollama.pychecks 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 intests/test_typing.pycover the new API under mypy and basedpyright.
Behavior changes
- None for existing programs. thunc now registers a pytest plugin (the
thunc_modelandthunc_isolatedfixtures), loaded by pytest when thunc is installed; it adds nothing else to your test runs.
Full changelog: v0.4.0...v0.5.0