Skip to content

AI Providers

AIProvider

Bases: ABC

AI model provider for generating responses.

name property

name

Provider name (e.g. 'anthropic', 'openai').

supports_vision property

supports_vision

Whether this provider can process images.

supports_streaming property

supports_streaming

Whether this provider supports streaming token generation.

supports_structured_streaming property

supports_structured_streaming

Whether this provider supports structured streaming with tool calls.

model_name abstractmethod property

model_name

Model identifier (e.g. 'claude-sonnet-4-20250514', 'gpt-4o').

context_window property

context_window

Input context window of the active model in tokens, if known.

Resolved offline from the curated :meth:available_models catalog keyed by :attr:model_name — no API key or network. Returns None when the active model is absent from the catalog (custom / local model ids, e.g. an arbitrary vLLM model string), so callers must degrade gracefully rather than assume a window.

available_models classmethod

available_models()

Curated, offline catalog of models known to this provider.

Returns a hand-maintained list — no API key or network required — so an integrator can discover configurable models by calling this on the class before instantiating. The base returns an empty list; each provider overrides it with its catalog.

list_models async

list_models()

Models reported live by the provider's API.

The base implementation returns the curated :meth:available_models. Providers whose API exposes a models endpoint override this to query it, backfilling missing metadata from the catalog via :meth:_merge_curated.

generate abstractmethod async

generate(context)

Generate an AI response from the given context.

Parameters:

Name Type Description Default
context AIContext

Conversation context including messages, system prompt, temperature, and target channel capabilities.

required

Returns:

Type Description
AIResponse

The AI response with content, usage stats, and optional

AIResponse

tasks/observations.

generate_stream async

generate_stream(context)

Yield text deltas as they arrive. Override for streaming providers.

generate_structured_stream async

generate_structured_stream(context)

Yield structured events (thinking deltas, text deltas, tool calls, done).

Default implementation wraps generate() so every provider works without changes. Override for true streaming support.

close async

close()

Release resources. Override in subclasses that hold connections.

AIContext

Bases: BaseModel

Context passed to AI provider for generation.

AIMessage

Bases: BaseModel

A message in the AI conversation context.

AITextPart

Bases: BaseModel

Text part of a multimodal message.

AIImagePart

Bases: BaseModel

Image part of a multimodal message.

AITool

Bases: BaseModel

Tool definition for function calling.

AIToolCall

Bases: BaseModel

A tool call from the AI response.

AIResponse

Bases: BaseModel

Response from an AI provider.

MockAIProvider

MockAIProvider(responses=None, *, vision=False, ai_responses=None, streaming=False)

Bases: AIProvider

Round-robin response provider for tests.

available_models classmethod

available_models()

Fixed two-entry catalog for exercising model-discovery code.

generate_stream async

generate_stream(context)

Yield text from generate() as a single delta.

generate_structured_stream async

generate_structured_stream(context)

Yield structured events from generate() result.

Per-Room AI Configuration

AI channel settings can be overridden per-room using binding metadata:

# Default AI channel
ai = AIChannel("ai", provider=anthropic, system_prompt="Default assistant")
kit.register_channel(ai)

# Override per room
kit.attach_channel(room_id, "ai", metadata={
    "system_prompt": "You are a customer support agent for Acme Corp.",
    "temperature": 0.3,  # More deterministic
    "max_tokens": 2048,
})

Silent Observer Pattern (Meeting Notes)

# Attach AI as note-taker
kit.attach_channel(meeting_room_id, "ai", metadata={
    "system_prompt": """You are a meeting note-taker.
    Listen to the conversation silently.
    When someone says 'meeting ended', compile and send a summary.""",
})

# Mute so AI listens but doesn't respond
await kit.mute(meeting_room_id, "ai")

# Later, unmute to let AI send summary
await kit.unmute(meeting_room_id, "ai")

Tools/Function Calling

Tools can be passed via binding metadata for function calling:

kit.attach_channel(room_id, "ai", metadata={
    "tools": [
        {
            "name": "search_knowledge_base",
            "description": "Search the company knowledge base",
            "parameters": {
                "type": "object",
                "properties": {
                    "query": {"type": "string"}
                },
                "required": ["query"]
            }
        }
    ]
})

Tool calls are returned in AIResponse.tool_calls:

response = await provider.generate(context)
for tool_call in response.tool_calls:
    print(f"Tool: {tool_call.name}, Args: {tool_call.arguments}")

Gemini Provider

GeminiAIProvider

GeminiAIProvider(config)

Bases: AIProvider

AI provider using the Google Gemini API.

supports_vision property

supports_vision

All Gemini models support vision.

available_models classmethod

available_models()

Curated, offline catalog of Gemini models.

list_models async

list_models()

List generate-content models the Gemini API currently exposes.

generate_structured_stream async

generate_structured_stream(context)

Yield structured events from the Gemini streaming API.

generate async

generate(context)

Generate by consuming the structured stream.

generate_stream async

generate_stream(context)

Yield text deltas as they arrive from the Gemini API.

close async

close()

Release the genai client reference.

GeminiConfig

Bases: BaseModel

Google Gemini AI provider configuration.

thinking_level class-attribute instance-attribute

thinking_level = None

Thinking level for Gemini 3.1 models: minimal, low, medium, high.

Usage

from roomkit.providers.gemini.ai import GeminiAIProvider
from roomkit.providers.gemini.config import GeminiConfig

config = GeminiConfig(api_key="your-api-key")
provider = GeminiAIProvider(config)

# Use with AIChannel
ai_channel = AIChannel("ai", provider=provider)

Install with: pip install roomkit[gemini]

Schema Cleaning

Gemini rejects extra JSON Schema fields common in MCP/OpenAPI tool definitions. RoomKit auto-cleans schemas when building FunctionDeclaration objects:

clean_gemini_schema

clean_gemini_schema(schema)

Recursively prepare a JSON Schema for Gemini FunctionDeclaration.

Performs two passes per node:

  1. Collapse Pydantic-style Optionals. {"anyOf": [{...}, {"type": "null"}]} becomes {..., "nullable": true}. oneOf / allOf are handled the same way for symmetry. When the union has multiple non-null branches, we keep the first one and add nullable if any branch was null — Gemini's schema dialect does not support full union types.
  2. Strip unknown keys. Anything not in :data:_GEMINI_ALLOWED_KEYS (e.g. $schema, additionalProperties, default, title) is dropped at every nesting level.

Parameters:

Name Type Description Default
schema dict[str, Any] | None

A JSON Schema dict (e.g. tool parameter schema), or None.

required

Returns:

Type Description
dict[str, Any] | None

A cleaned copy, or None if input was None.

vLLM Provider (Local LLM)

VLLMConfig

Bases: BaseModel

Configuration for a local vLLM server.

vLLM exposes an OpenAI-compatible API, so this config is translated into an OpenAIConfig by :func:create_vllm_provider.

Attributes:

Name Type Description
model str

Model name loaded by the vLLM server (required).

base_url str

Base URL of the vLLM OpenAI-compatible endpoint.

api_key SecretStr

Bearer token sent as Authorization: Bearer <key>. Matches vllm serve --api-key; default "none" for the common no-auth local server.

max_tokens int

Maximum tokens in the response.

temperature float

Sampling temperature.

timeout float

HTTP request timeout in seconds. Increase for vLLM servers that load models lazily on first request.

headers dict[str, str] | None

Extra HTTP headers on every request — for a reverse proxy that needs custom headers, or a non-Bearer Authorization scheme. Maps to OpenAIConfig.default_headers.

extra_body dict[str, Any] | None

Extra JSON fields merged into every request body — the route for vLLM-specific params (guided_json/guided_choice guided decoding, top_k/repetition_penalty sampling). Maps to OpenAIConfig.extra_body.

max_retries class-attribute instance-attribute

max_retries = 0

SDK-level retry count. Default 0 because RoomKit's RetryPolicy handles retries at the right layer with proper backoff and fallback.

include_stream_usage class-attribute instance-attribute

include_stream_usage = False

When True, request token usage in streaming responses.

headers class-attribute instance-attribute

headers = None

Extra HTTP headers sent on every request (proxy headers, non-Bearer auth). None sends only the SDK defaults.

extra_body class-attribute instance-attribute

extra_body = None

Extra request-body fields for vLLM-specific params (guided decoding, extra sampling). None sends a vanilla body.

create_vllm_provider

create_vllm_provider(config)

Create an OpenAI-compatible AI provider pointed at a local vLLM server.

This is a factory function — no new subclass is needed because vLLM implements the OpenAI Chat Completions API. The openai SDK is imported lazily when :class:OpenAIAIProvider is instantiated.

Note

The returned provider inherits :meth:OpenAIAIProvider.available_models, whose curated catalog lists OpenAI's hosted models — not whatever a local vLLM server serves. For a vLLM deployment, call :meth:~OpenAIAIProvider.list_models instead: it queries the server's /v1/models endpoint and returns the models actually loaded there.

Parameters:

Name Type Description Default
config VLLMConfig

vLLM connection settings.

required

Returns:

Name Type Description
An OpenAIAIProvider

class:OpenAIAIProvider configured for the local vLLM server.

Usage

from roomkit.providers.vllm import create_vllm_provider, VLLMConfig
from roomkit.channels.ai import AIChannel

# Configure connection to a local vLLM server
config = VLLMConfig(
    model="meta-llama/Llama-3.1-8B-Instruct",
    base_url="http://localhost:8000/v1",
)

# Factory returns an OpenAIAIProvider pointed at your vLLM server
provider = create_vllm_provider(config)

# Use with AIChannel like any other AI provider
ai_channel = AIChannel("ai", provider=provider)

Install with: pip install roomkit[vllm]

Anthropic Provider

AnthropicAIProvider

AnthropicAIProvider(config)

Bases: AIProvider

AI provider using the Anthropic Messages API.

supports_vision property

supports_vision

Claude 3+ models support vision.

available_models classmethod

available_models()

Curated, offline catalog of Claude models.

list_models async

list_models()

List models the Anthropic API currently exposes for this key.

generate_structured_stream async

generate_structured_stream(context)

Yield structured events from the Anthropic Messages streaming API.

When extended thinking is enabled, yields StreamThinkingDelta events before text deltas.

generate async

generate(context)

Generate by consuming the structured stream.

generate_stream async

generate_stream(context)

Yield text deltas as they arrive from the Anthropic Messages API.

close async

close()

Close the underlying HTTP client.

AnthropicConfig

Bases: BaseModel

Anthropic AI provider configuration.

timeout class-attribute instance-attribute

timeout = 60.0

Request timeout in seconds (default 60s).

base_url class-attribute instance-attribute

base_url = None

Override the base URL (e.g., for Claude Code sandbox proxy).

extra_headers class-attribute instance-attribute

extra_headers = None

Extra headers sent with every request (e.g., X-Tenant-ID).

enable_prompt_caching class-attribute instance-attribute

enable_prompt_caching = True

Apply Anthropic prompt caching (explicit cache_control markers) to the stable request prefix — tools, system prompt, and the conversation suffix. Every tool-loop round re-sends the full context; without markers it is billed at the full input rate on every round, with them the prefix re-reads at the cached rate (10%). Disable for proxies that reject cache_control blocks.

use_adaptive_thinking class-attribute instance-attribute

use_adaptive_thinking = False

Send extended thinking as {"type": "adaptive"} instead of the deprecated {"type": "enabled", "budget_tokens": N}. Anthropic's newer models (Opus 4.7/4.8, Fable 5) reject budget_tokens with HTTP 400; adaptive is the modern, recommended shape on Opus 4.6+ and Sonnet 4.6. Leave False for older models (Sonnet 4.5 and earlier) that only accept budget_tokens.

supports_custom_temperature class-attribute instance-attribute

supports_custom_temperature = True

When False, temperature is omitted from requests. Anthropic's reasoning models (Opus 4.7/4.8, Fable 5) removed the sampling parameters and reject temperature with HTTP 400.

Usage

from roomkit.providers.anthropic.ai import AnthropicAIProvider
from roomkit.providers.anthropic.config import AnthropicConfig
from roomkit.channels.ai import AIChannel

config = AnthropicConfig(api_key="your-api-key")
provider = AnthropicAIProvider(config)

ai_channel = AIChannel("ai", provider=provider)

Install with: pip install roomkit[anthropic]

OpenAI Provider

OpenAIAIProvider

OpenAIAIProvider(config)

Bases: AIProvider

AI provider using the OpenAI Chat Completions API.

supports_vision property

supports_vision

GPT-4o and GPT-4-turbo models support vision.

available_models classmethod

available_models()

Curated, offline catalog of OpenAI chat/multimodal models.

list_models async

list_models()

List every model id the configured endpoint exposes.

The OpenAI /v1/models response carries only ids — metadata for known chat models is backfilled from the curated catalog. The raw list also includes non-chat models (embeddings, audio); they pass through unfiltered since the endpoint reports no capability field.

generate_structured_stream async

generate_structured_stream(context)

Yield structured events with <think> tag parsing.

Text inside <think>...</think> is yielded as :class:StreamThinkingDelta; everything else as :class:StreamTextDelta. Tool calls are collected from the final chunks and yielded as :class:StreamToolCall.

generate_stream async

generate_stream(context)

Yield text deltas (thinking content filtered out).

close async

close()

Close the underlying HTTP client.

OpenAIConfig

Bases: BaseModel

OpenAI AI provider configuration.

Attributes:

Name Type Description
api_key SecretStr

API key for authentication.

base_url str | None

Custom base URL for OpenAI-compatible APIs (e.g., Ollama, LM Studio, Azure OpenAI, or other providers). If None, uses the default OpenAI API.

model str

Model identifier to use.

max_tokens int

Maximum tokens in the response.

temperature float

Sampling temperature.

timeout class-attribute instance-attribute

timeout = 30.0

HTTP request timeout in seconds. Override for servers that need longer (e.g. Ollama cold-starting a model on first request).

max_retries class-attribute instance-attribute

max_retries = 0

SDK-level retry count. Default 0 because RoomKit's RetryPolicy handles retries at the right layer with proper backoff and fallback.

include_stream_usage class-attribute instance-attribute

include_stream_usage = False

When True, request token usage in streaming responses via stream_options.include_usage. The usage is included in the final :class:StreamDone event.

use_max_completion_tokens class-attribute instance-attribute

use_max_completion_tokens = False

Send the output cap as max_completion_tokens instead of the deprecated max_tokens. OpenAI's newer models (o-series, gpt-5, gpt-4.1) reject max_tokens outright. Leave False for OpenAI-compatible servers (vLLM, LM Studio, older Azure deployments) that only understand max_tokens.

supports_custom_temperature class-attribute instance-attribute

supports_custom_temperature = True

When False, temperature is omitted from requests. OpenAI's reasoning models (o-series, gpt-5) accept only the default temperature=1 and reject any other value with HTTP 400.

reasoning_effort class-attribute instance-attribute

reasoning_effort = None

Reasoning depth for OpenAI reasoning models (o-series, gpt-5): "low" | "medium" | "high". Controls how long the model reasons (quality vs latency/cost); the reasoning trace itself stays hidden in the Chat Completions API. None = the model's default. Only send it for reasoning models — others reject the parameter.

default_headers class-attribute instance-attribute

default_headers = None

Extra HTTP headers sent on every request, passed to the SDK's default_headers. Use for an OpenAI-compatible endpoint behind a reverse proxy that needs custom headers, or a non-Bearer Authorization scheme (e.g. Basic). None sends only the SDK's own headers; the api_key Bearer token is unaffected.

extra_body class-attribute instance-attribute

extra_body = None

Extra JSON fields merged into every Chat Completions request body via the SDK's extra_body. The route for server-specific params the OpenAI schema omits — e.g. vLLM guided decoding (guided_json/guided_choice) and extra sampling (top_k, repetition_penalty, min_p). None sends a vanilla body.

Usage

from roomkit.providers.openai.ai import OpenAIAIProvider
from roomkit.providers.openai.config import OpenAIConfig
from roomkit.channels.ai import AIChannel

config = OpenAIConfig(api_key="your-api-key")
provider = OpenAIAIProvider(config)

ai_channel = AIChannel("ai", provider=provider)

Install with: pip install roomkit[openai]

Mistral Provider

MistralAIProvider

MistralAIProvider(config)

Bases: AIProvider

AI provider using the Mistral AI API.

Supports streaming, tool calling, vision (multimodal models), and <think> tag parsing for reasoning models.

available_models classmethod

available_models()

Curated, offline catalog of Mistral chat/multimodal models.

list_models async

list_models()

List models the Mistral API currently exposes for this key.

generate_structured_stream async

generate_structured_stream(context)

Yield structured events with <think> tag parsing.

Text inside <think>...</think> is yielded as :class:StreamThinkingDelta; everything else as :class:StreamTextDelta. Tool calls are accumulated from deltas and yielded as :class:StreamToolCall.

generate async

generate(context)

Generate by consuming the structured stream.

generate_stream async

generate_stream(context)

Yield text deltas as they arrive from the Mistral API.

close async

close()

Close the underlying HTTP client.

MistralConfig

Bases: BaseModel

Mistral AI provider configuration.

Attributes:

Name Type Description
api_key SecretStr

Mistral API key for authentication.

model str

Model identifier (e.g. 'mistral-large-latest', 'pixtral-large-latest').

max_tokens int

Maximum tokens in the response.

temperature float

Sampling temperature.

server_url str | None

Custom base URL for Mistral-compatible APIs. If None, uses the default Mistral endpoint.

reasoning_effort str | None

Reasoning effort for models that expose it (mistral-small-latest, mistral-medium-3-5): "high" streams a reasoning trace before the answer, "none" omits it. None leaves it to the model's default (Magistral models always reason). Overridden per-turn by AIContext.thinking_budget.

Usage

from roomkit.providers.mistral.ai import MistralAIProvider
from roomkit.providers.mistral.config import MistralConfig
from roomkit.channels.ai import AIChannel

config = MistralConfig(api_key="your-api-key")
provider = MistralAIProvider(config)

ai_channel = AIChannel("ai", provider=provider)

Install with: pip install roomkit[mistral]

Azure Provider

AzureAIProvider

AzureAIProvider(config)

Bases: OpenAIAIProvider

AI provider using Azure AI Studio's OpenAI-compatible Chat Completions API.

Subclasses :class:OpenAIAIProvider — only client initialisation and provider name differ. All message building, tool handling, response parsing, and streaming are inherited.

available_models classmethod

available_models()

Azure exposes user-named deployments, not a fixed model catalog.

Deployment names are chosen per Azure resource, so there is no meaningful offline list — use :meth:list_models for the live set.

AzureAIConfig

Bases: BaseModel

Azure AI Studio provider configuration.

Uses the OpenAI-compatible Chat Completions API exposed by Azure AI Foundry deployments (DeepSeek, GPT-4o, Mistral, etc.).

Attributes:

Name Type Description
api_key SecretStr

Azure API key for authentication.

azure_endpoint str

Azure AI Foundry project endpoint URL.

api_version str

Azure API version string.

model str

Deployment name (no default — user must specify).

max_tokens int

Maximum tokens in the response.

temperature float

Sampling temperature.

timeout float

HTTP request timeout in seconds.

max_retries class-attribute instance-attribute

max_retries = 0

SDK-level retry count. Default 0 because RoomKit's RetryPolicy handles retries at the right layer with proper backoff and fallback.

include_stream_usage class-attribute instance-attribute

include_stream_usage = False

When True, request token usage in streaming responses.

use_max_completion_tokens class-attribute instance-attribute

use_max_completion_tokens = False

Send the output cap as max_completion_tokens rather than the deprecated max_tokens. Required by newer Azure-hosted OpenAI models; leave False for deployments that only understand max_tokens.

supports_custom_temperature class-attribute instance-attribute

supports_custom_temperature = True

When False, temperature is omitted — reasoning deployments accept only the default and reject any other value with HTTP 400.

reasoning_effort class-attribute instance-attribute

reasoning_effort = None

Reasoning depth for reasoning deployments ("low"/"medium"/ "high"); None uses the model default. Only sent for models that accept it.

extra_body class-attribute instance-attribute

extra_body = None

Extra JSON fields merged into every request body via the SDK's extra_body — for deployment-specific params the OpenAI schema omits. None sends a vanilla body.

Usage

from roomkit.providers.azure.ai import AzureAIProvider
from roomkit.providers.azure.config import AzureAIConfig
from roomkit.channels.ai import AIChannel

config = AzureAIConfig(
    azure_endpoint="https://your-resource.openai.azure.com/",
    api_key="your-api-key",
    deployment="your-deployment-name",
)
provider = AzureAIProvider(config)

ai_channel = AIChannel("ai", provider=provider)

Install with: pip install roomkit[azure]

Ollama Provider (Local / Cloud LLM)

Native provider for Ollama. Calls /api/chat directly, so the think parameter and streamed reasoning work without <think> tag parsing. See AI Thinking — Native Ollama provider for thinking, authentication, and sampling options (temperature, num_ctx, top_p, top_k, min_p, keep_alive).

OllamaAIProvider

OllamaAIProvider(config)

Bases: AIProvider

AI provider using Ollama's native API via the ollama-python SDK.

available_models classmethod

available_models()

Curated, offline snapshot of popular public Ollama models.

list_models async

list_models()

List models installed on the configured Ollama server.

Reads /api/tags for the installed set, then probes /api/show per model (bounded parallel fan-out) to attach capabilities — the tags the picker uses to keep completion-only models out of an embeddings channel and vice-versa. A per-model probe failure yields no capabilities for that model (older servers don't ship the field); consumers treat empty as "unknown, allow everywhere".

generate_stream async

generate_stream(context)

Yield text deltas (thinking content filtered out).

generate_structured_stream async

generate_structured_stream(context)

Yield structured events with thinking streamed separately.

Ollama's native streaming emits one chunk per token-ish, each with message.thinking and/or message.content deltas plus an optional final message.tool_calls. We pass these straight through as the corresponding StreamThinkingDelta, StreamTextDelta, and StreamToolCall events — no tag parsing, no field reordering.

close async

close()

Release the underlying httpx client.

OllamaConfig

Bases: BaseModel

Ollama AI provider configuration.

Wraps the native Ollama /api/chat endpoint via the ollama-python SDK. Prefer this over the OpenAI-compatible shim when the model is a reasoning model (DeepSeek-R1, Qwen 3 thinking variants, etc.) because Ollama exposes the think parameter and streams the reasoning content as a separate thinking field — both ignored by the OpenAI-compat endpoint.

Attributes:

Name Type Description
host str

Base URL of the Ollama server. Default points at the local daemon. The native API lives under /api on the same host; the SDK appends the path.

model str

Model identifier to use (e.g. "qwen3:8b", "llama3.2", "deepseek-r1:7b").

max_tokens int | None

Maximum tokens to generate in the response. Maps to Ollama's options.num_predict. None lets the server pick its default.

temperature float

Sampling temperature. Maps to options.temperature.

timeout float

HTTP request timeout in seconds. Long default because local models cold-start on first request and reasoning models can take 30-60s before the first token.

max_retries int

SDK-level retry count. Default 0 because RoomKit's RetryPolicy handles retries at the right layer with proper backoff and fallback.

think bool | ThinkEffort | None

Whether and how hard the model should reason before answering. None (default) means "use the model's default" — reasoning models think, others don't. True/False force thinking on or off as a boolean. One of "low", "medium", "high" selects an effort level for models that support it (Ollama 0.7+ on reasoning-capable models like gpt-oss and deepseek-r1). Effort strings pass straight through to the Ollama API; unsupported models silently downgrade to boolean behavior. AIContext.thinking_budget overrides this at request time: None/0think=False, >0 → uses this config value if it's a string, otherwise think=True.

keep_alive str | int | None

How long the model stays loaded in memory after the request. Maps to Ollama's keep_alive parameter. A duration string with a unit ("5m", "30s") or an integer number of seconds — -1 keeps the model loaded indefinitely, 0 unloads it immediately. A unit-less numeric string (e.g. "-1" from a text field) is coerced to an int, because Ollama parses a string as a Go duration and rejects one without a unit. None uses the server default (5 minutes).

num_ctx int | None

Context window size. Maps to options.num_ctx. None uses the model's default (typically 2048 — bump for long contexts).

top_p float | None

Nucleus sampling cutoff. Maps to options.top_p. None uses the model's default.

top_k int | None

Top-k sampling cutoff. Maps to options.top_k. None uses the model's default.

min_p float | None

Minimum-probability sampling cutoff. Maps to options.min_p. None uses the model's default.

api_key SecretStr | None

Bearer token for a protected Ollama endpoint — Ollama Cloud/Turbo, or a self-hosted server behind a reverse proxy that checks Authorization: Bearer. Sent as the Authorization header. None (default) leaves auth to the SDK, which still falls back to the OLLAMA_API_KEY environment variable when it is set. Prefer this field when the key comes from a secret manager rather than the process environment.

headers dict[str, str] | None

Extra HTTP headers attached to every request — for a reverse proxy that needs custom headers, or a non-Bearer Authorization scheme (e.g. Basic). api_key takes precedence over an Authorization entry supplied here. None (default) sends only the SDK's own headers.

Usage

from roomkit.providers.ollama import OllamaAIProvider, OllamaConfig
from roomkit.channels.ai import AIChannel

config = OllamaConfig(host="http://localhost:11434", model="llama3.2")
provider = OllamaAIProvider(config)

ai_channel = AIChannel("ai", provider=provider)

Install with: pip install roomkit[ollama]

Streaming

StreamEvent module-attribute

StreamTextDelta

Bases: BaseModel

A text delta from a streaming AI response.

StreamThinkingDelta

Bases: BaseModel

A thinking/reasoning delta from a streaming AI response.

Emitted before text deltas when the model is reasoning. A delta may carry only a signature (with empty thinking): Anthropic streams the thinking block's opaque signature separately, and it must be preserved so the block can be echoed back in history without a 400.

StreamToolCall

Bases: BaseModel

A complete tool call extracted from a streaming AI response.

StreamDone

Bases: BaseModel

Signals the end of a streaming AI response.

Response Parts

AIThinkingPart

Bases: BaseModel

AI reasoning/thinking block in conversation history.

Used to preserve thinking blocks across tool-loop turns (required by providers like Anthropic that mandate round-trip fidelity).

Attributes:

Name Type Description
thinking str

The reasoning text produced by the model.

signature str | None

Provider-specific opaque token for caching/validation (e.g. Anthropic's thinking block signature).

AIToolCallPart

Bases: BaseModel

Assistant's tool call in conversation history.

AIToolResultPart

Bases: BaseModel

Tool execution result in conversation history.

result is a plain string for text results, or a list of content parts (text and/or image) when a tool returns multimodal output — e.g. an edge tool that returns a screenshot. Providers that support image tool results (Anthropic) render the parts as content blocks; the rest flatten via as_text().

as_text

as_text()

Flatten the result to plain text for providers without image support.

A string result is returned unchanged; a list concatenates its text parts and substitutes a [image] placeholder for each image part.

split_for_message

split_for_message()

Split the result into the tool-message text and its image parts.

Unlike Anthropic — whose Messages API accepts image blocks inside a tool_result — most providers reject image content in a tool / function-response message; the image has to ride on a following user message instead. This returns the text to keep on the tool message (text parts joined, or a "[see image below]" placeholder when the result was image-only, so the tool-call/result pairing stays non-empty and valid) together with the image parts to render natively elsewhere.

A string result yields (result, []) and a text-only list yields (joined_text, []) — the no-op path that keeps every existing text tool byte-for-byte unchanged. Only a list carrying an image populates the second element and triggers a provider's synthetic-image path.

ProviderError

ProviderError(message, *, retryable=False, provider='', status_code=None)

Bases: Exception

Error from an AI provider SDK call.

Attributes:

Name Type Description
retryable

Whether the caller should retry the request.

provider

Name of the provider that raised the error.

status_code

HTTP status code from the provider, if available.