Seqoria Agent
An async Python library for building assistants that call Python tools and remote MCP servers. Use it inside a web application, run model/tool loops, stream responses, and keep conversation state under your application's control.
PyPI · Alpha API · Python 3.12+ · Apache-2.0
Supported features
- Automatic model/tool loops, streaming responses, and single-step helpers for application-controlled loops.
- In-process tools with Pydantic argument validation, nested schemas, and hidden parameters supplied from trusted request context.
- MCP client connections over Streamable HTTP, SSE, and stdio.
- Parallel tool execution with shared concurrency limits, timeouts, dependency scheduling, and structured failure events.
- OpenAI, Anthropic, Ollama, and OpenAI-compatible HTTP providers.
- Explicit conversation histories and provider fallback.
Installation
pip install seqoria-agent
The package is named seqoria-agent; import it as seqoria_agent. HTTP providers use HTTPX and are included in the core installation. Vendor SDKs, model runtimes, and databases are not required for HTTP-provider usage.
Optional extras:
| Extra | Purpose |
|---|---|
performance |
Optional JSON serialization and hashing accelerators |
server |
FastAPI dependency for application integration |
all |
All runtime extras |
dev,docs |
Contributor and documentation tools |
For example: pip install 'seqoria-agent[server]'.
Quickstart
Set OPENAI_API_KEY and set OPENAI_MODEL to a model ID available to your account. The example makes hosted model calls.
import asyncio
import os
from seqoria_agent import AsyncAIClient, LocalToolbox
from seqoria_agent.models import AssistantMessage
from seqoria_agent.providers import AsyncOpenAIProvider
tools = LocalToolbox()
@tools.tool()
async def add(a: int, b: int) -> int:
"""Add two integers."""
return a + b
async def main():
history = []
async with AsyncOpenAIProvider(model_id=os.environ["OPENAI_MODEL"]) as provider:
async with AsyncAIClient(
providers=[provider],
local_toolbox=tools,
max_concurrency=16,
tool_timeout=30,
) as client:
async for event in client.chat("What is 2 + 3?", history=history):
if isinstance(event, AssistantMessage):
print(event.content)
# Reuse this history for another turn in the same conversation.
async for event in client.chat("Now add 10 to that.", history=history):
if isinstance(event, AssistantMessage):
print(event.content)
if __name__ == "__main__":
asyncio.run(main())
The client records user messages, paired tool calls/results, and final assistant messages in the supplied history. Providers belong to the application; close clients before closing the providers they use.
For an example requiring no API key or service, run python examples/manual_loop/basic_once.py from a checkout or source distribution after installing the package.
Providers
Import provider classes from seqoria_agent.providers:
| Backend | Async provider | Installation |
|---|---|---|
| OpenAI | AsyncOpenAIProvider |
Core |
| OpenAI-compatible endpoint | AsyncOpenAICompatibleProvider |
Core |
| Anthropic | AsyncAnthropicProvider |
Core |
| Ollama | AsyncOllamaProvider |
Core; requires a running Ollama service |
Use Async*Provider classes with AsyncAIClient. Blocking scripts can use AIClient as a regular context manager with either sync or async providers; chat_sync() returns the final answer. Provider classes without the Async prefix are the synchronous variants.
With multiple providers configured, the client can fall back after a provider error before streaming output begins. Errors after partial output propagate, avoiding replay of text or tool calls. Endpoint capabilities and available models depend on the backend.
Streaming and tool failures
Inside an active client lifespan, use stream_chat() to receive text deltas, grouped tool events, and a final assistant message:
from seqoria_agent.models import AssistantMessage, ChatChunk, ToolCallError, ToolMessages
async for event in client.stream_chat("What is 4 + 5?", history=history):
if isinstance(event, ChatChunk):
print(event.content, end="", flush=True)
elif isinstance(event, ToolMessages):
for message in event:
if isinstance(message, ToolCallError):
print(f"\nTool {message.name} failed: {message.error}")
elif isinstance(event, AssistantMessage):
# The final message contains the complete response and aggregate usage.
# Avoid printing its content again after rendering the text deltas.
if event.usage is not None:
print("\nTokens:", event.usage.total_tokens)
Tool failures, including missing hidden parameters, become ToolCallError events. Independent calls can finish; declared dependents are skipped after a prerequisite fails. Provider and transport startup failures can still raise exceptions.
For application-controlled loops, use llm_generate_once() or llm_stream_once(), then execute requested tools through run_tool_calls() or run_call_stream(). run_tool_calls() preserves input order; run_call_stream() yields (request, result) pairs in completion order. Single-step helpers leave response recording to the caller.
Serving multiple users
Create one AsyncAIClient per application worker and fixed tool/authentication configuration during application startup. Reuse its connections across independent conversations. Create resources within each worker's running event loop.
Give every conversation its own history list. Pass identity derived from authentication through context on each request. Hidden local tool arguments are omitted from the model's tool schema:
@tools.tool(server_populated=["tenant_id", "user_id"])
async def account_summary(tenant_id: str, user_id: str) -> dict:
"""Read the authenticated user's account."""
return await account_service.read(tenant_id=tenant_id, user_id=user_id)
# Application integration: authenticate, authorize conversation ownership,
# and acquire the conversation lock before running this turn.
async for event in client.chat(
request_text,
history=conversation_history,
context={"tenant_id": principal.tenant_id, "user_id": principal.user_id},
):
...
account_service, principal, history loading, locking, and response delivery are application integration points. The application owns authentication, authorization, persistence, context budgeting, retention, rate limits, and serialization of simultaneous turns in one conversation. Multiple workers need storage transactions or distributed coordination when updating the same conversation.
Save model messages as JSON-compatible dictionaries:
saved_history = [
message if isinstance(message, dict) else message.model_dump(mode="json")
for message in conversation_history
]
Those dictionaries can be loaded into a new history list for later turns. Reconcile incomplete history after a cancelled or failed turn before retrying; a tool's side effects may already have occurred.
Configure providers, credentials, remote servers, and tool blocklists for the client's whole lifespan. Remote MCP connections authenticated as different end users need separate clients/sessions. Remote servers resolve hidden identity from their authenticated server context; local server_args are not transmitted to remote tools.
Execution limits
The default tool concurrency limit is 16 per client. max_concurrency and tool_timeout cover parameter resolution and tool invocation. The timeout starts after acquiring a slot, so time spent waiting in the queue is excluded. Use max_turns to bound model/tool rounds and application-level limits for total request time and queue depth.
Synchronous tools and parameter callbacks run in worker threads. Cancellation cannot stop an already-running Python thread; bound underlying I/O and use async tools for cancellable work. CPU-intensive tasks belong in a process pool or job queue. Close abandoned async streams explicitly, for example with contextlib.aclosing.
Tool execution and retries
Every requested tool call executes; the library does not cache or replay tool results. If your application needs caching, implement it within the operation or data service that owns the result, with explicit authorization scope, invalidation, and side-effect rules.
Transport retries default to one attempt. Additional attempts can repeat side effects after an ambiguous failure; enable retries only where replay is safe. Dependency declarations schedule calls requested in the same batch; authorize operations inside the tools themselves.
Remote MCP tools
Connect to an existing MCP server during the client lifespan:
from seqoria_agent.client import MCPServerConfig
server = MCPServerConfig(
url="http://127.0.0.1:8000/mcp",
timeout=30,
)
# Add mcp_servers=[server] when constructing AsyncAIClient.
# Enter the client context before discovering or calling its remote tools.
Use MCPServerConfig for headers, timeouts, transport selection, stdio configuration, or OAuth. The default interactive OAuth flow is for local scripts; web applications supply their own authorization flow. Remote servers remain responsible for authentication, authorization, and identity injection.
Seqoria Agent provides MCP client orchestration and LocalToolbox for in-process tools. Build and deploy remote servers separately with the official MCP SDK or another compatible implementation. The example servers under examples/server-client/ use the official SDK directly.
Migration
From 0.8 to 0.9
- MLX providers and the
mlx-lm/mlx-vlmextras are removed. For local inference, use Ollama or an OpenAI-compatible HTTP service. - Use
contextandparam_registrywithAsyncAIClientfor hidden local parameters.LocalToolbox.register_param_provideris removed; direct toolbox calls supply trustedserver_argsexplicitly. - Tool output stays intact: JSON keys such as
ai_messageandmetadataare ordinary data. Interpret display metadata in your application. XML parsing helpers and the executor'son_metadatacallback are removed. - Use
mcp_serversin client constructors andClientSettings; theurlsalias and unusedClientSettings.client_kwargsfield are removed. Configure transports withMCPServerConfig. - Use
ToolCallError.errorfor failures andToolCallResult.resultfor successes. The error'sresultalias is removed. - Use transport/pool context managers for resource ownership. The no-op
MCPConnection.close(), global HTTP pool helpers, andConnectionPoolalias are removed; useMCPConnectionPool.
From 0.7 to 0.8
Version 0.8.0 removes SeqoriaMCP, seqoria_agent.server, and the server-only XMCPError exception. Migrate server code to an independent MCP server implementation. The client-side mcp_servers option and LocalToolbox remain supported.
Built-in tool-result caching is also removed. Drop cache and cache_ttl client/settings options, cache backend imports, and the redis extra. Implement any required caching within application-owned tools or data services.
From 0.6
Version 0.7 removed automatic memory and planning, background capture, embeddings, graph/vector/database adapters, and their extras. Replace memory objects with application-owned history lists and remove retrieval_query arguments. The library does not migrate or delete existing memory data.
The API remains alpha; hosted integrations and production throughput require validation with your application's workload.
Development and documentation
From a checkout or extracted source distribution:
python -m pip install -e '.[dev,docs]'
ruff check .
python -m pytest
python -m build
python -m twine check --strict dist/*
mkdocs build --strict
CI runs Python 3.12/3.13 on Linux, macOS, and Windows, including package build and core-import checks. Tests use mocked providers, in-memory MCP sessions, and a local MCP subprocess. Hosted models and model downloads are not required for the default suite.
The source distribution includes these guides and examples:
- Web application lifespans and conversation ownership
- Tool execution and manual loops
- MCP client connections
- Release review and integration boundaries
- Changelog and publishing guide
License
Apache-2.0. See LICENSE.txt.
Metadata
Release files for seqoria-agent 0.9.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| seqoria_agent-0.9.0.tar.gz | 143.7 kB | With provenance | Details for seqoria_agent-0.9.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| seqoria_agent-0.9.0-py3-none-any.whl | Python 3 | none | any | Details for seqoria_agent-0.9.0-py3-none-any.whl |
Total release size: 244.6 kB
Release files / seqoria_agent-0.9.0.tar.gz
| Download URL | seqoria_agent-0.9.0.tar.gz |
|---|---|
| Size | 143.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
21a5859eb29616f77e52ccbfb830f3b438cac2a849ea6969303e345edd4f6e2f
|
|
BLAKE2b-256 checksum How to use checksums |
c20abb44a31c4f34396ee14eedc5d0bf42b1529740d4adda74c084b1d33eff1d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 18, 2026.
Transparency logRelease files / seqoria_agent-0.9.0-py3-none-any.whl
| Download URL | seqoria_agent-0.9.0-py3-none-any.whl |
|---|---|
| Size | 100.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
deb456fbb246f4a202ce4284da191a8e5800c9ae36a3a151f0d2de0cf1637d3f
|
|
BLAKE2b-256 checksum How to use checksums |
949a310c01b081c605d93e508a3a8d3cf4b91886949d5a56c3d8571ddbaa84f9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 18, 2026.
Transparency logSecurity for seqoria-agent 0.9.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for seqoria_agent-0.9.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 18, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.