Provider Protocol
Anything with the right generate() signature is a provider. No inheritance, no registration, no base class.
A tiny, swappable LLM core. A Protocol, a few dataclasses, one optional provider.
pip install loomkitfrom loomkit import Messagefrom loomkit.providers.gemini import GeminiProvider provider = GeminiProvider()resp = provider.generate( [Message(role="user", content="Name three primary colors.")], model="gemini-2.5-flash",)print(resp.text)v0 ships only what you need to call a model and swap backends later. Everything else is deliberately deferred.
Anything with the right generate() signature is a provider. No inheritance, no registration, no base class.
A handful of dataclasses. The smallest useful surface for chat-style generation.
One concrete provider via the official google-genai SDK. Optional extra. Core stays zero-deps.
Streaming, tools, retries, and agents land through the Provider seam without breaking call sites.
Install the Gemini extra, set GEMINI_API_KEY or GOOGLE_API_KEY, and call generate().
import osfrom loomkit import Messagefrom loomkit.providers.gemini import GeminiProvider # Reads GEMINI_API_KEY (or GOOGLE_API_KEY) from envprovider = GeminiProvider() resp = provider.generate( [ Message(role="system", content="You are concise."), Message(role="user", content="Name three primary colors."), ], model="gemini-2.5-flash", temperature=0.2,) print(resp.text)print(resp.finish_reason, resp.usage)Provider is a typing.Protocol. Adding a new backend means writing one class with a generate() method matching the signature. No imports from loomkit, no inheritance, no registration.
Call sites typed against Provider accept any conforming class.
class MyProvider: def generate(self, messages, *, model, temperature=None, max_tokens=None, stop=None) -> Response: ... # No loomkit imports. No inheritance. No registration. # Call sites typed against Provider accept any conforming class.Features layer through the Provider seam without breaking existing call sites. No kitchen-sink framework, just composable surfaces.
Streaming
generate_stream() returning chunk iterables
Tool / function calling
tools= kwarg; Message.content grows to a parts list
Async
Sibling AsyncProvider Protocol with async def generate(...)
Retries / rate limiting
Decorator providers: RetryingProvider(inner, ...)
Tracing / observability
Same shape: TracingProvider(inner, sink)
Agent loops
One layer up: loomkit.agents consumes a Provider
Graphs
Top of the stack; consumes agents
Core is zero-deps. Gemini and dev tooling are optional extras. Requires Python 3.10+.
Core only
Zero dependencies
pip install loomkitWith Gemini
Adds google-genai
pip install 'loomkit[gemini]'Dev setup
Plus pytest
pip install 'loomkit[gemini,dev]'