windlass.interfaces.llm¶
llm
¶
The LLM interface.
Every model provider — OpenAI, Anthropic, Gemini, Groq, Ollama, or your own —
implements this one class. Agents, RAG pipelines, evaluators and guardrails all
talk to :class:LLM, never to a vendor SDK, which is what makes swapping
providers a one-word change.
Implementers override exactly two coroutines:
- :meth:
LLM.agenerate— a single completion. - :meth:
LLM.astream_generate— incremental events (optional; the default emits the finished completion as one chunk).
Everything else — the blocking API, prompt coercion, retries, tool-schema plumbing — is provided here.
Example
from windlass.providers.llm.fake import FakeLLM llm = FakeLLM(responses=["Paris"]) llm.complete("Capital of France?").content 'Paris'
LLM
¶
LLM(
model: str = "",
*,
temperature: float | None = None,
max_tokens: int | None = None,
timeout: float | None = None,
system_prompt: str | None = None,
name: str | None = None,
**config: Any
)
Bases: Component
Abstract chat-completion model.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model
|
str
|
Model identifier passed to the provider. |
''
|
temperature
|
float | None
|
Sampling temperature. Falls back to the global setting. |
None
|
max_tokens
|
int | None
|
Completion ceiling. |
None
|
timeout
|
float | None
|
Per-request timeout in seconds. |
None
|
system_prompt
|
str | None
|
Prepended to every call that does not already start with a system message. |
None
|
name
|
str | None
|
Component name for traces. Defaults to the provider name. |
None
|
**config
|
Any
|
Provider-specific options forwarded verbatim to the SDK. |
{}
|
Attributes:
| Name | Type | Description |
|---|---|---|
model |
The configured model identifier. |
|
temperature |
float
|
The configured sampling temperature. |
max_tokens |
int | None
|
The configured completion ceiling. |
supports_tools |
bool
|
Whether this provider can do native tool calling. |
supports_streaming |
bool
|
Whether this provider can stream. |
Example
Implementing a provider takes one method::
class MyLLM(LLM):
provider_name = "mine"
async def agenerate(self, messages, *, tools=None, **kw):
text = await my_sdk.chat(messages[-1].content)
return Completion(content=text, model=self.model)
Source code in src\windlass\interfaces\llm.py
default_model
classmethod
¶
Return the model used when the caller does not name one.
Returns:
| Type | Description |
|---|---|
str
|
A provider-appropriate default model identifier. |
agenerate
abstractmethod
async
¶
agenerate(
messages: list[Message], *, tools: list[dict[str, Any]] | None = None, **kwargs: Any
) -> Completion
Produce one completion.
This is the only method a provider must implement.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
messages
|
list[Message]
|
The conversation, already normalised and with the system prompt applied. |
required |
tools
|
list[dict[str, Any]] | None
|
JSON-schema tool definitions in OpenAI function-calling format. Adapters translate these into their own shape. |
None
|
**kwargs
|
Any
|
Per-call overrides ( |
{}
|
Returns:
| Type | Description |
|---|---|
Completion
|
The completion, with |
Raises:
| Type | Description |
|---|---|
ProviderError
|
For any provider-side failure. |
Source code in src\windlass\interfaces\llm.py
astream_generate
async
¶
astream_generate(
messages: list[Message], *, tools: list[dict[str, Any]] | None = None, **kwargs: Any
) -> AsyncIterator[StreamEvent]
Produce incremental completion events.
The default implementation calls :meth:agenerate and emits the result
as a single text event followed by done — correct, but not
actually incremental. Providers that support streaming should override
this.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
messages
|
list[Message]
|
The normalised conversation. |
required |
tools
|
list[dict[str, Any]] | None
|
Tool definitions. |
None
|
**kwargs
|
Any
|
Per-call overrides. |
{}
|
Yields:
| Type | Description |
|---|---|
AsyncIterator[StreamEvent]
|
class: |
Source code in src\windlass\interfaces\llm.py
acomplete
async
¶
acomplete(
prompt: PromptLike,
*,
tools: list[dict[str, Any]] | None = None,
retry: bool = True,
**kwargs: Any
) -> Completion
Generate a completion, with retries and timing.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
prompt
|
PromptLike
|
A string, a message, or a full transcript. |
required |
tools
|
list[dict[str, Any]] | None
|
Tool definitions the model may call. |
None
|
retry
|
bool
|
Apply the configured retry policy to transient failures. |
True
|
**kwargs
|
Any
|
Per-call overrides forwarded to the provider. |
{}
|
Returns:
| Type | Description |
|---|---|
Completion
|
The completion. |
Raises:
| Type | Description |
|---|---|
ProviderError
|
When the provider fails and retries are exhausted. |
AuthenticationError
|
When credentials are missing or rejected. |
Performance
One network round trip. Set retry=False on latency-critical
paths where you would rather fail fast than wait out a backoff.
Example
import asyncio from windlass.providers.llm.fake import FakeLLM asyncio.run(FakeLLM(responses=["hi"]).acomplete("hello")).content 'hi'
Source code in src\windlass\interfaces\llm.py
complete
¶
complete(
prompt: PromptLike,
*,
tools: list[dict[str, Any]] | None = None,
retry: bool = True,
**kwargs: Any
) -> Completion
Blocking :meth:acomplete.
Safe to call from a notebook or from inside a running event loop; the call is dispatched to a background loop when necessary.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
prompt
|
PromptLike
|
A string, a message, or a full transcript. |
required |
tools
|
list[dict[str, Any]] | None
|
Tool definitions the model may call. |
None
|
retry
|
bool
|
Apply the configured retry policy. |
True
|
**kwargs
|
Any
|
Per-call overrides. |
{}
|
Returns:
| Type | Description |
|---|---|
Completion
|
The completion. |
Source code in src\windlass\interfaces\llm.py
astream
async
¶
astream(
prompt: PromptLike, *, tools: list[dict[str, Any]] | None = None, **kwargs: Any
) -> AsyncIterator[StreamEvent]
Stream a completion as it is generated.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
prompt
|
PromptLike
|
A string, a message, or a full transcript. |
required |
tools
|
list[dict[str, Any]] | None
|
Tool definitions. |
None
|
**kwargs
|
Any
|
Per-call overrides. |
{}
|
Yields:
| Type | Description |
|---|---|
AsyncIterator[StreamEvent]
|
Stream events. Text deltas arrive as they are produced; the final |
AsyncIterator[StreamEvent]
|
event is always |
Example
import asyncio from windlass.providers.llm.fake import FakeLLM async def main(): ... llm = FakeLLM(responses=["hey"]) ... return "".join([e.delta async for e in llm.astream("hi")]) asyncio.run(main()) 'hey'
Source code in src\windlass\interfaces\llm.py
stream
¶
stream(
prompt: PromptLike, *, tools: list[dict[str, Any]] | None = None, **kwargs: Any
) -> Iterator[StreamEvent]
Blocking :meth:astream.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
prompt
|
PromptLike
|
A string, a message, or a full transcript. |
required |
tools
|
list[dict[str, Any]] | None
|
Tool definitions. |
None
|
**kwargs
|
Any
|
Per-call overrides. |
{}
|
Yields:
| Type | Description |
|---|---|
StreamEvent
|
Stream events, pulled one at a time so nothing is buffered ahead of |
StreamEvent
|
the consumer. |
Source code in src\windlass\interfaces\llm.py
astream_text
async
¶
Stream only the text deltas — the common case for chat UIs.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
prompt
|
PromptLike
|
A string, a message, or a full transcript. |
required |
**kwargs
|
Any
|
Per-call overrides. |
{}
|
Yields:
| Type | Description |
|---|---|
AsyncIterator[str]
|
Non-empty text fragments. |
Source code in src\windlass\interfaces\llm.py
abatch
async
¶
abatch(
prompts: Sequence[PromptLike], *, concurrency: int | None = None, **kwargs: Any
) -> list[Completion]
Complete many prompts with bounded concurrency.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
prompts
|
Sequence[PromptLike]
|
The prompts to run. |
required |
concurrency
|
int | None
|
Maximum simultaneous requests. Defaults to the global
|
None
|
**kwargs
|
Any
|
Per-call overrides applied to every prompt. |
{}
|
Returns:
| Type | Description |
|---|---|
list[Completion]
|
Completions in the same order as |
Performance
Bounded on purpose — an unbounded fan-out over a few hundred prompts is the fastest way to get rate limited.
Example
import asyncio from windlass.providers.llm.fake import FakeLLM llm = FakeLLM(responses=["a", "b"]) [c.content for c in asyncio.run(llm.abatch(["1", "2"]))]['a', 'b']
Source code in src\windlass\interfaces\llm.py
batch
¶
batch(
prompts: Sequence[PromptLike], *, concurrency: int | None = None, **kwargs: Any
) -> list[Completion]
Blocking :meth:abatch.