Python SDK for building AI agents with multi-LLM support, streaming, and production-ready infrastructure
Project description
Siili AI SDK
Python SDK for building AI agents with multi-LLM support, streaming, and production infrastructure.
Installation
pip install siili-ai-sdk
Quick Start
from siili_ai_sdk.agent.base_agent import BaseAgent
class MyAgent(BaseAgent):
pass
agent = MyAgent(system_prompt="You are a helpful assistant.")
print(agent.get_response_text("Hello!"))
Features
- Multi-LLM Support: OpenAI, Anthropic, Google, Azure, Ollama
- Unified API: Same interface across all providers
- Streaming: Real-time response streaming via SSE
- Tools: Function calling with LangChain integration
- Structured Output: Pydantic model responses
- Server: FastAPI with thread persistence, auth, file uploads
- Audio: Text-to-speech and speech-to-text
- Cost Tracking: Token usage and cost estimation
Agent API
Basic Response Methods
from siili_ai_sdk.agent.base_agent import BaseAgent
from siili_ai_sdk.models.model_registry import ModelRegistry
agent = MyAgent(
system_prompt="You are helpful.",
llm_model=ModelRegistry.CLAUDE_4_SONNET
)
# Sync - text only
text = agent.get_response_text("Hello")
# Sync - full message with blocks
message = agent.get_response("Hello")
print(message.get_text_content())
# Async
message = await agent.get_response_async("Hello")
Streaming
# Token stream
async for chunk in agent.get_response_stream("Write a story"):
print(chunk, end="", flush=True)
# Event stream (for SSE)
async for event in agent.get_event_stream("Write a story"):
if event.get_event_type() == "StreamingUpdated":
print(event.content, end="")
Structured Output
from pydantic import BaseModel
class Recipe(BaseModel):
name: str
ingredients: list[str]
steps: list[str]
recipe = agent.get_structured_response("Give me a pasta recipe", Recipe)
print(recipe.name)
Interactive CLI
agent.run_cli() # Starts interactive chat in terminal
Tools
from siili_ai_sdk.tools.tool_provider import ToolProvider, BaseTool, tool
class WeatherTools(ToolProvider):
def get_tools(self) -> list[BaseTool]:
@tool
def get_weather(city: str) -> str:
"""Get current weather for a city."""
return f"Sunny, 22°C in {city}"
@tool
def get_forecast(city: str, days: int = 3) -> str:
"""Get weather forecast."""
return f"{days}-day forecast for {city}: Sunny"
return [get_weather, get_forecast]
class WeatherAgent(BaseAgent):
def get_tool_providers(self) -> list[ToolProvider]:
return [WeatherTools()]
agent = WeatherAgent(system_prompt="You provide weather info.")
print(agent.get_response_text("What's the weather in Tokyo?"))
Built-in Tool Providers
from siili_ai_sdk.tools.impl.search_tool_provider import SearchToolProvider
from siili_ai_sdk.tools.impl.mcp_tool_provider import MCPToolProvider
class MyAgent(BaseAgent):
def get_tool_providers(self):
return [
SearchToolProvider(), # Web search (Tavily)
MCPToolProvider(server), # MCP server tools
]
Models
from siili_ai_sdk.models.model_registry import ModelRegistry
# Anthropic
ModelRegistry.CLAUDE_4_SONNET
ModelRegistry.CLAUDE_4_OPUS
ModelRegistry.CLAUDE_4_5_SONNET
ModelRegistry.CLAUDE_4_5_OPUS
# OpenAI
ModelRegistry.GPT_4_1
ModelRegistry.GPT_4O
ModelRegistry.O4_MINI
# Google
ModelRegistry.GEMINI_2_5_FLASH
ModelRegistry.GEMINI_2_5_PRO
# Aliases
ModelRegistry.from_name("sonnet") # CLAUDE_4_SONNET
ModelRegistry.from_name("gpt 4.1") # GPT_4_1
ModelRegistry.from_name("gemini 2.5") # GEMINI_2_5_FLASH
# Custom model
from siili_ai_sdk.models.llm_model import LLMModel
from siili_ai_sdk.models.llm_families import LLMFamilies
custom = LLMModel(
family=LLMFamilies.OPENAI,
name="gpt-4-custom",
reasoning=False
)
ModelRegistry.register_custom(custom)
FastAPI Server
from contextlib import asynccontextmanager
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from siili_ai_sdk.agent.base_agent import BaseAgent
from siili_ai_sdk.server.api.routers.api_builder import ApiBuilder
class MyAgent(BaseAgent):
pass
@asynccontextmanager
async def lifespan(app: FastAPI):
agent = MyAgent(system_prompt="You are helpful.")
api_builder = ApiBuilder.local(agent=agent)
app.include_router(api_builder.build_thread_router())
app.include_router(api_builder.build_file_router())
app.include_router(api_builder.build_audio_router())
yield
app = FastAPI(lifespan=lifespan)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_methods=["*"],
allow_headers=["*"],
)
API Endpoints
Thread management:
POST /threads- Create threadGET /threads- List threadsGET /threads/{id}- Get thread with messagesPOST /threads/{id}/messages/stream- Send message (SSE)DELETE /threads/{id}- Delete threadPOST /threads/{id}/cancel- Cancel generation
Files:
POST /files- Upload fileGET /files/{id}- Download file
Audio:
POST /audio/speech- Text to speechPOST /audio/transcribe- Speech to text
Production Setup
from siili_ai_sdk.server.storage.impl.local_file_thread_repository import LocalFileThreadRepository
from siili_ai_sdk.server.authorization.base_authorizer import BaseAuthorizer
# Custom repository and auth
api_builder = ApiBuilder.stateful(
repository=LocalFileThreadRepository(base_path="./data"),
authorizer=MyAuthorizer(),
agent=agent,
)
Orchestration
Code-first workflow orchestration without graph DSLs:
from siili_ai_sdk.orchestration import BaseOrchestrator, OrchestratorEvent
from dataclasses import dataclass
from typing import AsyncIterator
@dataclass
class State:
items: list[str]
@dataclass
class Result:
count: int
class MyOrchestrator(BaseOrchestrator[State, Result]):
async def run(self) -> AsyncIterator[OrchestratorEvent[Result]]:
state = State(items=[])
# Run step with automatic status events
async for event in self.step("fetch", "Fetching data", self.fetch, state):
yield event
if event.result:
state = event.result
# Progress updates
for i, item in enumerate(state.items):
yield self.progress("process", i + 1, len(state.items))
await self.process(item)
yield self.ok(Result(count=len(state.items)))
async def fetch(self, state: State) -> State:
return State(items=["a", "b", "c"])
async def process(self, item: str):
pass
# Run
orchestrator = MyOrchestrator()
result = orchestrator.run_sync()
Configuration
Environment variables:
# LLM Providers (at least one required)
ANTHROPIC_API_KEY=sk-ant-...
OPENAI_API_KEY=sk-...
GOOGLE_API_KEY=...
# Optional
AZURE_API_KEY=...
AZURE_ENDPOINT=https://your-resource.openai.azure.com/
DEFAULT_MODEL=claude-sonnet-4-20250514
Development
# Setup
uv sync
# Tests
make test # All
make test-unit # Unit only
make test-integration # Integration only
make test-unit-single PATTERN=name # Single test
# Quality
make lint # Check linting
make lint-fix # Fix linting
make typecheck # Type check
Message Structure
Messages contain blocks of different types:
from siili_ai_sdk.thread.models import MessageBlockType
# Block types
MessageBlockType.PLAIN # Regular text
MessageBlockType.REASONING # Chain of thought
MessageBlockType.TOOL_USE # Tool call
MessageBlockType.ERROR # Error message
License
MIT - Copyright (c) 2025 Siili Solutions Oyj
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file siili_ai_sdk-0.6.3.tar.gz.
File metadata
- Download URL: siili_ai_sdk-0.6.3.tar.gz
- Upload date:
- Size: 341.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0b7c7bd9b871f9aa3d9a67f26f7ea59d6578cddd2625682e923dd98f43bb373a
|
|
| MD5 |
f615f58904db71d4c7832479e97243d8
|
|
| BLAKE2b-256 |
3e716c7968ae5c5ce35e194484c89c3f5df3dd15b858663d1448d5b3eb0d0b6a
|
File details
Details for the file siili_ai_sdk-0.6.3-py3-none-any.whl.
File metadata
- Download URL: siili_ai_sdk-0.6.3-py3-none-any.whl
- Upload date:
- Size: 129.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9729715a0715305d07900847d815dfd29a664f924698b1608253e3de7e6f927a
|
|
| MD5 |
31f6e282e807929fc3db948aaa7dbb38
|
|
| BLAKE2b-256 |
028415b652626a15e7f3701dd1256c365abafb4726bec2c8f4dbcce2f1323338
|