LLM providers¶
The vendor-neutral provider protocol and its implementations (OpenAI,
Anthropic, and a deterministic mock for tests), so the agent loop is decoupled
from any single LLM vendor. The real providers import their SDKs lazily, so this
layer is importable without the optional llm extra and only fails if a real
provider is instantiated without its SDK.
AnthropicProvider defaults to Claude Opus 5 (claude-opus-5) and
OpenAIProvider to gpt-5-mini. Both send a sampling temperature only when
a caller passes one, cap each reply at 16,000 tokens by default, and normalize
the model's stop reason (end_turn, tool_use, max_tokens, refusal,
pause_turn, or stop_sequence) so the agent loops can act on it.
llm
¶
Vendor-neutral LLM provider layer for the Fugacio copilot.
Importing this package pulls in only the neutral types and the in-memory
MockProvider; the real providers (OpenAIProvider,
AnthropicProvider) import their SDKs lazily, so they are importable here
without the optional llm extra installed and only fail if instantiated
without the SDK.
Modules:
| Name | Description |
|---|---|
anthropic |
Anthropic (Claude) Messages-API adapter for the Fugacio copilot. |
base |
Provider-neutral chat/tool-calling types for the Fugacio copilot. |
mock |
A deterministic in-memory provider for testing the agent loop without an API. |
openai |
OpenAI chat-completions adapter for the Fugacio copilot. |
Classes:
| Name | Description |
|---|---|
AnthropicProvider |
An |
ChatResponse |
A model's reply: free-text content and/or requested tool calls. |
LLMProvider |
A function-calling chat model. |
Message |
One turn in a chat transcript. |
ToolCall |
A model's request to invoke a tool. |
MockProvider |
A scripted |
OpenAIProvider |
An |
Functions:
| Name | Description |
|---|---|
anthropic_tools |
Map engine tool schemas to Anthropic's |
openai_tools |
Wrap engine tool schemas in OpenAI's |
AnthropicProvider
¶
AnthropicProvider(
model: str = "claude-opus-5",
*,
client: Any | None = None,
api_key: str | None = None,
fallbacks: str | None = "default",
)
An LLMProvider backed by the Anthropic Messages API.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model
|
str
|
Claude model id. |
'claude-opus-5'
|
client
|
Any | None
|
An existing |
None
|
api_key
|
str | None
|
API key passed to a freshly created client. |
None
|
fallbacks
|
str | None
|
Server-side refusal-fallback mode. With the default,
|
'default'
|
Methods:
| Name | Description |
|---|---|
chat |
Call the Messages API and parse the reply into a |
chat
¶
chat(
messages: Sequence[Message],
*,
tools: Sequence[JsonDict] = (),
temperature: float | None = None,
max_tokens: int = 16000,
) -> ChatResponse
Call the Messages API and parse the reply into a ChatResponse.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
messages
|
Sequence[Message]
|
The conversation so far; system messages become the top-level system prompt. |
required |
tools
|
Sequence[JsonDict]
|
Engine tool schemas the model may call. |
()
|
temperature
|
float | None
|
Sampling temperature. |
None
|
max_tokens
|
int
|
Per-reply output token cap, thinking included. |
16000
|
Returns:
| Type | Description |
|---|---|
ChatResponse
|
The parsed reply. A |
ChatResponse
|
|
ChatResponse
dataclass
¶
ChatResponse(
content: str = "",
tool_calls: tuple[ToolCall, ...] = (),
stop_reason: str | None = None,
provider_blocks: tuple[Any, ...] = (),
raw: Any = None,
)
A model's reply: free-text content and/or requested tool calls.
Check stop_reason before trusting the content: a "refusal" reply
carries no usable content, and a "max_tokens" reply was cut off.
Attributes:
| Name | Type | Description |
|---|---|---|
content |
str
|
The assistant's text (the final answer when there are no calls). |
tool_calls |
tuple[ToolCall, ...]
|
Any tool calls the model wants executed before continuing. |
stop_reason |
str | None
|
Why the model stopped, normalized as described in the
module docstring, or |
provider_blocks |
tuple[Any, ...]
|
Opaque provider content blocks (for example, Anthropic
|
raw |
Any
|
The provider's raw response object, for debugging (not portable). |
LLMProvider
¶
Bases: Protocol
A function-calling chat model.
Implementations translate the neutral Message / tool-schema inputs to
their own API and parse the reply into a ChatResponse.
Methods:
| Name | Description |
|---|---|
chat |
Return the model's reply to |
chat
¶
chat(
messages: Sequence[Message],
*,
tools: Sequence[JsonDict] = (),
temperature: float | None = None,
max_tokens: int = 16000,
) -> ChatResponse
Return the model's reply to messages with tools available.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
messages
|
Sequence[Message]
|
The conversation so far. |
required |
tools
|
Sequence[JsonDict]
|
Engine tool schemas the model may call. |
()
|
temperature
|
float | None
|
Sampling temperature. |
None
|
max_tokens
|
int
|
Per-reply output token cap. |
16000
|
Returns:
| Type | Description |
|---|---|
ChatResponse
|
The parsed |
Message
dataclass
¶
Message(
role: str,
content: str = "",
tool_calls: tuple[ToolCall, ...] = (),
tool_call_id: str | None = None,
name: str | None = None,
is_error: bool = False,
provider_blocks: tuple[Any, ...] = (),
)
One turn in a chat transcript.
Attributes:
| Name | Type | Description |
|---|---|---|
role |
str
|
|
content |
str
|
Text content (may be empty for an assistant tool-call turn). |
tool_calls |
tuple[ToolCall, ...]
|
Tool calls requested by an assistant turn. |
tool_call_id |
str | None
|
For a |
name |
str | None
|
For a |
is_error |
bool
|
For a |
provider_blocks |
tuple[Any, ...]
|
For an assistant turn, the opaque provider blocks
( |
Methods:
| Name | Description |
|---|---|
system |
A system instruction message. |
user |
A user message. |
assistant |
An assistant message, optionally requesting tool calls. |
tool |
A tool-result message answering a specific tool call. |
assistant
classmethod
¶
assistant(
content: str = "",
tool_calls: Sequence[ToolCall] = (),
provider_blocks: Sequence[Any] = (),
) -> Message
An assistant message, optionally requesting tool calls.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
content
|
str
|
The assistant's text. |
''
|
tool_calls
|
Sequence[ToolCall]
|
Tool calls the assistant requested. |
()
|
provider_blocks
|
Sequence[Any]
|
The reply's |
()
|
Returns:
| Type | Description |
|---|---|
Message
|
The assistant |
tool
classmethod
¶
tool(
content: str,
tool_call_id: str,
name: str | None = None,
*,
is_error: bool = False,
) -> Message
A tool-result message answering a specific tool call.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
content
|
str
|
The serialized tool result. |
required |
tool_call_id
|
str
|
Id of the call this message answers. |
required |
name
|
str | None
|
The tool name. |
None
|
is_error
|
bool
|
Whether the call failed ( |
False
|
Returns:
| Type | Description |
|---|---|
Message
|
The tool-result |
ToolCall
dataclass
¶
A model's request to invoke a tool.
Attributes:
| Name | Type | Description |
|---|---|---|
id |
str
|
Provider-assigned call id (echoed back with the result). |
name |
str
|
Tool name (must exist in the registry). |
arguments |
JsonDict
|
Parsed JSON arguments for the tool. When the provider
couldn't parse them, they hold the |
Methods:
| Name | Description |
|---|---|
invalid |
A call whose raw arguments couldn't be parsed into a JSON object. |
invalid
classmethod
¶
A call whose raw arguments couldn't be parsed into a JSON object.
The agent loops don't run such a call. They answer it with an error
result quoting raw and error, so the model can resend it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
call_id
|
str
|
Provider-assigned call id. |
required |
name
|
str
|
Requested tool name. |
required |
raw
|
str
|
The argument text exactly as the model produced it. |
required |
error
|
str
|
Why the text isn't a valid JSON object. |
required |
Returns:
| Type | Description |
|---|---|
ToolCall
|
A |
MockProvider
dataclass
¶
MockProvider(
script: Script,
calls: list[
tuple[list[Message], list[JsonDict]]
] = list(),
call_kwargs: list[JsonDict] = list(),
_index: int = 0,
)
A scripted LLMProvider.
Attributes:
| Name | Type | Description |
|---|---|---|
script |
Script
|
Either a list of replies returned in order, or a function
|
calls |
list[tuple[list[Message], list[JsonDict]]]
|
Recorded |
call_kwargs |
list[JsonDict]
|
Recorded |
Methods:
| Name | Description |
|---|---|
chat |
Return the next scripted reply (or evaluate the script callable). |
OpenAIProvider
¶
OpenAIProvider(
model: str = "gpt-5-mini",
*,
client: Any | None = None,
api_key: str | None = None,
)
An LLMProvider backed by the OpenAI API.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model
|
str
|
Chat model name. |
'gpt-5-mini'
|
client
|
Any | None
|
An existing |
None
|
api_key
|
str | None
|
API key passed to a freshly created client. |
None
|
Methods:
| Name | Description |
|---|---|
chat |
Call chat-completions and parse the reply into a |
chat
¶
chat(
messages: Sequence[Message],
*,
tools: Sequence[JsonDict] = (),
temperature: float | None = None,
max_tokens: int = 16000,
) -> ChatResponse
Call chat-completions and parse the reply into a ChatResponse.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
messages
|
Sequence[Message]
|
The conversation so far. |
required |
tools
|
Sequence[JsonDict]
|
Engine tool schemas the model may call. |
()
|
temperature
|
float | None
|
Sampling temperature. |
None
|
max_tokens
|
int
|
Per-reply output token cap, sent as
|
16000
|
Returns:
| Type | Description |
|---|---|
ChatResponse
|
The parsed reply. A |
ChatResponse
|
model refusal) carries no content, and a |
ChatResponse
|
keeps its text but drops its tool calls. |
anthropic_tools
¶
Map engine tool schemas to Anthropic's {"name", "description", "input_schema"}.