API Reference
Protocols
Section titled “Protocols”AIProviderProtocol
Section titled “AIProviderProtocol”Protocol for AI provider implementations.
async def chat( messages: list[ChatMessageProtocol], tools: list[dict[str, Any]] | None = None, **kwargs: Any ) -> CompletionProtocol
Chat with optional tool calling.
| Parameter | Type | Description |
|---|---|---|
| `messages` | list[ChatMessageProtocol] | List of chat messages. |
| `tools` | list[dict[str, Any]] | None | Optional list of JSON Schema tool definitions. Intentionally ``list[dict[str, Any]]`` — tool schemas are provider-specific JSON and their shape is not constrained here. **kwargs: Provider-specific options. |
| Type | Description |
|---|---|
| CompletionProtocol | Completion with optional tool calls. |
AIWorkflowNodeProtocol
Section titled “AIWorkflowNodeProtocol”AI-domain graph node protocol for workflow execution.
A workflow node represents a single unit of work in a directed graph. Nodes receive the current shared state, perform their work, and return a state update dict that is merged into the global state.
Unique node identifier within the workflow.
Execute this node with the current workflow state.
| Parameter | Type | Description |
|---|---|---|
| `state` | dict[str, Any] | Current shared workflow state. |
| Type | Description |
|---|---|
| dict[str, Any] | Dict of state updates to merge into the shared state. |
AgentExecutorProtocol
Section titled “AgentExecutorProtocol”Protocol for agent execution engines.
The executor runs an agent with governance checks, memory management, and observability integration.
async def run( agent: AgentProtocol, message: str, session_id: str | None = None, user_id: str | None = None, **kwargs: Any ) -> Any
Execute an agent and return the response.
Returns Result[AgentResponse, AgentError].
AgentProtocol
Section titled “AgentProtocol”Protocol for AI agents.
An agent declares its identity, capabilities (tools), and persona (system prompt). The AgentExecutor uses this protocol to drive the reasoning loop.
Unique agent identifier.
property tools() -> list[ToolProtocol]
Tools available to this agent.
System prompt defining the agent’s persona and constraints.
AggregateRootProtocol
Section titled “AggregateRootProtocol”Structural protocol for aggregate root objects.
Any class that implements event buffering and consistency boundaries
satisfies this protocol. Type-check against it instead of the concrete
AggregateRoot base class where possible.
Register a domain event with the aggregate.
Return and clear all buffered domain events.
Return buffered events without clearing them.
Discard all buffered domain events.
Return True when there are buffered events not yet published.
AsyncLockProtocol
Section titled “AsyncLockProtocol”Protocol for a simple in-process async mutual-exclusion lock.
Mirrors the interface of asyncio.Lock. Implementations are single-process (i.e. not distributed); use DistributedLockProtocol or LockManagerProtocol when cross-process coordination is required.
Example
from lexigram.contracts.lock import AsyncLockProtocol
async def protected(lock: AsyncLockProtocol) -> None: async with lock: await do_critical_work()Container registration
container.singleton(AsyncLockProtocol, InMemoryAsyncLock)Acquire the lock, blocking until it becomes available.
| Type | Description |
|---|---|
| bool | ``True`` once the lock has been acquired. |
Release the lock.
| Exception | Description |
|---|---|
| RuntimeError | If the lock is not currently held. |
Return True if the lock is currently held by any coroutine.
AsyncSecretStoreProtocol
Section titled “AsyncSecretStoreProtocol”Async persistent store for sensitive named secret values.
Typical usage
store = await container.resolve(AsyncSecretStoreProtocol)token = await store.get("stripe_api_key")Return the secret value for name, or None if absent.
| Parameter | Type | Description |
|---|---|---|
| `name` | str | Unique secret identifier. |
Return a mapping of name → value for all requested secrets.
| Parameter | Type | Description |
|---|---|---|
| `names` | str | One or more secret names. |
| Type | Description |
|---|---|
| dict[str, str] | Dict containing only the names that were found. |
Write or overwrite a secret value.
| Parameter | Type | Description |
|---|---|---|
| `name` | str | Unique secret identifier. |
| `value` | str | Plaintext secret value. |
Remove a secret. No-op if absent.
| Parameter | Type | Description |
|---|---|---|
| `name` | str | Unique secret identifier. |
AsyncStringSerializerProtocol
Section titled “AsyncStringSerializerProtocol”Protocol for value serialization.
Implementations handle conversion between Python objects and string representations suitable for storage or transmission. Used across extensions (cache, messaging, tasks, etc.) for consistent serialization.
Example
class JSONSerializer: async def serialize(self, value: Any) -> str: return json.dumps(value)
async def deserialize(self, data: str) -> Any: return json.loads(data)Serialize a Python object to string.
| Parameter | Type | Description |
|---|---|---|
| `value` | Any | Python object to serialize. |
| Type | Description |
|---|---|
| str | String representation. |
Deserialize string back to Python object.
| Parameter | Type | Description |
|---|---|---|
| `data` | str | Serialized string data. |
| Type | Description |
|---|---|
| Any | Reconstructed Python object. |
AuthProviderProtocol
Section titled “AuthProviderProtocol”Protocol for authentication and authorization providers.
Auth providers are responsible for user authentication, authorization, token management, and access control.
Retrieve a user by their unique identifier.
| Parameter | Type | Description |
|---|---|---|
| `user_id` | str | Unique user identifier. |
| Type | Description |
|---|---|
| Any | None | User object or None if not found. |
Verify an encoded auth token and return verification details.
| Parameter | Type | Description |
|---|---|---|
| `token` | str | Raw encoded auth token (JWT or similar). |
| Type | Description |
|---|---|
| Any | Verification result (typically ``Result[VerifiedToken, TokenError]``). |
Return True if user holds at least one of the given roles.
| Parameter | Type | Description |
|---|---|---|
| `user` | Any | Authenticated user object. |
| `roles` | list[str] | Role names to check. |
| Type | Description |
|---|---|
| bool | True if the user has at least one of the supplied roles. |
Return True if user has at least one of the given permissions.
| Parameter | Type | Description |
|---|---|---|
| `user` | Any | Authenticated user object. |
| `permissions` | list[str] | Permission names to check. |
| Type | Description |
|---|---|
| bool | True if the user has at least one of the supplied permissions. |
AuthenticatedUserProtocol
Section titled “AuthenticatedUserProtocol”Protocol for authenticated user attached to requests.
This protocol defines the contract that any authenticated user implementation must follow for type-safe user handling.
Example
def get_user_profile(user: AuthenticatedUserProtocol) -> dict: return {"user_id": user.user_id, "roles": user.roles}Unique identifier for the user.
Name of the authenticated user.
Email address of the user.
Whether the user account is active.
Whether the user’s email is verified.
List of roles assigned to the user.
List of permissions granted to the user.
Check if user has a specific role.
| Parameter | Type | Description |
|---|---|---|
| `role` | str | The role to check for. |
| Type | Description |
|---|---|
| bool | True if the user has the role. |
Check if user has a specific permission.
| Parameter | Type | Description |
|---|---|---|
| `permission` | str | The permission to check for. |
| Type | Description |
|---|---|
| bool | True if the user has the permission. |
AuthorizerProtocol
Section titled “AuthorizerProtocol”Protocol for authorization decisions.
Authorizers determine if an authenticated user can perform a specific action on a resource.
Check if user is authorized for action on resource.
| Parameter | Type | Description |
|---|---|---|
| `user` | Any | Authenticated user. |
| `action` | str | Action to perform (e.g., "read", "write", "delete"). |
| `resource` | Any | Target resource. |
| Type | Description |
|---|---|
| bool | True if authorized. |
async def check_access( user: Any, allowed_roles: set[str], resource: str | None = None, action: str | None = None ) -> bool
Check if user has access based on roles and permissions.
| Parameter | Type | Description |
|---|---|---|
| `user` | Any | Authenticated user. |
| `allowed_roles` | set[str] | Set of roles that grant access. |
| `resource` | str | None | Target resource (optional). |
| `action` | str | None | Action to perform (optional). |
| Type | Description |
|---|---|
| bool | True if access is granted. |
Check if user can perform action on resource.
| Parameter | Type | Description |
|---|---|---|
| `user` | Any | Authenticated user. |
| `action` | str | Action to perform. |
| `resource` | str | Target resource. |
| Type | Description |
|---|---|
| bool | True if authorized. |
BlobStoreProtocol
Section titled “BlobStoreProtocol”Protocol for blob storage operations.
This interface defines the contract for file storage backends (S3, GCS, Azure Blob, local filesystem, etc.).
Example
class S3BlobStore: async def upload(self, path: str, data: bytes, **options) -> FileInfo: await self._client.put_object(Bucket=self._bucket, Key=path, Body=data) return FileInfo(path=path, size=len(data), ...)async def upload( path: str, data: bytes | AsyncIterator[bytes], content_type: str | None = None, **options: Any ) -> FileInfo
Upload data to the storage backend.
| Parameter | Type | Description |
|---|---|---|
| `path` | str | Storage path/key. |
| `data` | bytes | AsyncIterator[bytes] | File content as bytes or async iterator. |
| `content_type` | str | None | MIME type of the content. **options: Additional upload options. |
| Type | Description |
|---|---|
| FileInfo | FileInfo with path, size, and metadata. |
Download file content into memory.
| Parameter | Type | Description |
|---|---|---|
| `path` | str | Storage path/key. |
| Type | Description |
|---|---|
| bytes | File content as bytes. |
Stream file content (memory efficient).
| Parameter | Type | Description |
|---|---|---|
| `path` | str | Storage path/key. |
| `chunk_size` | int | Size of each chunk in bytes. |
| Type | Description |
|---|---|
| AsyncIterator[bytes] | File content in chunks. |
Delete a file.
| Parameter | Type | Description |
|---|---|---|
| `path` | str | Storage path/key. |
Check if file exists.
| Parameter | Type | Description |
|---|---|---|
| `path` | str | Storage path/key. |
| Type | Description |
|---|---|
| bool | True if file exists. |
async def info(path: str) -> FileInfo
Get file metadata.
| Parameter | Type | Description |
|---|---|---|
| `path` | str | Storage path/key. |
| Type | Description |
|---|---|
| FileInfo | FileInfo with size, content_type, etc. |
def list(prefix: str = '') -> AsyncIterator[FileInfo]
List files with a given prefix.
| Parameter | Type | Description |
|---|---|---|
| `prefix` | str | Path prefix to filter by. |
| Type | Description |
|---|---|
| AsyncIterator[FileInfo] | FileInfo for each matching file. |
Get public URL (if applicable).
| Parameter | Type | Description |
|---|---|---|
| `path` | str | Storage path/key. |
| Type | Description |
|---|---|
| str | Public URL string. |
async def get_presigned_url( path: str, expires_in: timedelta = timedelta(hours=1), method: str = 'GET' ) -> str
Get a temporary secure URL.
| Parameter | Type | Description |
|---|---|---|
| `path` | str | Storage path/key. |
| `expires_in` | timedelta | URL validity window as a timedelta (default one hour). Pass ``timedelta(minutes=5)`` for secure short-lived downloads or ``timedelta(hours=24)`` for bulk exports. |
| `method` | str | HTTP method (GET or PUT). |
| Type | Description |
|---|---|
| str | Presigned URL string. |
Perform health check.
| Type | Description |
|---|---|
| HealthCheckResult | Structured health check result. |
CORSPolicyProtocol
Section titled “CORSPolicyProtocol”Protocol for CORS (Cross-Origin Resource Sharing) policy configuration.
Defines how to evaluate CORS requests and provide the necessary headers and configuration for browser-based clients.
Example
class CORSPolicy: def is_origin_allowed(self, origin: str) -> bool: return origin in ("https://app.example.com", "https://admin.example.com")
def get_allowed_headers(self) -> list[str]: return ["content-type", "authorization", "x-request-id"]
def get_allowed_methods(self) -> list[str]: return ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"]
def get_max_age(self) -> int: return 3600Check if an origin is permitted for CORS requests.
| Parameter | Type | Description |
|---|---|---|
| `origin` | str | The value of the Origin header from a CORS preflight request. |
| Type | Description |
|---|---|
| bool | True if the origin is allowed, False otherwise. |
Return the list of allowed request headers.
| Type | Description |
|---|---|
| list[str] | List of header names that clients are allowed to send. |
| Common values | ["content-type", "authorization", "x-request-id"]. |
Return the list of allowed HTTP methods.
| Type | Description |
|---|---|
| list[str] | List of HTTP methods clients are allowed to use. |
| Typical | ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"]. |
Return the preflight cache duration in seconds.
| Type | Description |
|---|---|
| int | Maximum time (in seconds) browsers should cache preflight responses. Typical values: 3600 (1 hour) to 86400 (24 hours). |
CacheBackendProtocol
Section titled “CacheBackendProtocol”Protocol for cache backend implementations.
This interface defines the contract that all cache backend implementations must follow. It provides a unified API for different storage mechanisms (memory, Redis, Memcached, etc.).
Example
class RedisBackend: async def get(self, key: str) -> Any | None: data = await self._redis.get(key) return self._serializer.deserialize(data) if data else None
async def set(self, key: str, value: Any, ttl: int | None = None) -> bool: data = self._serializer.serialize(value) await self._redis.set(key, data, ex=ttl) return Trueasync def get(key: str) -> Result[Any | None, CacheError]
Get a value from the cache.
| Parameter | Type | Description |
|---|---|---|
| `key` | str | The cache key to retrieve. |
| Type | Description |
|---|---|
| Result[Any | None, CacheError] | Ok(value) if found, Ok(None) if not found, Err(CacheError) on failure. |
Note
The return type is Any by design: the cache is a
heterogeneous store and the caller knows the expected type.
Use cast(T, result.unwrap()) at call sites for type safety.
async def set( key: str, value: Any, ttl: int | None = None ) -> Result[None, CacheError]
Set a value in the cache with optional TTL.
| Parameter | Type | Description |
|---|---|---|
| `key` | str | The cache key to set. |
| `value` | Any | The value to cache. |
| `ttl` | int | None | Time to live in seconds (optional). |
| Type | Description |
|---|---|
| Result[None, CacheError] | Ok(None) if successful, Err(CacheError) on failure. |
async def delete(key: str) -> Result[bool, CacheError]
Delete a value from the cache.
| Parameter | Type | Description |
|---|---|---|
| `key` | str | The cache key to delete. |
| Type | Description |
|---|---|
| Result[bool, CacheError] | Ok(True) if deleted, Ok(False) if not found, Err(CacheError) on failure. |
async def delete_many(keys: list[str]) -> Result[int, CacheError]
Delete multiple values from the cache.
| Parameter | Type | Description |
|---|---|---|
| `keys` | list[str] | List of cache keys to delete. |
| Type | Description |
|---|---|
| Result[int, CacheError] | Ok(count) of deleted keys, Err(CacheError) on failure. |
async def delete_pattern(pattern: str) -> Result[int, CacheError]
Delete all keys matching a glob-style pattern.
| Parameter | Type | Description |
|---|---|---|
| `pattern` | str | Glob pattern (e.g. ``"pet:list:*"``). Supports ``*`` as a wildcard matching any sequence of characters. |
| Type | Description |
|---|---|
| Result[int, CacheError] | Ok(count) of deleted keys, Err(CacheError) on failure. |
async def exists(key: str) -> Result[bool, CacheError]
Check if a key exists in the cache.
| Parameter | Type | Description |
|---|---|---|
| `key` | str | The cache key to check. |
| Type | Description |
|---|---|
| Result[bool, CacheError] | Ok(True) if exists, Ok(False) otherwise, Err(CacheError) on failure. |
async def clear() -> Result[None, CacheError]
Clear all values from the cache.
| Type | Description |
|---|---|
| Result[None, CacheError] | Ok(None) if successful, Err(CacheError) on failure. |
async def get_many(keys: list[str]) -> Result[dict[str, Any], CacheError]
Get multiple values from the cache.
| Parameter | Type | Description |
|---|---|---|
| `keys` | list[str] | List of cache keys to retrieve. |
| Type | Description |
|---|---|
| Result[dict[str, Any], CacheError] | Ok(dict) mapping found keys to values, Err(CacheError) on failure. |
async def set_many( items: dict[str, Any], ttl: int | None = None ) -> Result[None, CacheError]
Set multiple values in the cache.
| Parameter | Type | Description |
|---|---|---|
| `items` | dict[str, Any] | Dictionary of key-value pairs to cache. |
| `ttl` | int | None | Time to live in seconds for all items. |
| Type | Description |
|---|---|
| Result[None, CacheError] | Ok(None) if all items set successfully, Err(CacheError) on failure. |
Perform a health check on the cache backend.
| Type | Description |
|---|---|
| HealthCheckResult | Structured HealthCheckResult. |
CacheProviderProtocol
Section titled “CacheProviderProtocol”Protocol for cache providers.
Cache providers are responsible for setting up caching backends, cache warming, and cache management.
CliContributorProtocol
Section titled “CliContributorProtocol”Protocol for CLI contributors that register generators, commands, health checks, doctor checks, shell context, and hooks into the CLI.
Each contributor is discovered via the lexigram.cli.contributors
entry point group. Install the package to make contributions available.
Unique identifier for this contributor (e.g. ‘core’, ‘web’, ‘sql’).
def get_generators() -> list[GeneratorDefinition]
Return all generator definitions this contributor provides.
| Type | Description |
|---|---|
| list[GeneratorDefinition] | A list of GeneratorDefinition instances. May be empty. |
Return CLI command groups contributed by this package.
| Type | Description |
|---|---|
| list[CommandContribution] | A list of CommandContribution instances. May be empty. |
Return runtime health checks contributed by this package.
Health checks require a booted DI container.
| Type | Description |
|---|---|
| list[HealthCheckContribution] | A list of HealthCheckContribution instances. May be empty. |
Return static environment/config diagnostic checks.
Doctor checks are sync and require no container.
| Type | Description |
|---|---|
| list[DoctorCheckContribution] | A list of DoctorCheckContribution instances. May be empty. |
Return objects to inject into the interactive shell namespace.
| Type | Description |
|---|---|
| list[ShellContextContribution] | A list of ShellContextContribution instances. May be empty. |
Return CLI lifecycle hooks contributed by this package.
| Type | Description |
|---|---|
| list[HookContribution] | A list of HookContribution instances. May be empty. |
ClockProtocol
Section titled “ClockProtocol”Injectable time source for the framework.
Return the current timezone-aware UTC time.
Return a monotonic elapsed-time counter.
Return the current Unix timestamp in UTC seconds.
Backward-compatible alias for timestamp.
CommandBusProtocol
Section titled “CommandBusProtocol”Protocol for command bus implementations.
Example
class CommandBusProtocol: async def dispatch(self, command: Command) -> Any: handler = self._handlers[type(command)] return await handler.handle(command)Dispatch a command to its handler.
| Parameter | Type | Description |
|---|---|---|
| `command` | Any | Command to dispatch. |
| Type | Description |
|---|---|
| Any | Result from the command handler. |
ConfigProtocol
Section titled “ConfigProtocol”Protocol for configuration access across the framework.
Any configuration object (BaseConfig, LexigramConfig, or custom
implementations) can satisfy this protocol by implementing get(),
get_section(), and has_section().
Example
config = container.resolve(ConfigProtocol)db_url = config.get("database.url", "sqlite:///default.db")logging = config.get_section("logging", LoggingConfig)The active deployment environment.
Return True when the active environment is production.
Return True when the active environment is development.
Return True when the active environment is testing.
Return True when the active environment is staging.
Return True when debug mode is enabled.
Get a configuration value by dot-notation key.
| Parameter | Type | Description |
|---|---|---|
| `key` | str | Configuration key (e.g. ``"app.name"`` or ``"database.url"``). |
| `default` | Any | Value returned when the key is not found. |
| Type | Description |
|---|---|
| Any | The configuration value, or *default* if not found. |
Get a typed configuration section.
| Parameter | Type | Description |
|---|---|---|
| `name` | str | Section name (e.g. ``"logging"``). |
| `model_cls` | type[T] | None | Optional model class to coerce the section into. |
| Type | Description |
|---|---|
| T | dict[str, Any] | A model instance when *model_cls* is provided, otherwise a raw dict or the attribute value. |
Check whether a configuration section exists.
| Parameter | Type | Description |
|---|---|---|
| `name` | str | Section name to check. |
| Type | Description |
|---|---|
| bool | True if the section is present. |
ConnectionPoolProtocol
Section titled “ConnectionPoolProtocol”Protocol for connection pools.
Initialize the connection pool.
Shutdown the connection pool.
Get a connection from the pool.
Get pool statistics.
Check pool health.
Get query statistics.
Pre-create count connections to avoid cold-start latency.
| Parameter | Type | Description |
|---|---|---|
| `count` | int | None | Number of connections to open. Defaults to ``min_connections`` (or the pool minimum) if not specified. |
Validate all idle connections in the pool, evicting dead ones.
| Type | Description |
|---|---|
| int | Number of valid connections remaining after validation. |
ConnectionProtocol
Section titled “ConnectionProtocol”Protocol for database connections.
Represents an active database connection that can execute queries.
Execute a SQL query.
| Parameter | Type | Description |
|---|---|---|
| `sql` | str | SQL query string. |
| `params` | list[Any] | None | Query parameters for parameterized queries. |
| Type | Description |
|---|---|
| QueryResult | QueryResult with rows and metadata. |
Close the connection.
Fetch rows from the database.
| Parameter | Type | Description |
|---|---|---|
| `query` | str | SQL query string. *args: Positional query parameters. **kwargs: Named query parameters. |
| Type | Description |
|---|---|
| list[dict[str, Any]] | List of row dictionaries. |
ContainerProtocol
Section titled “ContainerProtocol”Combined DI container protocol covering registration, resolution, and validation.
Use this instead of Any when a component needs to both register
services (via singleton/transient) and resolve them (via
resolve) within the same method. This is a structural Protocol
— any object implementing both ContainerRegistrarProtocol and
ContainerResolverProtocol satisfies this type.
ContainerRegistrarProtocol
Section titled “ContainerRegistrarProtocol”Protocol for registering dependencies in the container.
Used during the registration phase where resolution is not yet permitted.
Register a transient service.
def singleton( service_type: type[T], instance: T | None = None, *, name: str | None = None, factory: Any | None = None, validate: bool = True ) -> None
def singleton( service_type: Any, instance: Any = None, *, name: str | None = None, factory: Any | None = None, validate: bool = True ) -> None
def singleton( service_type: Any, instance: Any = None, *, name: str | None = None, factory: Any | None = None, validate: bool = True ) -> None
Register a singleton service (shared instance).
| Parameter | Type | Description |
|---|---|---|
| `service_type` | Any | The abstract type (protocol/class) being registered. Accepts both concrete classes (``type[T]`` with full type inference) and Protocol types (via ``Any`` fallback). |
| `instance` | Any | Pre-built singleton instance. |
| `name` | str | None | Optional string key. When provided, the binding is stored under this name instead of ``service_type``. Resolve via ``Annotated[T, Named(name)]``. |
| `factory` | Any | None | Factory callable for lazy creation. |
| `validate` | bool | Whether to validate protocol conformance. |
def scoped( service_type: type[T], factory: Any, validate: bool = True, *, name: str | None = None ) -> None
Register a scoped service (one instance per scope).
| Parameter | Type | Description |
|---|---|---|
| `service_type` | type[T] | The abstract type being registered. |
| `factory` | Any | Factory callable, called once per scope. |
| `validate` | bool | Whether to validate protocol conformance. |
| `name` | str | None | Optional string key for named scoped registration. Resolve via ``Annotated[T, Named(name)]``. |
Check if a service is registered.
ContainerResolverProtocol
Section titled “ContainerResolverProtocol”Protocol for resolving dependencies from the container.
Async-first code should depend on this protocol. It provides only an
asynchronous resolve() method and makes no guarantees about sync
behaviour. All synchronous helpers have been removed to keep the API
simple and forward‑looking.
Used during the boot phase and runtime after registration is complete.
Asynchronously resolve a service by its type.
The framework is async-first and does not support string or other loose keys. Consumers should only register and resolve using types so that the DI container remains fully type-safe.
Accepts both concrete classes (type[T] with full return-type
inference) and Protocol types (via Any fallback).
| Parameter | Type | Description |
|---|---|---|
| `service_type` | Any | The service type to resolve. |
| `bypass_visibility` | bool | If True, skip module visibility enforcement. Use only in framework-internal resolution paths. |
Call a function with dependency injection.
Create a request-scoped resolution context.
Check if a service is registered.
Resolve a service, returning None if not registered.
This provides a graceful way to handle optional dependencies without catching exceptions.
| Parameter | Type | Description |
|---|---|---|
| `service_type` | Any | The type to resolve. |
| Type | Description |
|---|---|
| Any | None | The resolved instance or None if the service is not registered. |
Resolve all registered implementations that are subtypes of a service type.
Useful for collecting multiple implementations of a protocol or
abstract base class (e.g. all registered EventHandlerProtocol instances).
| Parameter | Type | Description |
|---|---|---|
| `service_type` | Any | The base type whose implementations to resolve. |
| Type | Description |
|---|---|
| list[Any] | A list of resolved instances. |
ContextPrunerProtocol
Section titled “ContextPrunerProtocol”Relevance-based conversation history pruning.
Unlike sliding-window truncation, implementations score each turn for relevance to the current query and preserve high-value turns regardless of their position in the history.
async def prune( history: list[ChatMessageProtocol], current_query: str, max_turns: int ) -> list[ChatMessageProtocol]
Prune history to at most max_turns, preserving relevant turns.
| Parameter | Type | Description |
|---|---|---|
| `history` | list[ChatMessageProtocol] | Full conversation history as ChatMessageProtocol instances. |
| `current_query` | str | The current user query (used for relevance scoring). |
| `max_turns` | int | Maximum number of turns to retain. |
| Type | Description |
|---|---|
| list[ChatMessageProtocol] | Pruned history in chronological order. |
CursorPageProtocol
Section titled “CursorPageProtocol”Protocol for cursor-based paginated result pages.
Implemented by CursorPage and Relay-compliant GraphQL page types.
Use this for code that should work with any cursor-pagination result.
Items in this page.
Opaque cursor for the next page, or None if no more.
Whether there are more results after this page.
DatabaseProviderProtocol
Section titled “DatabaseProviderProtocol”Protocol for database providers.
This defines the interface that all database providers must implement, regardless of the underlying database technology.
Example
class PostgresProvider: async def connect(self) -> None: self._pool = await asyncpg.create_pool(self._dsn)
async def execute_query( self, sql: str, params: list[Any] | None = None, ) -> QueryResult: async with self._pool.acquire() as conn: rows = await conn.fetch(sql, *params or []) return QueryResult(rows=list(map(dict, rows)), ...)Establish connection to the database.
Close connection to the database.
Check if database is connected.
Execute a SELECT query.
| Parameter | Type | Description |
|---|---|---|
| `sql` | str | SQL query string. |
| `params` | list[Any] | None | Query parameters. **kwargs: Additional options. |
| Type | Description |
|---|---|
| QueryResult | QueryResult with rows and execution metadata. |
Execute an INSERT operation.
| Parameter | Type | Description |
|---|---|---|
| `table` | str | Table name. |
| `data` | dict[str, Any] | Column-value mapping. **kwargs: Additional options. |
| Type | Description |
|---|---|
| InsertResult | InsertResult with inserted ID and influenced rows. |
async def execute_update( table: str, data: dict[str, Any], where_clause: str, where_params: list[Any] | None = None, **kwargs: Any ) -> UpdateResult
Execute an UPDATE operation.
| Parameter | Type | Description |
|---|---|---|
| `table` | str | Table name. |
| `data` | dict[str, Any] | Column-value updates. |
| `where_clause` | str | WHERE condition. |
| `where_params` | list[Any] | None | Parameters for WHERE clause. **kwargs: Additional options. |
| Type | Description |
|---|---|
| UpdateResult | UpdateResult with affected rows. |
async def execute_delete( table: str, where_clause: str, where_params: list[Any] | None = None, **kwargs: Any ) -> DeleteResult
Execute a DELETE operation.
| Parameter | Type | Description |
|---|---|---|
| `table` | str | Table name. |
| `where_clause` | str | WHERE condition. |
| `where_params` | list[Any] | None | Parameters for WHERE clause. **kwargs: Additional options. |
| Type | Description |
|---|---|
| DeleteResult | DeleteResult with affected rows. |
Execute a raw SQL query with parameters.
| Parameter | Type | Description |
|---|---|---|
| `sql` | str | SQL query string. |
| `params` | Any | Query parameters. |
| Type | Description |
|---|---|
| QueryResult | QueryResult with execution results. |
Context manager for transactions.
| Parameter | Type | Description |
|---|---|---|
| `isolation_level` | IsolationLevel | None | Optional ANSI SQL isolation level. When ``None`` the driver's default isolation level is used. |
Example
async with db.transaction(isolation_level=IsolationLevel.SERIALIZABLE): await db.execute("INSERT INTO ...") await db.execute("UPDATE ...")Begin a transaction.
Commit current transaction.
Rollback current transaction.
Check if a table exists.
Perform health check on database connection.
Return an async context manager that establishes a scoped session.
The scoped context binds a database session to the current
async context so that get_scoped_connection can retrieve it
without passing the connection around explicitly.
| Type | Description |
|---|---|
| AbstractAsyncContextManager[Any] | Async context manager that yields no value (or the session). |
async def get_scoped_connection() -> ConnectionProtocol
Return the connection bound to the current scoped context.
Must be called within an active scoped_context block.
| Type | Description |
|---|---|
| ConnectionProtocol | Active ConnectionProtocol for the current scope. |
async def acquire() -> ConnectionProtocol
Acquire a connection from the pool for manual management.
Use this when you need fine-grained control over connection lifecycle, but prefer scoped_context when possible for automatic cleanup.
| Type | Description |
|---|---|
| ConnectionProtocol | An acquired connection that must be released via release. |
Example
conn = await db.acquire()try: result = await conn.execute("SELECT * FROM users")finally: await db.release(conn)async def release(connection: ConnectionProtocol) -> None
Release a connection back to the pool.
| Parameter | Type | Description |
|---|---|---|
| `connection` | ConnectionProtocol | Connection acquired via acquire. |
DistributedLockProtocol
Section titled “DistributedLockProtocol”Protocol for distributed locking.
Distributed locks coordinate access to shared resources across multiple processes, threads, or services. They provide:
- Mutual exclusion: Only one holder at a time
- Safety: Locks expire after a TTL to prevent deadlocks
- Non-blocking acquire: Returns immediately if lock is held
Implementations must be safe for use in async contexts and handle network partitions gracefully.
Example
lock = RedisLock(redis, "my-resource", ttl=30)
# Non-blocking acquireif await lock.acquire(): try: await process() finally: await lock.release()
# Blocking with timeoutif await lock.acquire_blocking(timeout=5.0): try: await process() finally: await lock.release()
# Context manager (preferred)async with lock: await process()Attempt to acquire the lock non-blocking.
Returns immediately with True if the lock was acquired, False if the lock is already held by another process.
| Type | Description |
|---|---|
| bool | True if lock was acquired, False otherwise |
Attempt to acquire the lock with optional timeout.
Blocks until the lock is acquired or the timeout expires.
| Parameter | Type | Description |
|---|---|---|
| `timeout` | float | None | Maximum seconds to wait. None means wait forever. |
| Type | Description |
|---|---|
| bool | True if lock was acquired, False if timeout expired |
Release the lock.
| Type | Description |
|---|---|
| bool | True if lock was released by this call, False if lock was not held or already expired |
Check if this instance currently holds the lock.
| Type | Description |
|---|---|
| bool | True if this instance holds the lock |
Extend the lock TTL.
Useful for long-running operations that need to prevent the lock from expiring mid-operation.
| Parameter | Type | Description |
|---|---|---|
| `additional_time` | float | Seconds to add to the TTL |
| Type | Description |
|---|---|
| bool | True if TTL was extended, False if lock not held |
DocumentVectorStoreProtocol
Section titled “DocumentVectorStoreProtocol”Document-centric vector store API for RAG and AI packages.
This is the AI-layer contract for add/search/delete against embedded documents. For connection lifecycle and collection management, use VectorStoreProtocol (infrastructure layer).
All vector database drivers (Qdrant, ChromaDB, PGVector, etc.) are adapted
to this shape via lexigram-vector so callers can swap backends.
async def add(documents: list[DocumentProtocol]) -> Result[list[str], VectorError]
Add documents to the vector store.
| Parameter | Type | Description |
|---|---|---|
| `documents` | list[DocumentProtocol] | List of documents with text and metadata. |
| Type | Description |
|---|---|
| Result[list[str], VectorError] | ``Ok(list[str])`` with document IDs on success, or ``Err(VectorStoreError)`` on failure. |
async def batch_upsert( documents: list[DocumentProtocol], batch_size: int = 100 ) -> Result[int, VectorError]
Upsert documents in batches.
| Parameter | Type | Description |
|---|---|---|
| `documents` | list[DocumentProtocol] | List of documents to upsert. |
| `batch_size` | int | Number of documents per batch. defaults to 100. |
| Type | Description |
|---|---|
| Result[int, VectorError] | ``Ok(int)`` with the total count of documents upserted, or ``Err(VectorStoreError)`` on failure. |
async def search( query: list[float], *, top_k: int = 10, filters: dict[str, Any] | None = None, score_threshold: float | None = None ) -> Result[list[SearchResultProtocol], VectorError]
Search for similar documents using a vector.
| Parameter | Type | Description |
|---|---|---|
| `query` | list[float] | Query embedding vector. |
| `top_k` | int | Number of results to return. |
| `filters` | dict[str, Any] | None | Metadata filters. |
| `score_threshold` | float | None | Minimum relevance score. |
| Type | Description |
|---|---|
| Result[list[SearchResultProtocol], VectorError] | ``Ok(list of search results)`` on success, or ``Err(VectorStoreError)`` on failure. |
async def search_text( query: str, *, top_k: int = 10, filters: dict[str, Any] | None = None ) -> Result[list[SearchResultProtocol], VectorError]
Search for similar documents using text.
| Parameter | Type | Description |
|---|---|---|
| `query` | str | Query text. |
| `top_k` | int | Number of results to return. |
| `filters` | dict[str, Any] | None | Metadata filters. |
| Type | Description |
|---|---|
| Result[list[SearchResultProtocol], VectorError] | ``Ok(list of search results)`` on success, or ``Err(VectorStoreError)`` on failure. |
async def delete(ids: list[str]) -> Result[int, VectorError]
Delete documents by ID.
| Parameter | Type | Description |
|---|---|---|
| `ids` | list[str] | List of document IDs to delete. |
| Type | Description |
|---|---|
| Result[int, VectorError] | ``Ok(int)`` with the count of deleted documents on success, or ``Err(VectorStoreError)`` on failure. |
Perform a lightweight connectivity check.
| Type | Description |
|---|---|
| HealthCheckResult | Structured health check result. |
DomainEventPublisherProtocol
Section titled “DomainEventPublisherProtocol”Protocol for publishing domain events.
Publish a domain event.
| Parameter | Type | Description |
|---|---|---|
| `event` | Any | DomainEvent instance. |
EmbeddingClientProtocol
Section titled “EmbeddingClientProtocol”Protocol for embedding client implementations.
Generate embeddings for texts.
| Parameter | Type | Description |
|---|---|---|
| `texts` | list[str] | List of strings to embed. |
| Type | Description |
|---|---|
| list[list[float]] | List of embedding vectors. |
Perform a lightweight connectivity check.
| Type | Description |
|---|---|
| HealthCheckResult | Structured health check result. |
Close the client and release resources.
EpisodicMemoryProtocol
Section titled “EpisodicMemoryProtocol”Protocol for episodic memory (conversation history with temporal grounding).
Episodic memory stores timestamped events and conversations, supporting hybrid retrieval based on recency and relevance.
Record a new episode/conversation turn.
| Parameter | Type | Description |
|---|---|---|
| `entry` | MemoryEntry | The episode to record |
Recall episodes based on relevance and recency.
| Parameter | Type | Description |
|---|---|---|
| `query` | MemoryQuery | Query parameters with weighting preferences |
| Type | Description |
|---|---|
| list[MemorySearchResult] | Ranked list of matching episodes |
Forget/delete a specific episode.
| Parameter | Type | Description |
|---|---|---|
| `entry_id` | str | ID of the episode to forget |
Check if the episodic memory backend is reachable and healthy.
| Parameter | Type | Description |
|---|---|---|
| `timeout` | float | Maximum seconds to wait for a response. |
| Type | Description |
|---|---|
| HealthCheckResult | Health check result with status and details. |
EventBusProtocol
Section titled “EventBusProtocol”Protocol for event bus implementations.
The event bus manages event publication and subscription.
Example
```pythonclass InMemoryEventBus: async def publish(self, event: DomainEvent) -> "Result[None, EventError]": for handler in self._handlers.get(type(event), []): await handler.handle(event) return Ok(None)
def subscribe(self, event_type, handler): self._handlers.setdefault(event_type, []).append(handler)<div style='padding-left: 1rem; border-left: 1px solid var(--sl-color-gray-5); margin-top: 2rem; margin-bottom: 2rem;'><div style='background: var(--color-background-weak); padding: 0.6rem 1rem; border-radius: 4px; border-left: 2px solid var(--color-border-weak); margin-bottom: 1rem; display: flex; justify-content: space-between; align-items: flex-start;'><pre style='margin: 0; font-family: var(--sl-font-mono); font-size: 0.875em; line-height: 1.6; white-space: pre-wrap; word-break: break-all; flex: 1;'><span style='color: var(--lex-color-keyword)'>async </span><span style='color: var(--lex-color-keyword)'>def </span><span style='color: var(--lex-color-fname); font-weight: 600'>publish</span><span style='color: var(--lex-color-colon)'>(</span><span style='color: var(--lex-color-name)'>event</span><span style='color: var(--lex-color-colon)'>: </span><span style='color: var(--lex-color-type)'>Any</span><span style='color: var(--lex-color-colon)'>)</span><span style='color: var(--lex-color-keyword)'> -> </span><span style='color: var(--lex-color-return)'>Result<span style='color: var(--lex-color-colon)'>[</span><span style='color: var(--lex-color-default) !important'>None</span><span style='color: var(--lex-color-colon)'>,</span> <a href='/packages/events/lexigram-events/api/#eventerror' style='color:inherit; text-decoration:underline; text-decoration-color:rgba(128,128,128,0.3); text-underline-offset:2px;'>EventError</a><span style='color: var(--lex-color-colon)'>]</span></span></pre><a href='https://github.com/dbtinoy-/lexigram/blob/main/lexigram/lexigram-contracts/src/lexigram/contracts/events/protocols.py#L97' target='_blank' title='View Source' style='color: var(--sl-color-gray-3); opacity: 0.6; flex-shrink: 0; margin-left: 0.75rem; display: inline-flex; align-items: center; text-decoration: none;' onmouseover="this.style.opacity='1'" onmouseout="this.style.opacity='0.6'"><svg xmlns='http://www.w3.org/2000/svg' width='15' height='15' viewBox='0 0 24 24' fill='currentColor'><path d='M12 0C5.374 0 0 5.373 0 12c0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23A11.509 11.509 0 0 1 12 5.803c1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 C20.566 21.797 24 17.3 24 12c0-6.627-5.373-12-12-12z'/></svg></a></div>
Publish an event to all subscribers.
<div style='margin:0;line-height:1.4;'><span style='display:block;font-size:0.7em;font-weight:700;letter-spacing:0.07em;text-transform:uppercase;color:var(--color-brand);margin-top:1rem;margin-bottom:0.4rem;'>Parameters</span><table style='border-collapse:collapse;width:100%;font-size:0.85em;margin:0;margin-bottom:1rem;table-layout:fixed;'><thead><tr><th style='text-align:left;padding:0.4rem 0.5rem;color:var(--color-text-strong);font-weight:600;font-size:0.82em;border-bottom:1px solid var(--color-border-weak);width:20%;'>Parameter</th><th style='text-align:left;padding:0.4rem 0.5rem;color:var(--color-text-strong);font-weight:600;font-size:0.82em;border-bottom:1px solid var(--color-border-weak);width:25%;'>Type</th><th style='text-align:left;padding:0.4rem 0.5rem;color:var(--color-text-strong);font-weight:600;font-size:0.82em;border-bottom:1px solid var(--color-border-weak);padding-left:1.2rem;border-left:1px solid var(--color-border-weak);width:55%;'>Description</th></tr></thead><tbody><tr><td style='padding:0.6rem 0.5rem;vertical-align:top;white-space:nowrap;font-family:var(--sl-font-mono);font-size:0.85em;color:var(--lex-color-name);border-bottom:1px solid var(--color-border-weak);'>`event`</td><td style='padding:0.6rem 0.5rem;vertical-align:top;color:var(--lex-color-type) !important;font-family:var(--sl-font-mono);font-size:0.82em;border-bottom:1px solid var(--color-border-weak);'>Any</td><td style='padding:0.6rem 0.5rem 0.6rem 1.2rem;vertical-align:top;font-size:0.9em;font-family:var(--sl-font-mono);color:var(--color-text-weak);border-left:1px solid var(--color-border-weak);border-bottom:1px solid var(--color-border-weak);'>DomainEvent to publish.</td></tr></tbody></table></div>
<div style='margin:0;line-height:1.4;'><span style='display:block;font-size:0.7em;font-weight:700;letter-spacing:0.07em;text-transform:uppercase;color:var(--color-brand);margin-top:1rem;margin-bottom:0.4rem;'>Returns</span><table style='border-collapse:collapse;width:100%;font-size:0.85em;margin:0;margin-bottom:1rem;table-layout:fixed;'><thead><tr><th style='text-align:left;padding:0.4rem 0.5rem;color:var(--color-text-strong);font-weight:600;font-size:0.82em;border-bottom:1px solid var(--color-border-weak);width:45%;'>Type</th><th style='text-align:left;padding:0.4rem 0.5rem;color:var(--color-text-strong);font-weight:600;font-size:0.82em;border-bottom:1px solid var(--color-border-weak);padding-left:1.2rem;border-left:1px solid var(--color-border-weak);width:55%;'>Description</th></tr></thead><tbody><tr><td style='padding:0.6rem 0.5rem;vertical-align:top;color:var(--lex-color-type) !important;font-family:var(--sl-font-mono);font-size:0.82em;border-bottom:1px solid var(--color-border-weak);'>Result<span style='color: var(--lex-color-colon)'>[</span><span style='color: var(--lex-color-default) !important'>None</span><span style='color: var(--lex-color-colon)'>,</span> <a href='/packages/events/lexigram-events/api/#eventerror' style='color:inherit; text-decoration:underline; text-decoration-color:rgba(128,128,128,0.3); text-underline-offset:2px;'>EventError</a><span style='color: var(--lex-color-colon)'>]</span></td><td style='padding:0.6rem 0.5rem 0.6rem 1.2rem;vertical-align:top;font-size:0.9em;font-family:var(--sl-font-mono);color:var(--color-text-weak);border-left:1px solid var(--color-border-weak);border-bottom:1px solid var(--color-border-weak);'>Ok(None) when the event is successfully enqueued for dispatch. Err(EventError) when the event cannot be accepted (e.g.\ no handlers registered and the bus requires at least one).</td></tr></tbody></table></div>
<div style='background: var(--color-background-weak); padding: 0.6rem 1rem; border-radius: 4px; border-left: 2px solid var(--color-border-weak); margin-bottom: 1rem; display: flex; justify-content: space-between; align-items: flex-start;'><pre style='margin: 0; font-family: var(--sl-font-mono); font-size: 0.875em; line-height: 1.6; white-space: pre-wrap; word-break: break-all; flex: 1;'><span style='color: var(--lex-color-keyword)'>def </span><span style='color: var(--lex-color-fname); font-weight: 600'>subscribe</span><span style='color: var(--lex-color-colon)'>(</span> <span style='color: var(--lex-color-name)'>event_type</span><span style='color: var(--lex-color-colon)'>: </span><span style='color: var(--lex-color-type)'>type</span><span style='color: var(--lex-color-colon)'>,</span> <span style='color: var(--lex-color-name)'>handler</span><span style='color: var(--lex-color-colon)'>: </span><span style='color: var(--lex-color-type)'>EventHandlerProtocol</span><span style='color: var(--lex-color-colon)'>)</span><span style='color: var(--lex-color-keyword)'> -> </span><span style='color: var(--lex-color-default) !important'>None</span></pre><a href='https://github.com/dbtinoy-/lexigram/blob/main/lexigram/lexigram-contracts/src/lexigram/contracts/events/protocols.py#L110' target='_blank' title='View Source' style='color: var(--sl-color-gray-3); opacity: 0.6; flex-shrink: 0; margin-left: 0.75rem; display: inline-flex; align-items: center; text-decoration: none;' onmouseover="this.style.opacity='1'" onmouseout="this.style.opacity='0.6'"><svg xmlns='http://www.w3.org/2000/svg' width='15' height='15' viewBox='0 0 24 24' fill='currentColor'><path d='M12 0C5.374 0 0 5.373 0 12c0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23A11.509 11.509 0 0 1 12 5.803c1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 C20.566 21.797 24 17.3 24 12c0-6.627-5.373-12-12-12z'/></svg></a></div>
Subscribe a handler to an event type.
<div style='margin:0;line-height:1.4;'><span style='display:block;font-size:0.7em;font-weight:700;letter-spacing:0.07em;text-transform:uppercase;color:var(--color-brand);margin-top:1rem;margin-bottom:0.4rem;'>Parameters</span><table style='border-collapse:collapse;width:100%;font-size:0.85em;margin:0;margin-bottom:1rem;table-layout:fixed;'><thead><tr><th style='text-align:left;padding:0.4rem 0.5rem;color:var(--color-text-strong);font-weight:600;font-size:0.82em;border-bottom:1px solid var(--color-border-weak);width:20%;'>Parameter</th><th style='text-align:left;padding:0.4rem 0.5rem;color:var(--color-text-strong);font-weight:600;font-size:0.82em;border-bottom:1px solid var(--color-border-weak);width:25%;'>Type</th><th style='text-align:left;padding:0.4rem 0.5rem;color:var(--color-text-strong);font-weight:600;font-size:0.82em;border-bottom:1px solid var(--color-border-weak);padding-left:1.2rem;border-left:1px solid var(--color-border-weak);width:55%;'>Description</th></tr></thead><tbody><tr><td style='padding:0.6rem 0.5rem;vertical-align:top;white-space:nowrap;font-family:var(--sl-font-mono);font-size:0.85em;color:var(--lex-color-name);border-bottom:1px solid var(--color-border-weak);'>`event_type`</td><td style='padding:0.6rem 0.5rem;vertical-align:top;color:var(--lex-color-type) !important;font-family:var(--sl-font-mono);font-size:0.82em;border-bottom:1px solid var(--color-border-weak);'>type</td><td style='padding:0.6rem 0.5rem 0.6rem 1.2rem;vertical-align:top;font-size:0.9em;font-family:var(--sl-font-mono);color:var(--color-text-weak);border-left:1px solid var(--color-border-weak);border-bottom:1px solid var(--color-border-weak);'>Type of event to subscribe to.</td></tr><tr><td style='padding:0.6rem 0.5rem;vertical-align:top;white-space:nowrap;font-family:var(--sl-font-mono);font-size:0.85em;color:var(--lex-color-name);border-bottom:1px solid var(--color-border-weak);'>`handler`</td><td style='padding:0.6rem 0.5rem;vertical-align:top;color:var(--lex-color-type) !important;font-family:var(--sl-font-mono);font-size:0.82em;border-bottom:1px solid var(--color-border-weak);'>EventHandlerProtocol</td><td style='padding:0.6rem 0.5rem 0.6rem 1.2rem;vertical-align:top;font-size:0.9em;font-family:var(--sl-font-mono);color:var(--color-text-weak);border-left:1px solid var(--color-border-weak);border-bottom:1px solid var(--color-border-weak);'>Handler to call when event is published.</td></tr></tbody></table></div>
<div style='background: var(--color-background-weak); padding: 0.6rem 1rem; border-radius: 4px; border-left: 2px solid var(--color-border-weak); margin-bottom: 1rem; display: flex; justify-content: space-between; align-items: flex-start;'><pre style='margin: 0; font-family: var(--sl-font-mono); font-size: 0.875em; line-height: 1.6; white-space: pre-wrap; word-break: break-all; flex: 1;'><span style='color: var(--lex-color-keyword)'>def </span><span style='color: var(--lex-color-fname); font-weight: 600'>unsubscribe</span><span style='color: var(--lex-color-colon)'>(</span> <span style='color: var(--lex-color-name)'>event_type</span><span style='color: var(--lex-color-colon)'>: </span><span style='color: var(--lex-color-type)'>type</span><span style='color: var(--lex-color-colon)'>,</span> <span style='color: var(--lex-color-name)'>handler</span><span style='color: var(--lex-color-colon)'>: </span><span style='color: var(--lex-color-type)'>EventHandlerProtocol</span><span style='color: var(--lex-color-colon)'>)</span><span style='color: var(--lex-color-keyword)'> -> </span><span style='color: var(--lex-color-default) !important'>None</span></pre><a href='https://github.com/dbtinoy-/lexigram/blob/main/lexigram/lexigram-contracts/src/lexigram/contracts/events/protocols.py#L119' target='_blank' title='View Source' style='color: var(--sl-color-gray-3); opacity: 0.6; flex-shrink: 0; margin-left: 0.75rem; display: inline-flex; align-items: center; text-decoration: none;' onmouseover="this.style.opacity='1'" onmouseout="this.style.opacity='0.6'"><svg xmlns='http://www.w3.org/2000/svg' width='15' height='15' viewBox='0 0 24 24' fill='currentColor'><path d='M12 0C5.374 0 0 5.373 0 12c0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23A11.509 11.509 0 0 1 12 5.803c1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 C20.566 21.797 24 17.3 24 12c0-6.627-5.373-12-12-12z'/></svg></a></div>
Remove a handler subscription for an event type.
<div style='margin:0;line-height:1.4;'><span style='display:block;font-size:0.7em;font-weight:700;letter-spacing:0.07em;text-transform:uppercase;color:var(--color-brand);margin-top:1rem;margin-bottom:0.4rem;'>Parameters</span><table style='border-collapse:collapse;width:100%;font-size:0.85em;margin:0;margin-bottom:1rem;table-layout:fixed;'><thead><tr><th style='text-align:left;padding:0.4rem 0.5rem;color:var(--color-text-strong);font-weight:600;font-size:0.82em;border-bottom:1px solid var(--color-border-weak);width:20%;'>Parameter</th><th style='text-align:left;padding:0.4rem 0.5rem;color:var(--color-text-strong);font-weight:600;font-size:0.82em;border-bottom:1px solid var(--color-border-weak);width:25%;'>Type</th><th style='text-align:left;padding:0.4rem 0.5rem;color:var(--color-text-strong);font-weight:600;font-size:0.82em;border-bottom:1px solid var(--color-border-weak);padding-left:1.2rem;border-left:1px solid var(--color-border-weak);width:55%;'>Description</th></tr></thead><tbody><tr><td style='padding:0.6rem 0.5rem;vertical-align:top;white-space:nowrap;font-family:var(--sl-font-mono);font-size:0.85em;color:var(--lex-color-name);border-bottom:1px solid var(--color-border-weak);'>`event_type`</td><td style='padding:0.6rem 0.5rem;vertical-align:top;color:var(--lex-color-type) !important;font-family:var(--sl-font-mono);font-size:0.82em;border-bottom:1px solid var(--color-border-weak);'>type</td><td style='padding:0.6rem 0.5rem 0.6rem 1.2rem;vertical-align:top;font-size:0.9em;font-family:var(--sl-font-mono);color:var(--color-text-weak);border-left:1px solid var(--color-border-weak);border-bottom:1px solid var(--color-border-weak);'>Type of event to unsubscribe from.</td></tr><tr><td style='padding:0.6rem 0.5rem;vertical-align:top;white-space:nowrap;font-family:var(--sl-font-mono);font-size:0.85em;color:var(--lex-color-name);border-bottom:1px solid var(--color-border-weak);'>`handler`</td><td style='padding:0.6rem 0.5rem;vertical-align:top;color:var(--lex-color-type) !important;font-family:var(--sl-font-mono);font-size:0.82em;border-bottom:1px solid var(--color-border-weak);'>EventHandlerProtocol</td><td style='padding:0.6rem 0.5rem 0.6rem 1.2rem;vertical-align:top;font-size:0.9em;font-family:var(--sl-font-mono);color:var(--color-text-weak);border-left:1px solid var(--color-border-weak);border-bottom:1px solid var(--color-border-weak);'>Handler to remove.</td></tr></tbody></table></div>
</div>
<hr style='border:none;border-top:2px solid rgba(99,102,241,0.45);margin:1.75rem 0 0 0;' />
<div data-pagefind-weight='10'>
### `EventHandlerProtocol`
</div>
<span data-api-type='Protocols' style='display:none;'></span>
<div style='display: flex; justify-content: flex-end; margin-top: -1rem; margin-bottom: 1rem;'><a href='https://github.com/dbtinoy-/lexigram/blob/main/lexigram/lexigram-contracts/src/lexigram/contracts/events/protocols.py#L37' target='_blank' title='View Source' style='color: var(--sl-color-gray-3); opacity: 0.6; flex-shrink: 0; margin-left: 0.75rem; display: inline-flex; align-items: center; text-decoration: none;' onmouseover="this.style.opacity='1'" onmouseout="this.style.opacity='0.6'"><svg xmlns='http://www.w3.org/2000/svg' width='15' height='15' viewBox='0 0 24 24' fill='currentColor'><path d='M12 0C5.374 0 0 5.373 0 12c0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23A11.509 11.509 0 0 1 12 5.803c1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 C20.566 21.797 24 17.3 24 12c0-6.627-5.373-12-12-12z'/></svg></a></div>Protocol for event handlers.
<div style='padding-left: 1rem; border-left: 1px solid var(--sl-color-gray-5); margin-top: 2rem; margin-bottom: 2rem;'><div style='background: var(--color-background-weak); padding: 0.6rem 1rem; border-radius: 4px; border-left: 2px solid var(--color-border-weak); margin-bottom: 1rem; display: flex; justify-content: space-between; align-items: flex-start;'><pre style='margin: 0; font-family: var(--sl-font-mono); font-size: 0.875em; line-height: 1.6; white-space: pre-wrap; word-break: break-all; flex: 1;'><span style='color: var(--lex-color-keyword)'>async </span><span style='color: var(--lex-color-keyword)'>def </span><span style='color: var(--lex-color-fname); font-weight: 600'>handle</span><span style='color: var(--lex-color-colon)'>(</span><span style='color: var(--lex-color-name)'>event</span><span style='color: var(--lex-color-colon)'>: </span><span style='color: var(--lex-color-type)'>Any</span><span style='color: var(--lex-color-colon)'>)</span><span style='color: var(--lex-color-keyword)'> -> </span><span style='color: var(--lex-color-return)'>Result<span style='color: var(--lex-color-colon)'>[</span><span style='color: var(--lex-color-default) !important'>None</span><span style='color: var(--lex-color-colon)'>,</span> <a href='/packages/events/lexigram-events/api/#eventerror' style='color:inherit; text-decoration:underline; text-decoration-color:rgba(128,128,128,0.3); text-underline-offset:2px;'>EventError</a><span style='color: var(--lex-color-colon)'>]</span></span></pre><a href='https://github.com/dbtinoy-/lexigram/blob/main/lexigram/lexigram-contracts/src/lexigram/contracts/events/protocols.py#L40' target='_blank' title='View Source' style='color: var(--sl-color-gray-3); opacity: 0.6; flex-shrink: 0; margin-left: 0.75rem; display: inline-flex; align-items: center; text-decoration: none;' onmouseover="this.style.opacity='1'" onmouseout="this.style.opacity='0.6'"><svg xmlns='http://www.w3.org/2000/svg' width='15' height='15' viewBox='0 0 24 24' fill='currentColor'><path d='M12 0C5.374 0 0 5.373 0 12c0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23A11.509 11.509 0 0 1 12 5.803c1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 C20.566 21.797 24 17.3 24 12c0-6.627-5.373-12-12-12z'/></svg></a></div>
Handle an event.
<div style='margin:0;line-height:1.4;'><span style='display:block;font-size:0.7em;font-weight:700;letter-spacing:0.07em;text-transform:uppercase;color:var(--color-brand);margin-top:1rem;margin-bottom:0.4rem;'>Parameters</span><table style='border-collapse:collapse;width:100%;font-size:0.85em;margin:0;margin-bottom:1rem;table-layout:fixed;'><thead><tr><th style='text-align:left;padding:0.4rem 0.5rem;color:var(--color-text-strong);font-weight:600;font-size:0.82em;border-bottom:1px solid var(--color-border-weak);width:20%;'>Parameter</th><th style='text-align:left;padding:0.4rem 0.5rem;color:var(--color-text-strong);font-weight:600;font-size:0.82em;border-bottom:1px solid var(--color-border-weak);width:25%;'>Type</th><th style='text-align:left;padding:0.4rem 0.5rem;color:var(--color-text-strong);font-weight:600;font-size:0.82em;border-bottom:1px solid var(--color-border-weak);padding-left:1.2rem;border-left:1px solid var(--color-border-weak);width:55%;'>Description</th></tr></thead><tbody><tr><td style='padding:0.6rem 0.5rem;vertical-align:top;white-space:nowrap;font-family:var(--sl-font-mono);font-size:0.85em;color:var(--lex-color-name);border-bottom:1px solid var(--color-border-weak);'>`event`</td><td style='padding:0.6rem 0.5rem;vertical-align:top;color:var(--lex-color-type) !important;font-family:var(--sl-font-mono);font-size:0.82em;border-bottom:1px solid var(--color-border-weak);'>Any</td><td style='padding:0.6rem 0.5rem 0.6rem 1.2rem;vertical-align:top;font-size:0.9em;font-family:var(--sl-font-mono);color:var(--color-text-weak);border-left:1px solid var(--color-border-weak);border-bottom:1px solid var(--color-border-weak);'>DomainEvent to handle.</td></tr></tbody></table></div>
<div style='margin:0;line-height:1.4;'><span style='display:block;font-size:0.7em;font-weight:700;letter-spacing:0.07em;text-transform:uppercase;color:var(--color-brand);margin-top:1rem;margin-bottom:0.4rem;'>Returns</span><table style='border-collapse:collapse;width:100%;font-size:0.85em;margin:0;margin-bottom:1rem;table-layout:fixed;'><thead><tr><th style='text-align:left;padding:0.4rem 0.5rem;color:var(--color-text-strong);font-weight:600;font-size:0.82em;border-bottom:1px solid var(--color-border-weak);width:45%;'>Type</th><th style='text-align:left;padding:0.4rem 0.5rem;color:var(--color-text-strong);font-weight:600;font-size:0.82em;border-bottom:1px solid var(--color-border-weak);padding-left:1.2rem;border-left:1px solid var(--color-border-weak);width:55%;'>Description</th></tr></thead><tbody><tr><td style='padding:0.6rem 0.5rem;vertical-align:top;color:var(--lex-color-type) !important;font-family:var(--sl-font-mono);font-size:0.82em;border-bottom:1px solid var(--color-border-weak);'>Result<span style='color: var(--lex-color-colon)'>[</span><span style='color: var(--lex-color-default) !important'>None</span><span style='color: var(--lex-color-colon)'>,</span> <a href='/packages/events/lexigram-events/api/#eventerror' style='color:inherit; text-decoration:underline; text-decoration-color:rgba(128,128,128,0.3); text-underline-offset:2px;'>EventError</a><span style='color: var(--lex-color-colon)'>]</span></td><td style='padding:0.6rem 0.5rem 0.6rem 1.2rem;vertical-align:top;font-size:0.9em;font-family:var(--sl-font-mono);color:var(--color-text-weak);border-left:1px solid var(--color-border-weak);border-bottom:1px solid var(--color-border-weak);'>``Ok(None)`` on success, ``Err(EventError)`` if handling fails in an expected, recoverable way.</td></tr></tbody></table></div>
</div>
<hr style='border:none;border-top:2px solid rgba(99,102,241,0.45);margin:1.75rem 0 0 0;' />
<div data-pagefind-weight='10'>
### `EventStoreProtocol`
</div>
<span data-api-type='Protocols' style='display:none;'></span>
<div style='display: flex; justify-content: flex-end; margin-top: -1rem; margin-bottom: 1rem;'><a href='https://github.com/dbtinoy-/lexigram/blob/main/lexigram/lexigram-contracts/src/lexigram/contracts/events/protocols.py#L253' target='_blank' title='View Source' style='color: var(--sl-color-gray-3); opacity: 0.6; flex-shrink: 0; margin-left: 0.75rem; display: inline-flex; align-items: center; text-decoration: none;' onmouseover="this.style.opacity='1'" onmouseout="this.style.opacity='0.6'"><svg xmlns='http://www.w3.org/2000/svg' width='15' height='15' viewBox='0 0 24 24' fill='currentColor'><path d='M12 0C5.374 0 0 5.373 0 12c0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23A11.509 11.509 0 0 1 12 5.803c1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 C20.566 21.797 24 17.3 24 12c0-6.627-5.373-12-12-12z'/></svg></a></div>Protocol for event store implementations.
The event store persists and retrieves domain events.
**Example**
```pythonclass PostgresEventStore: async def append(self, stream_id, events, expected_version=None): async with self.db.transaction(): for event in events: await self.db.insert("events", event.to_dict())Append events to a stream.
| Parameter | Type | Description |
|---|---|---|
| `stream_id` | str | Unique stream identifier. |
| `events` | list[Any] | List of events to append. |
| `expected_version` | int | None | Expected stream version for optimistic concurrency. |
| Type | Description |
|---|---|
| int | New stream version. |
| Exception | Description |
|---|---|
| ConcurrencyError | If expected version doesn't match. |
Read events from a stream.
| Parameter | Type | Description |
|---|---|---|
| `stream_id` | str | Unique stream identifier. |
| `start` | int | Starting position. |
| `count` | int | None | Maximum events to read. |
| Type | Description |
|---|---|
| list[Any] | List of events. |
Read events from all streams.
| Parameter | Type | Description |
|---|---|---|
| `position` | int | Starting global position. |
| `count` | int | None | Maximum events to read. |
| Type | Description |
|---|---|
| list[Any] | List of events. |
GracefulShutdownProtocol
Section titled “GracefulShutdownProtocol”Standard protocol for services that support graceful shutdown.
Any service that holds background tasks, open connections, or in-flight
work SHOULD implement this protocol. The framework will call
shutdown() on all registered services during teardown.
Behavioral Contract:
- shutdown() MUST be idempotent — calling it twice is safe.
- shutdown() SHOULD complete within a reasonable timeout.
- shutdown() MUST NOT raise exceptions.
- shutdown() SHOULD release all held resources (tasks, connections,
file handles) before returning.
HasherProtocol
Section titled “HasherProtocol”General-purpose hashing protocol (non-password-specific).
Hash algorithm name (for example sha256 or blake2b).
Hash input data and return an encoded digest.
| Parameter | Type | Description |
|---|---|---|
| `data` | str | bytes | Input string or bytes to hash. |
| Type | Description |
|---|---|
| str | Encoded hash string. |
Constant-time verification against an expected digest.
| Parameter | Type | Description |
|---|---|---|
| `data` | str | bytes | Input string or bytes to hash. |
| `expected` | str | Expected encoded digest. |
| Type | Description |
|---|---|
| bool | True when the digest matches, False otherwise. |
Backward-compatible async alias for digest.
Backward-compatible async alias for verify_digest.
HealthCheckAggregatorProtocol
Section titled “HealthCheckAggregatorProtocol”Protocol for services that aggregate health checks from multiple providers.
Implementations collect HealthCheckProtocol instances, run them concurrently, and return a single AggregateHealthResult.
def register( name: str, check: HealthCheckProtocol, *, category: HealthCheckCategory = HealthCheckCategory.READINESS ) -> None
Register a named health check.
| Parameter | Type | Description |
|---|---|---|
| `name` | str | Unique component name for this check. |
| `check` | HealthCheckProtocol | Object implementing HealthCheckProtocol. |
| `category` | HealthCheckCategory | Probe category for this check. Defaults to HealthCheckCategory.READINESS. |
async def run_all( timeout: float = 5.0, *, category: HealthCheckCategory | None = None ) -> AggregateHealthResult
Run all registered checks concurrently and aggregate results.
| Parameter | Type | Description |
|---|---|---|
| `timeout` | float | Per-check timeout in seconds. |
| `category` | HealthCheckCategory | None | Optional probe category filter. |
| Type | Description |
|---|---|
| AggregateHealthResult | AggregateHealthResult containing all component results. |
async def run_liveness(timeout: float = 5.0) -> AggregateHealthResult
Run only liveness checks and aggregate results.
async def run_readiness(timeout: float = 5.0) -> AggregateHealthResult
Run only readiness checks and aggregate results.
async def run_startup(timeout: float = 5.0) -> AggregateHealthResult
Run only startup checks and aggregate results.
HealthCheckProtocol
Section titled “HealthCheckProtocol”Protocol for health check capability.
Expected Behavior:
- health_check: MUST return a result within a reasonable timeout (~5s).
- health_check: SHOULD NOT raise exceptions; wrap errors in HealthCheckResult.
HealthCheckRegistryProtocol
Section titled “HealthCheckRegistryProtocol”Protocol for a categorised health check registry.
Implementations (e.g. HealthChecker) store checks tagged with a
HealthCheckCategory so that
callers can query subsets independently:
run_liveness— is the process alive and not deadlocked?run_readiness— is the process ready to accept traffic?run_startup— has initial startup completed?
This maps directly to the three Kubernetes probe types.
def add( name: str, check: Callable[[], Any], *, timeout: float | None = None, critical: bool = True, category: HealthCheckCategory = HealthCheckCategory.READINESS ) -> None
Register a categorised health check.
| Parameter | Type | Description |
|---|---|---|
| `name` | str | Unique identifier for the check. |
| `check` | Callable[[], Any] | Callable that performs the check. |
| `timeout` | float | None | Optional per-check timeout in seconds. |
| `critical` | bool | Whether a non-healthy result should make the aggregate readiness status ``UNHEALTHY``. Defaults to ``True``. |
| `category` | HealthCheckCategory | HealthCheckCategory value. Defaults to ``READINESS``. |
Run all registered checks regardless of category.
| Type | Description |
|---|---|
| tuple[Any, dict[str, Any]] | ``(aggregate_status, per_check_results)`` tuple. |
Run only LIVENESS checks.
| Type | Description |
|---|---|
| tuple[Any, dict[str, Any]] | ``(aggregate_status, per_check_results)`` tuple. |
Run only READINESS checks.
| Type | Description |
|---|---|
| tuple[Any, dict[str, Any]] | ``(aggregate_status, per_check_results)`` tuple. |
Run only STARTUP checks.
| Type | Description |
|---|---|
| tuple[Any, dict[str, Any]] | ``(aggregate_status, per_check_results)`` tuple. |
HttpRequestLoggerProtocol
Section titled “HttpRequestLoggerProtocol”Protocol for HTTP request/response logging middleware.
Defines how to log completed HTTP requests with duration, status code, and optional metadata for monitoring and audit purposes.
Example
class RequestLogger: async def log_request( self, method: str, path: str, status_code: int, duration_ms: float, request_id: str | None = None, **metadata: Any, ) -> None: logger.info( "request_completed", method=method, path=path, status=status_code, duration_ms=duration_ms, request_id=request_id, **metadata, )async def log_request( method: str, path: str, status_code: int, duration_ms: float, request_id: str | None = None, **metadata: Any ) -> None
Log a completed HTTP request.
| Parameter | Type | Description |
|---|---|---|
| `method` | str | HTTP method (GET, POST, etc.). |
| `path` | str | Request path URI. |
| `status_code` | int | HTTP response status code. |
| `duration_ms` | float | Request processing duration in milliseconds. |
| `request_id` | str | None | Optional request identifier for tracing. **metadata: Additional context-specific data (client_id, user_id, etc.). |
IdGeneratorProtocol
Section titled “IdGeneratorProtocol”Injectable identity generator.
property strategy() -> IdStrategy
Return the active ID generation strategy.
Generate a new unique identifier.
Generate a new identifier for a specific entity type.
IdempotencyMiddlewareProtocol
Section titled “IdempotencyMiddlewareProtocol”Protocol for HTTP idempotency deduplication middleware.
Run the handler with idempotency deduplication.
Default TTL (seconds) for cached idempotency results.
IdempotencyStoreProtocol
Section titled “IdempotencyStoreProtocol”Protocol for storing and checking idempotency keys.
async def get(key: str) -> Result[Any | None, IdempotencyError]
Retrieve a stored result by idempotency key.
| Parameter | Type | Description |
|---|---|---|
| `key` | str | The idempotency key. |
| Type | Description |
|---|---|
| Result[Any | None, IdempotencyError] | ``Ok(value)`` when a cached result exists. ``Ok(None)`` when the key is not present or expired. ``Err(IdempotencyError)`` on store failures. |
async def get_record(key: str) -> Result[IdempotencyRecord | None, IdempotencyError]
Retrieve the full idempotency record, including metadata.
async def set( key: str, value: Any, ttl: float | None = None ) -> Result[None, IdempotencyError]
Store a result with an optional time-to-live.
| Parameter | Type | Description |
|---|---|---|
| `key` | str | The idempotency key. |
| `value` | Any | The result to store. |
| `ttl` | float | None | Time-to-live in seconds, or ``None`` for no expiry. |
async def delete(key: str) -> Result[None, IdempotencyError]
Remove an idempotency record by key.
async def acquire( key: str, ttl: int ) -> Result[bool, IdempotencyError]
Atomically claim an idempotency key if it is not already held.
| Parameter | Type | Description |
|---|---|---|
| `key` | str | The idempotency key to acquire. |
| `ttl` | int | Time-to-live in seconds for the claimed key. |
| Type | Description |
|---|---|
| Result[bool, IdempotencyError] | ``Ok(True)`` if this caller should proceed. ``Ok(False)`` if the key is already claimed. ``Err(IdempotencyError)`` on store failures. |
JobProtocol
Section titled “JobProtocol”Protocol for JobProtocol objects.
KeyDerivationProtocol
Section titled “KeyDerivationProtocol”Protocol for key derivation services.
Derive an encoded key from a secret.
| Parameter | Type | Description |
|---|---|---|
| `secret` | str | Input secret to derive from. |
| `salt` | bytes | None | Optional salt. When omitted, implementations generate one. |
| Type | Description |
|---|---|
| str | Stable encoded key derivation string. |
Verify a secret against a derived key payload.
| Parameter | Type | Description |
|---|---|---|
| `secret` | str | Input secret to verify. |
| `encoded` | str | Stable encoded key derivation string. |
| Type | Description |
|---|---|
| bool | True when the secret matches the encoded payload, False otherwise. |
Backward-compatible async alias for derive.
LLMClientProtocol
Section titled “LLMClientProtocol”Protocol for LLM client implementations.
All LLM providers (OpenAI, Anthropic, Google, etc.) should implement this interface.
async def complete( messages: list[ChatMessageProtocol], *, model: str | None = None, temperature: float | None = None, max_tokens: int | None = None, tools: list[ToolDefinition] | None = None, stop_sequences: list[str] | None = None, **kwargs: Any ) -> Result[CompletionProtocol, LLMError]
Generate a completion from messages.
| Parameter | Type | Description |
|---|---|---|
| `messages` | list[ChatMessageProtocol] | List of chat messages. |
| `model` | str | None | Optional model override. |
| `temperature` | float | None | Optional sampling temperature. |
| `max_tokens` | int | None | Optional max output tokens. |
| `tools` | list[ToolDefinition] | None | Optional tool definitions. |
| `stop_sequences` | list[str] | None | Optional list of stop sequences for early termination. **kwargs: Provider-specific options. |
| Type | Description |
|---|---|
| Result[CompletionProtocol, LLMError] | ``Ok(Completion)`` on success, ``Err(LLMError)`` on recoverable failure. |
def stream_chat( messages: list[ChatMessageProtocol], *, model: str | None = None, temperature: float | None = None, max_tokens: int | None = None, tools: list[ToolDefinition] | None = None, stop_sequences: list[str] | None = None, **kwargs: Any ) -> AsyncStream[StreamChunk, LLMError]
Start a streaming completion.
This method returns an AsyncStream immediately (not wrapped in
Result). The stream is established lazily when iteration begins.
Setup failures and mid-stream failures are both surfaced through the
stream’s typed error channel.
| Parameter | Type | Description |
|---|---|---|
| `messages` | list[ChatMessageProtocol] | List of chat messages. |
| `model` | str | None | Optional model override. |
| `temperature` | float | None | Optional sampling temperature. |
| `max_tokens` | int | None | Optional max output tokens. |
| `tools` | list[ToolDefinition] | None | Optional tool definitions. |
| `stop_sequences` | list[str] | None | Optional list of stop sequences for early termination. **kwargs: Provider-specific options. |
| Type | Description |
|---|---|
| AsyncStream[StreamChunk, LLMError] | ``AsyncStream[StreamChunk, LLMError]`` that yields chunks or surfaces typed errors through terminal operations (``collect()``, ``first()``, ``drain()``). |
Perform a lightweight connectivity check.
| Type | Description |
|---|---|
| HealthCheckResult | Structured health check result. |
Close the client and release resources.
LockManagerProtocol
Section titled “LockManagerProtocol”Protocol for a process-local or distributed lock manager.
A lock manager creates and tracks named locks for coordinating mutual exclusion of concurrent operations. Callers use acquire to obtain a per-key async context manager.
Implementations range from purely in-memory (single-process deduplication) to Redis-backed or advisory-lock-backed distributed variants.
Example
from lexigram.contracts.lock import LockManagerProtocol
async def process(manager: LockManagerProtocol) -> None: async with manager.acquire("resource:42", timeout=30): await do_work()Container registration
container.singleton(LockManagerProtocol, InMemoryLockManager)Return an async context manager that holds the named lock.
The caller must use the returned value as an async context manager.
The lock is acquired on __aenter__ and released on __aexit__.
| Parameter | Type | Description |
|---|---|---|
| `key` | str | Unique, stable identifier for the resource to protect. |
| `timeout` | float | Informational TTL in seconds; implementations may use this to automatically expire stale locks. |
| Type | Description |
|---|---|
| AbstractAsyncContextManager[Any] | An ``AbstractAsyncContextManager`` for the named lock. |
LockStoreProtocol
Section titled “LockStoreProtocol”Persistent distributed lock store.
Individual lock handles are not returned; all operations are done via the lock name and owner identifier.
Attempt to acquire the named lock.
| Parameter | Type | Description |
|---|---|---|
| `lock_name` | str | Globally unique lock identifier. |
| `owner` | str | Identifier of the requesting owner (e.g. host + PID). |
| `ttl` | int | Lock time-to-live in seconds. The lock is automatically released after this duration to prevent deadlocks. |
| Type | Description |
|---|---|
| bool | ``True`` if the lock was acquired; ``False`` if it is already held. |
Release the named lock only if it is held by owner.
| Parameter | Type | Description |
|---|---|---|
| `lock_name` | str | Globally unique lock identifier. |
| `owner` | str | Must match the owner that acquired the lock. |
| Type | Description |
|---|---|
| bool | ``True`` if the lock was released; ``False`` if it was not held by *owner* or did not exist. |
Extend the TTL of a currently-held lock.
| Parameter | Type | Description |
|---|---|---|
| `lock_name` | str | Globally unique lock identifier. |
| `owner` | str | Must match the owner that currently holds the lock. |
| `ttl` | int | New time-to-live in seconds from now. |
| Type | Description |
|---|---|
| bool | ``True`` if the extension was applied; ``False`` if the lock was not held by *owner*. |
MCPServerProtocol
Section titled “MCPServerProtocol”Protocol for the MCP server.
The server routes JSON-RPC messages to handlers and returns JSON-RPC responses.
Handle a JSON-RPC message and return the response.
Returns None for notifications (no response expected).
MCPToolProviderProtocol
Section titled “MCPToolProviderProtocol”Protocol for providing tools to the MCP server.
Satisfied by:
ToolRegistryAdapter(bridges lexigram-agents ToolRegistry)- Any custom tool provider
List all available tools in MCP format.
Returns list of dicts with name, description,
inputSchema keys.
Execute a tool by name with given arguments.
MCPTransportProtocol
Section titled “MCPTransportProtocol”Protocol for MCP transport implementations.
A transport handles the I/O layer — reading requests and writing responses. The MCP server is transport-agnostic.
MemoryConsolidatorProtocol
Section titled “MemoryConsolidatorProtocol”Protocol for consolidating and optimizing memory.
Consolidation compresses old entries, deduplicates, extracts entities, and manages memory size to prevent unbounded growth.
Consolidate a batch of memory entries.
Applies compression, deduplication, entity extraction, and pruning strategies to optimize memory storage and retrieval.
| Parameter | Type | Description |
|---|---|---|
| `entries` | list[MemoryEntry] | Entries to consolidate |
| Type | Description |
|---|---|
| ConsolidationResult | Consolidation result with statistics |
Check if the memory consolidator backend is reachable and healthy.
| Parameter | Type | Description |
|---|---|---|
| `timeout` | float | Maximum seconds to wait for a response. |
| Type | Description |
|---|---|
| HealthCheckResult | Health check result with status and details. |
MemoryProtocol
Section titled “MemoryProtocol”Protocol for conversation memory.
Add a message to memory.
| Parameter | Type | Description |
|---|---|---|
| `message` | Any | Message to add. |
Get all messages from memory.
| Type | Description |
|---|---|
| list[Any] | List of messages. |
Clear all messages from memory.
MemoryStoreProtocol
Section titled “MemoryStoreProtocol”Protocol for storing and retrieving memory entries.
Implementations should provide persistent or semi-persistent storage for memory entries, supporting both sequential and search-based access.
Store a single memory entry.
| Parameter | Type | Description |
|---|---|---|
| `entry` | MemoryEntry | The memory entry to store |
Search for memory entries based on a query.
| Parameter | Type | Description |
|---|---|---|
| `query` | MemoryQuery | Query parameters |
| Type | Description |
|---|---|
| list[MemorySearchResult] | List of matching entries with scores, ordered by relevance |
Get the N most recent entries.
| Parameter | Type | Description |
|---|---|---|
| `n` | int | Number of entries to return |
| Type | Description |
|---|---|
| list[MemoryEntry] | List of recent entries in descending temporal order |
Delete an entry by ID.
| Parameter | Type | Description |
|---|---|---|
| `entry_id` | str | ID of the entry to delete |
Clear all entries from the store.
Perform a lightweight connectivity check.
MigrationManagerProtocol
Section titled “MigrationManagerProtocol”Protocol for migration management.
Initialize the migration tracking table.
async def get_applied_migrations() -> list[MigrationRecord]
Get list of applied migrations.
Apply a migration.
Rollback a migration.
Get migrations that haven’t been applied yet.
MigrationRunnerProtocol
Section titled “MigrationRunnerProtocol”Executes database migrations in the correct order.
Implementations must be idempotent: running run_migrations() on an
already up-to-date schema must be a no-op. Each migration is identified
by a unique string version identifier (e.g. "20240101_001" or the
Alembic revision hash).
Typical usage
runner = await container.resolve(MigrationRunnerProtocol)result = await runner.run_migrations()if result: logger.info("migrations_applied", count=len(result))else: logger.info("schema_up_to_date")Apply all pending migrations.
| Type | Description |
|---|---|
| list[str] | List of migration version identifiers that were applied. Empty list means the schema was already up-to-date. |
Roll back migrations to target.
| Parameter | Type | Description |
|---|---|---|
| `target` | str | None | Version identifier to roll back to. ``None`` rolls back the most recent migration only. |
| Type | Description |
|---|---|
| list[str] | List of migration version identifiers that were rolled back. |
Return the version identifier of the most recently applied migration.
| Type | Description |
|---|---|
| str | None | Version string, or ``None`` if no migrations have been applied. |
Return version identifiers of migrations not yet applied.
| Type | Description |
|---|---|
| list[str] | Ordered list of pending migration version identifiers. |
ObjectMapperProtocol
Section titled “ObjectMapperProtocol”Protocol for a registry-based object-to-object mapper.
Provides a clean map() API for converting between registered type pairs without ad-hoc conversion logic scattered through the codebase.
def map( source: Any, dest_type: type[Any], *, validate: bool = False, validator: Any | None = None ) -> Any
Map a source object to the destination type.
Uses a registered mapping function to transform the source instance into an instance of dest_type.
| Parameter | Type | Description |
|---|---|---|
| `source` | Any | The source object to transform. |
| `dest_type` | type[Any] | The target type to produce. |
| `validate` | bool | Whether to validate the result after mapping. |
| `validator` | Any | None | Optional validator instance to use. |
| Type | Description |
|---|---|
| Any | A new instance of dest_type. |
| Exception | Description |
|---|---|
| MappingNotFoundError | If no mapping is registered for this type pair. |
Register a mapping function from source_type to dest_type.
| Parameter | Type | Description |
|---|---|---|
| `source_type` | type[Any] | The type to map from. |
| `dest_type` | type[Any] | The type to map to. |
| `mapper_func` | Any | A callable that accepts a source instance and returns a dest instance. |
OffsetPageProtocol
Section titled “OffsetPageProtocol”Protocol for offset-based page request parameters.
Implemented by offset/limit style pagination inputs. Use this for code that should work with any offset-pagination type.
Zero-based record offset.
Maximum number of records to return.
OnApplicationBootstrapProtocol
Section titled “OnApplicationBootstrapProtocol”Provider implements this to run after application bootstrap.
Called after ALL providers have been booted successfully. At this point every service is fully resolved and available.
Behavioral Contract:
- Implementers MUST NOT throw exceptions — doing so indicates
a fatal application startup failure.
- Implementers CAN resolve any service from the container.
- Implementers SHOULD start background tasks, schedulers, or
listeners here rather than in on_module_init().
OnApplicationShutdownProtocol
Section titled “OnApplicationShutdownProtocol”Provider implements this to run after shutdown completes.
Called after ALL providers have been shut down. Use this for final cleanup like closing log files or flushing metrics.
Behavioral Contract: - Implementers MUST NOT resolve services — the container is already disposed at this point. - Implementers MUST NOT throw exceptions. - Implementers SHOULD release any remaining OS resources.
Run after all providers are shut down.
OnBeforeShutdownProtocol
Section titled “OnBeforeShutdownProtocol”Provider implements this to run before shutdown begins.
Called before any provider’s shutdown() method is invoked.
Use this to drain queues, finish in-flight requests, or save state.
Behavioral Contract: - Implementers MUST complete within a reasonable timeout. - Implementers SHOULD NOT start new work — only finish existing work. - Implementers MUST NOT throw exceptions.
OnModuleInitProtocol
Section titled “OnModuleInitProtocol”Provider implements this to run initialization logic.
Called once when the provider is first booted, BEFORE other providers that depend on it.
Behavioral Contract:
- Implementers MUST be idempotent — calling on_module_init()
twice MUST NOT produce side effects or raise.
- Implementers SHOULD complete quickly — blocking here delays
the entire boot sequence.
- Implementers MUST NOT resolve services from other providers
that have not yet been booted.
Initialize provider after registration but before other providers boot.
PasswordHasherProtocol
Section titled “PasswordHasherProtocol”Protocol for password hashing services.
Responsible for hashing passwords and verifying them against hashes.
Hash a plain text password.
| Parameter | Type | Description |
|---|---|---|
| `password` | str | Plain text password. |
| Type | Description |
|---|---|
| str | Hashed password string. |
Verify a password against a hash.
| Parameter | Type | Description |
|---|---|---|
| `password` | str | Plain text password to check. |
| `hashed_password` | str | Stored hash to compare against. |
| Type | Description |
|---|---|
| bool | True if password matches hash, False otherwise. |
Protocol for an individual connection pool.
def get_stats() -> PoolStats
PoolManager
Section titled “PoolManager”Manager that tracks pools by name.
PoolStats
Section titled “PoolStats”Snapshot of pool statistics.
PromptAssemblerProtocol
Section titled “PromptAssemblerProtocol”Assembles prompt layers in cache-friendly static-to-dynamic order.
The static-first ordering maximizes provider-side KV cache reuse. The assembler also injects provider-specific cache annotations (Anthropic’s cache_control breakpoints, DeepSeek’s 64-token padding, etc.).
def assemble( system: str, tools: list[ToolDefinition] | None, reference_docs: list[str] | None, few_shot: list[ChatMessage] | None, history: list[ChatMessage], query: str, provider: str, dynamic_metadata: str | None = None ) -> list[ChatMessage]
Assemble a complete prompt message list.
| Parameter | Type | Description |
|---|---|---|
| `system` | str | System instructions (static, cached). |
| `tools` | list[ToolDefinition] | None | Tool/function definitions. |
| `reference_docs` | list[str] | None | Reference documents as text (semi-static). |
| `few_shot` | list[ChatMessage] | None | Few-shot example messages (static, cached). |
| `history` | list[ChatMessage] | Chat history messages (dynamic). |
| `query` | str | Current user query (dynamic). |
| `provider` | str | Provider name for cache annotation strategy. |
| `dynamic_metadata` | str | None | Timestamps, user IDs, etc. (dynamic). |
| Type | Description |
|---|---|
| list[ChatMessage] | Ordered list of ChatMessage instances ready for the LLM client. |
PromptCompressorProtocol
Section titled “PromptCompressorProtocol”Compresses text to fit within a token budget.
Implementations range from learned compression (LLMLingua-2) to heuristic truncation. The protocol guarantees that the returned text fits within target_token_count.
Placement note: Lives in ai/rag.py because its primary consumer is the RAG context compression stage. Also consumed by lexigram-ai-memory.
async def compress( text: str, target_token_count: int, force_tokens: list[str] | None = None ) -> str
Compress text to fit within target_token_count.
| Parameter | Type | Description |
|---|---|---|
| `text` | str | The raw text to compress. |
| `target_token_count` | int | Maximum tokens in the result. |
| `force_tokens` | list[str] | None | Tokens that must never be removed. |
| Type | Description |
|---|---|
| str | Compressed text fitting within the budget. |
ProviderProtocol
Section titled “ProviderProtocol”Contract for framework providers.
Providers are responsible for:
- Registering bindings into the container (register phase)
- Initializing external resources (boot phase)
- Cleaning up resources on shutdown (shutdown phase)
Expected Behavior:
- register: MUST be declarative. No external side effects or resolution.
- boot: CAN resolve services. MUST be idempotent if called twice.
- shutdown: MUST gracefully close resources. SHOULD NOT raise.
Unique provider identifier (e.g. ‘auth’, ‘database’).
Initialization order hint.
Names of providers that must be booted before this one.
async def register(container: ContainerRegistrarProtocol) -> None
Bind services into the container. declarative phase.
Initialize and wire services. Resolution and registration allowed here.
Tear down resources on application exit.
Called when boot() or shutdown() raises an exception.
Override to perform cleanup on startup/shutdown failure.
| Parameter | Type | Description |
|---|---|---|
| `error` | Exception | The exception that was raised. |
| `phase` | str | Either 'boot' or 'shutdown'. |
QueryBusProtocol
Section titled “QueryBusProtocol”Protocol for query bus implementations.
Example
class QueryBusProtocol: async def execute(self, query: Query) -> Any: handler = self._handlers[type(query)] return await handler.handle(query)Execute a query through its handler.
| Parameter | Type | Description |
|---|---|---|
| `query` | Any | Query to execute. |
| Type | Description |
|---|---|
| Any | Query result. |
QueryLoggerProtocol
Section titled “QueryLoggerProtocol”Protocol for logging database queries.
Implement this protocol to enable query logging in database providers. The concrete lexigram.sql.logging.BaseQueryLogger implements this interface and adds helper methods for querying the stored entries.
Log a query execution.
Return the most recent limit entries.
Return entries whose execution time exceeds threshold_seconds.
Return aggregated statistics over a time window.
ReadOnlyRepositoryProtocol
Section titled “ReadOnlyRepositoryProtocol”Protocol for read-only repository operations.
Use this for query-only access patterns (CQRS query side).
Example
class UserQueryRepository: async def get(self, id: str) -> User | None: return await self.db.query("users").where(id=id).first()
async def list(self, skip: int = 0, limit: int = 100) -> list[User]: return await self.db.query("users").offset(skip).limit(limit).all()Get entity by ID.
| Parameter | Type | Description |
|---|---|---|
| `item_id` | str | Entity identifier. |
| Type | Description |
|---|---|
| T | None | Entity if found, None otherwise. |
List entities with pagination.
| Parameter | Type | Description |
|---|---|---|
| `skip` | int | Number of records to skip. |
| `limit` | int | Maximum records to return. **filters: Optional filter criteria. |
| Type | Description |
|---|---|
| list[T] | List of entities. |
async def find_by_spec(spec: SpecificationProtocol[T]) -> list[T]
Find entities matching a complex specification.
| Parameter | Type | Description |
|---|---|---|
| `spec` | SpecificationProtocol[T] | The DDD specification to evaluate. |
| Type | Description |
|---|---|
| list[T] | List of matching entities. |
Count entities matching filters.
| Parameter | Type | Description |
|---|
| Type | Description |
|---|---|
| int | Total count of matching entities. |
RepositoryProtocol
Section titled “RepositoryProtocol”Protocol for full repository operations.
Extends ReadOnlyRepositoryProtocol with write operations.
Example
class UserRepository: async def save(self, entity: User) -> User: if entity.id: await self.db.update("users", entity.dict()).where(id=entity.id) else: entity.id = await self.db.insert("users", entity.dict()) return entity
async def delete(self, id: str) -> bool: result = await self.db.delete("users").where(id=id) return result.affected_rows > 0Save (create or update) an entity.
| Parameter | Type | Description |
|---|---|---|
| `entity` | T | Entity to save. |
| Type | Description |
|---|---|
| T | Saved entity with any generated fields populated. |
Delete entity by ID.
| Parameter | Type | Description |
|---|---|---|
| `item_id` | str | Entity identifier. |
| Type | Description |
|---|---|
| bool | True if deleted, False if not found. |
Save (create or update) multiple entities in a single operation.
Implementations SHOULD execute this as a batch for efficiency.
| Parameter | Type | Description |
|---|---|---|
| `entities` | list[T] | Entities to save. |
| Type | Description |
|---|---|
| list[T] | Saved entities with any generated fields populated. |
Delete multiple entities by ID.
Implementations SHOULD execute this as a batch for efficiency.
| Parameter | Type | Description |
|---|---|---|
| `item_ids` | list[str] | Entity identifiers to delete. |
| Type | Description |
|---|---|
| int | Number of entities actually deleted. |
SagaManagerProtocol
Section titled “SagaManagerProtocol”Protocol for saga lifecycle management.
The manager routes incoming events to all registered sagas and coordinates their execution.
Process an event through all relevant sagas.
| Parameter | Type | Description |
|---|---|---|
| `event` | Any | Domain event to route and process. |
SagaProtocol
Section titled “SagaProtocol”Protocol for saga / process-manager implementations.
Sagas coordinate long-running business processes that span multiple aggregates by reacting to domain events and dispatching commands.
Handle a domain event and produce commands.
| Parameter | Type | Description |
|---|---|---|
| `event` | Any | Domain event to handle. |
| Type | Description |
|---|---|
| list[Any] | List of commands to dispatch to the command bus. |
SearchEngineProtocol
Section titled “SearchEngineProtocol”Protocol for search engine backends.
async def search( query: str, filters: dict[str, Any] | None = None, sort: list[dict[str, str]] | None = None, limit: int | None = None, offset: int | None = None ) -> QueryResult
Execute a search query.
| Parameter | Type | Description |
|---|---|---|
| `query` | str | Search query string |
| `filters` | dict[str, Any] | None | Search filters |
| `sort` | list[dict[str, str]] | None | Sort specifications |
| `limit` | int | None | Maximum results to return |
| `offset` | int | None | Results offset for pagination |
| Type | Description |
|---|---|
| QueryResult | Search results |
async def index_document( document_id: str, document: dict[str, Any], index_name: str | None = None ) -> None
Index a document.
| Parameter | Type | Description |
|---|---|---|
| `document_id` | str | Unique document identifier |
| `document` | dict[str, Any] | Document data to index |
| `index_name` | str | None | Index name (optional) |
async def index_many( documents: list[tuple[str, dict[str, Any]]], index_name: str | None = None ) -> None
Index multiple documents in a single bulk operation.
Callers should prefer this over N repeated index_document calls when processing batches. Backends may use a native bulk API to avoid per-document round-trip overhead.
| Parameter | Type | Description |
|---|---|---|
| `documents` | list[tuple[str, dict[str, Any]]] | Sequence of ``(document_id, document)`` pairs. |
| `index_name` | str | None | Index name (optional, backend implementation chooses a default when ``None``). |
Delete a document from index.
| Parameter | Type | Description |
|---|---|---|
| `document_id` | str | Document identifier to delete |
| `index_name` | str | None | Index name (optional) |
Perform health check.
| Type | Description |
|---|---|
| HealthCheckResult | Structured health check result. |
SecretStoreProtocol
Section titled “SecretStoreProtocol”Protocol for retrieving, writing, and deleting named secrets.
Secret names may use any naming convention; a hierarchical path
(e.g. "database/password") is recommended for readability and
to align with most provider APIs.
All mutating operations (set_secret, delete_secret) are
synchronous at the protocol level — implementations may perform
async I/O internally but the public contract accepts simple calls from
both sync and async contexts.
Example
store = EnvSecretStore()val = store.get_secret("MY_API_KEY")Async-first usage via a wrapping coroutine
val = await asyncio.to_thread(store.get_secret, "MY_API_KEY")Return the value of a secret by name.
| Parameter | Type | Description |
|---|---|---|
| `name` | str | Unique secret identifier (e.g. ``"stripe/api-key"``). |
| Type | Description |
|---|---|
| str | The plaintext secret value. |
| Exception | Description |
|---|---|
| SecretNotFoundError | If no secret with that name exists. |
| SecretAccessError | If the caller lacks permission. |
Write or overwrite a secret.
| Parameter | Type | Description |
|---|---|---|
| `name` | str | Unique secret identifier. |
| `value` | str | Plaintext secret value to store. |
| Exception | Description |
|---|---|
| SecretAccessError | If the caller lacks permission to write. |
Delete a secret by name.
Non-existent secrets are silently ignored (idempotent delete).
| Parameter | Type | Description |
|---|---|---|
| `name` | str | Unique secret identifier. |
| Exception | Description |
|---|---|
| SecretAccessError | If the caller lacks permission to delete. |
Return True if a secret with name exists, False otherwise.
| Parameter | Type | Description |
|---|---|---|
| `name` | str | Unique secret identifier. |
SemanticCacheProtocol
Section titled “SemanticCacheProtocol”Embedding-based semantic similarity cache for LLM responses.
Provides three-tier lookup: exact hash match (Tier 1), vector similarity match (Tier 2), and cache miss (caller invokes LLM).
Placement note: Lives in ai/llm.py (not infra/cache/) because it carries AI-domain semantics (model tracking in store(), LLM response caching).
Look up a query in the cache.
Checks Tier 1 (exact hash) then Tier 2 (vector similarity).
| Parameter | Type | Description |
|---|---|---|
| `query` | str | The user query string. |
| Type | Description |
|---|---|
| str | None | Cached response string, or ``None`` on cache miss. |
Store a query-response pair in both tiers.
| Parameter | Type | Description |
|---|---|---|
| `query` | str | The user query string. |
| `response` | str | The LLM response to cache. |
| `model` | str | The model that produced the response. |
Invalidate a cached entry by query.
| Parameter | Type | Description |
|---|---|---|
| `query` | str | The user query string to invalidate. |
| Type | Description |
|---|---|
| bool | ``True`` if the entry was found and removed, ``False`` otherwise. |
SemanticMemoryProtocol
Section titled “SemanticMemoryProtocol”Protocol for semantic memory (extracted facts and entities).
Semantic memory stores generalized knowledge in the form of facts, entities, and their relationships for long-term retention.
Store a fact as a subject-predicate-object triple.
| Parameter | Type | Description |
|---|---|---|
| `subject` | str | The subject entity |
| `predicate` | str | The relationship type |
| `object_` | str | The object entity |
| `confidence` | float | Confidence score (0-1) for this fact |
Query facts by subject.
| Parameter | Type | Description |
|---|---|---|
| `subject` | str | The subject entity to query |
| Type | Description |
|---|---|
| list[dict[str, Any]] | List of facts with this subject |
Get all facts mentioning an entity (subject or object).
| Parameter | Type | Description |
|---|---|---|
| `entity` | str | The entity name |
| Type | Description |
|---|---|
| list[dict[str, Any]] | List of facts involving this entity |
Update the confidence score of a fact.
| Parameter | Type | Description |
|---|---|---|
| `fact_id` | str | ID of the fact to update |
| `confidence` | float | New confidence score (0-1) |
Check if the semantic memory backend is reachable and healthy.
| Parameter | Type | Description |
|---|---|---|
| `timeout` | float | Maximum seconds to wait for a response. |
| Type | Description |
|---|---|
| HealthCheckResult | Health check result with status and details. |
SerializerProtocol
Section titled “SerializerProtocol”General-purpose serializer/deserializer with typed round-trip support.
Serialize obj to raw bytes.
Deserialize data into an instance of type_.
StateStoreProtocol
Section titled “StateStoreProtocol”Persistent key-value store for arbitrary application state.
Supports bulk read/write operations on top of the basic get/set/delete primitives. Implementations may use any persistent backend (SQL, Redis, blob storage) that satisfies the interface.
Typical usage
state = await container.resolve(StateStoreProtocol)await state.set("session:abc123", {"user_id": "u-1"}, ttl=3600)data = await state.get("session:abc123")Get a value by key.
| Parameter | Type | Description |
|---|---|---|
| `key` | str | The key to retrieve. |
| Type | Description |
|---|---|
| Any | None | The value if found, None otherwise. |
Set a value with optional TTL.
| Parameter | Type | Description |
|---|---|---|
| `key` | str | The key to set. |
| `value` | Any | The value to store. |
| `ttl` | int | None | Optional time-to-live in seconds. |
Delete a key.
| Parameter | Type | Description |
|---|---|---|
| `key` | str | The key to delete. |
| Type | Description |
|---|---|
| bool | True if deleted, False if not found. |
Check if a key exists.
| Parameter | Type | Description |
|---|---|---|
| `key` | str | The key to check. |
| Type | Description |
|---|---|
| bool | True if exists, False otherwise. |
Set expiration on a key.
| Parameter | Type | Description |
|---|---|---|
| `key` | str | The key to expire. |
| `ttl` | int | Time-to-live in seconds. |
| Type | Description |
|---|---|
| bool | True if timeout was set, False if key doesn't exist. |
Get remaining TTL for a key.
| Parameter | Type | Description |
|---|---|---|
| `key` | str | The key to check. |
| Type | Description |
|---|---|
| int | TTL in seconds, -1 if no expiry, -2 if key doesn't exist. |
Return a mapping of keys → values for all keys that exist.
| Parameter | Type | Description |
|---|---|---|
| `keys` | list[str] | List of storage keys to fetch. |
| Type | Description |
|---|---|
| dict[str, Any] | Dict containing only keys that were found; absent keys are omitted. |
Persist multiple key-value pairs in a single operation.
| Parameter | Type | Description |
|---|---|---|
| `items` | dict[str, Any] | Mapping of storage keys to JSON-serializable values. |
| `ttl` | int | None | Optional time-to-live in seconds applied to all entries. |
StrategyProtocol
Section titled “StrategyProtocol”Protocol for agent reasoning strategies.
A strategy implements the reasoning loop that drives an agent’s behavior. Built-in strategies: ReActStrategy (reason → act → observe) and PlanAndExecuteStrategy (plan → execute steps).
async def execute( message: str, tools: list[ToolProtocol], history: list[dict[str, Any]], llm: Any, **kwargs: Any ) -> Any
Execute the reasoning strategy.
| Parameter | Type | Description |
|---|---|---|
| `message` | str | The user's input message. |
| `tools` | list[ToolProtocol] | Tools available to the agent. |
| `history` | list[dict[str, Any]] | Conversation history as list of message dicts. |
| `llm` | Any | LLM client for reasoning. **kwargs: Additional strategy-specific parameters (system_prompt, temperature, tool_registry, etc.) |
| Type | Description |
|---|---|
| Any | Result[AgentResponse, Exception] |
TaskExecutorProtocol
Section titled “TaskExecutorProtocol”Protocol for task executor implementations.
Executors process tasks from a queue by dispatching them to registered handlers.
Example
class TaskExecutorProtocol: async def execute(self, task: Task) -> Any: handler = self._handlers.get(task.name) if handler: return await handler(task.payload) raise UnknownTaskError(task.name)Execute a task using the registered handler.
| Parameter | Type | Description |
|---|---|---|
| `task` | Any | Task to execute. |
| Type | Description |
|---|---|
| Any | Task execution result. |
| Exception | Description |
|---|---|
| UnknownTaskError | If no handler registered for task. |
Register a handler for a task type.
| Parameter | Type | Description |
|---|---|---|
| `task_name` | str | Name of the task type. |
| `handler` | Any | Async callable to handle the task. |
Get the handler for a task type.
| Parameter | Type | Description |
|---|---|---|
| `task_name` | str | Name of the task type. |
| Type | Description |
|---|---|
| Any | None | Handler if registered, None otherwise. |
TaskProviderProtocol
Section titled “TaskProviderProtocol”Protocol for task provider implementations.
Task providers integrate task processing with the framework, providing dependency injection, lifecycle management, and health monitoring.
Register task services with the DI container.
| Parameter | Type | Description |
|---|---|---|
| `container` | Any | DI container to register services in. |
Start the task provider.
Called by the framework on application startup.
| Parameter | Type | Description |
|---|---|---|
| `container` | Any | None | Optional DI container. |
Shutdown the task provider gracefully.
Called by the framework on application shutdown.
| Parameter | Type | Description |
|---|---|---|
| `app` | Any | Application instance. |
Check task provider health.
| Type | Description |
|---|---|
| HealthCheckResult | HealthCheckResult with current status and metrics. |
Register a task handler.
| Parameter | Type | Description |
|---|---|---|
| `task_name` | str | Name of the task type. |
| `handler` | Any | Async handler function. |
Register a decorated task function for scheduling.
| Parameter | Type | Description |
|---|---|---|
| `task_func` | Any | Task function decorated with @scheduled. |
Enqueue a job for processing.
| Parameter | Type | Description |
|---|---|---|
| `job` | Any | JobProtocol instance to enqueue. |
| Type | Description |
|---|---|
| str | JobProtocol ID. |
def schedule_job( job_template: Any, cron_expression: str, job_id: str | None = None ) -> str | None
Schedule a job with cron expression.
| Parameter | Type | Description |
|---|---|---|
| `job_template` | Any | JobProtocol or JobTemplateProtocol instance. |
| `cron_expression` | str | Cron expression for scheduling. |
| `job_id` | str | None | Optional job ID. |
| Type | Description |
|---|---|
| str | None | Scheduled job ID if successful, None otherwise. |
Remove a scheduled job.
| Parameter | Type | Description |
|---|---|---|
| `job_id` | str | JobProtocol ID to unschedule. |
| Type | Description |
|---|---|
| bool | True if job was unscheduled, False otherwise. |
Get worker pool statistics.
| Type | Description |
|---|---|
| dict[str, Any] | None | Dictionary with worker statistics or None. |
Get scheduled jobs information.
| Type | Description |
|---|---|
| dict[str, Any] | None | Dictionary with scheduled jobs info or None. |
TaskQueueProtocol
Section titled “TaskQueueProtocol”Protocol for task queue implementations.
This defines the contract for background task queues (Redis-based, PostgreSQL-based, in-memory, etc.).
Example
class RedisTaskQueue: async def enqueue(self, task: Task) -> str: task_id = str(uuid4()) await self._redis.rpush("tasks", task.to_json()) return task_id
async def dequeue(self) -> Task | None: data = await self._redis.lpop("tasks") return Task.from_json(data) if data else NoneAdd a task to the queue.
| Parameter | Type | Description |
|---|---|---|
| `task` | Any | Task instance to enqueue. |
| Type | Description |
|---|---|
| Result[str, TaskQueueError] | Ok(task_id) on success; Err(TaskQueueError) if the queue reports a recoverable failure (e.g. full queue, invalid payload). Only infrastructure failures (lost connection) are raised as exceptions. |
Remove and return the next task.
| Type | Description |
|---|---|
| Any | None | Next Task or None if queue is empty. |
Get the number of tasks in the queue.
| Type | Description |
|---|---|
| int | Number of pending tasks. |
Clear all tasks from the queue.
Acknowledge successful processing of a dequeued task.
Signals that the task has been processed successfully and can be permanently discarded from any in-flight tracking.
| Parameter | Type | Description |
|---|---|---|
| `task_id` | str | ID of the task to acknowledge. |
Negative-acknowledge a dequeued task.
Signals that the task could not be processed. The task is optionally requeued for another processing attempt.
| Parameter | Type | Description |
|---|---|---|
| `task_id` | str | ID of the task to negative-acknowledge. |
| `requeue` | bool | If True, return the task to the queue for retry. If False, discard the task permanently. |
Close the queue connection and cleanup resources.
TenantConfigProviderProtocol
Section titled “TenantConfigProviderProtocol”Per-tenant configuration key-value store.
Provides a low-level get/set interface. The higher-level TenantConfigService adds default fallback and event emission on top of this protocol.
Retrieve a single configuration value for a tenant.
| Parameter | Type | Description |
|---|---|---|
| `tenant_id` | str | The tenant whose configuration is queried. |
| `key` | str | The configuration key. |
| Type | Description |
|---|---|
| Any | None | The stored value, or ``None`` if the key is not set for this tenant. |
Retrieve all configuration entries for a tenant.
| Parameter | Type | Description |
|---|---|---|
| `tenant_id` | str | The tenant whose configuration is retrieved. |
| Type | Description |
|---|---|
| dict[str, Any] | A dictionary of all key-value pairs for the tenant. Returns an empty dict if no overrides are set. |
Set a configuration value for a tenant.
| Parameter | Type | Description |
|---|---|---|
| `tenant_id` | str | The tenant whose configuration is updated. |
| `key` | str | The configuration key. |
| `value` | Any | The new value (must be JSON-serialisable). |
TenantIsolationStrategyProtocol
Section titled “TenantIsolationStrategyProtocol”Pluggable data isolation strategy.
Implementations provide the mechanics of isolating tenant data at the database layer (row-level, schema-per-tenant, or database-per-tenant).
Attributes:
name: Strategy identifier used by the registry
("row_level", "schema", "database").
Apply tenant isolation to the given execution context.
For row-level isolation this is a no-op; for schema isolation this sets
the search_path in context.
| Parameter | Type | Description |
|---|---|---|
| `tenant_id` | str | The active tenant. |
| `context` | dict[str, Any] | Mutable execution context dict to annotate. |
Remove any active isolation for the tenant.
| Parameter | Type | Description |
|---|---|---|
| `tenant_id` | str | The tenant whose isolation context to tear down. |
async def provision_isolation(tenant_id: str) -> Result[None, TenantError]
Provision isolation resources for a newly created tenant.
For row-level isolation this is a no-op. For schema isolation this creates the schema.
| Parameter | Type | Description |
|---|---|---|
| `tenant_id` | str | The newly created tenant. |
| Type | Description |
|---|---|
| Result[None, TenantError] | ``Ok(None)`` on success, ``Err(TenantError)`` on failure. |
async def deprovision_isolation(tenant_id: str) -> Result[None, TenantError]
Tear down isolation resources for a deactivated tenant.
| Parameter | Type | Description |
|---|---|---|
| `tenant_id` | str | The tenant being deactivated. |
| Type | Description |
|---|---|
| Result[None, TenantError] | ``Ok(None)`` on success, ``Err(TenantError)`` on failure. |
TenantProviderProtocol
Section titled “TenantProviderProtocol”Storage-agnostic tenant CRUD operations.
Applications may supply their own implementation by binding a class to
this protocol in the DI container. The default implementations are
InMemoryTenantProvider (for
testing/dev) and SQLTenantProvider (when
lexigram-tenancy[sql] is installed).
async def get_tenant(tenant_id: str) -> TenantInfo | None
Retrieve a tenant by its unique identifier.
| Parameter | Type | Description |
|---|---|---|
| `tenant_id` | str | The unique tenant identifier. |
| Type | Description |
|---|---|
| TenantInfo | None | The TenantInfo record, or ``None`` if no tenant with that ID exists. |
async def get_tenant_by_slug(slug: str) -> TenantInfo | None
Retrieve a tenant by its URL-safe slug.
| Parameter | Type | Description |
|---|---|---|
| `slug` | str | The tenant slug (e.g. ``acme-corp``). |
| Type | Description |
|---|---|
| TenantInfo | None | The matching TenantInfo, or ``None`` if not found. |
async def list_tenants( *, active_only: bool = True ) -> list[TenantInfo]
List tenants, optionally filtering to active ones only.
| Parameter | Type | Description |
|---|---|---|
| `active_only` | bool | When ``True`` (default), return only tenants with ``status == ACTIVE``. |
| Type | Description |
|---|---|
| list[TenantInfo] | List of matching TenantInfo records. |
async def create_tenant(command: CreateTenantCommand) -> Result[TenantInfo, TenantError]
Persist a new tenant record.
| Parameter | Type | Description |
|---|---|---|
| `command` | CreateTenantCommand | CreateTenantCommand with the new tenant's attributes. |
| Type | Description |
|---|---|
| Result[TenantInfo, TenantError] | ``Ok(TenantInfo)`` on success, ``Err(TenantError)`` on failure. |
async def update_tenant( tenant_id: str, command: UpdateTenantCommand ) -> Result[TenantInfo, TenantError]
Update mutable fields on an existing tenant record.
| Parameter | Type | Description |
|---|---|---|
| `tenant_id` | str | Identifier of the tenant to update. |
| `command` | UpdateTenantCommand | UpdateTenantCommand with the fields to apply. |
| Type | Description |
|---|---|
| Result[TenantInfo, TenantError] | ``Ok(TenantInfo)`` with the updated record, or ``Err(TenantError)``. |
async def deactivate_tenant(tenant_id: str) -> Result[None, TenantError]
Mark a tenant as inactive.
| Parameter | Type | Description |
|---|---|---|
| `tenant_id` | str | Identifier of the tenant to deactivate. |
| Type | Description |
|---|---|
| Result[None, TenantError] | ``Ok(None)`` on success, ``Err(TenantError)`` on failure. |
async def activate_tenant(tenant_id: str) -> Result[None, TenantError]
Mark a tenant as active.
| Parameter | Type | Description |
|---|---|---|
| `tenant_id` | str | Identifier of the tenant to activate. |
| Type | Description |
|---|---|
| Result[None, TenantError] | ``Ok(None)`` on success, ``Err(TenantError)`` on failure. |
async def suspend_tenant( tenant_id: str, reason: str | None = None ) -> Result[None, TenantError]
Mark a tenant as suspended.
| Parameter | Type | Description |
|---|---|---|
| `tenant_id` | str | Identifier of the tenant to suspend. |
| `reason` | str | None | Optional human-readable reason for the suspension. |
| Type | Description |
|---|---|
| Result[None, TenantError] | ``Ok(None)`` on success, ``Err(TenantError)`` on failure. |
TenantResolverProtocol
Section titled “TenantResolverProtocol”Resolves tenant identity from request context.
Implementations are tried in priority order by
CompositeResolver.
Lower priority value = tried first = higher trust level.
Attributes:
name: Unique resolver name (e.g. "header", "jwt_claim").
priority: Ordering weight; lower = tried first.
async def resolve(context: TenantResolutionContext) -> str | None
Attempt to resolve the tenant identifier from the given context.
| Parameter | Type | Description |
|---|---|---|
| `context` | TenantResolutionContext | Immutable snapshot of request data. |
| Type | Description |
|---|---|
| str | None | The resolved ``tenant_id`` string, or ``None`` if this resolver cannot determine the tenant from the provided context. |
TokenCounterProtocol
Section titled “TokenCounterProtocol”Model-aware token counter.
Implementations use the exact tokenizer for the target model (tiktoken for OpenAI, AutoTokenizer for HuggingFace, mistral-common for Mistral). A character-estimate fallback is always available.
Note: Methods are synchronous because tokenization is CPU-bound with no I/O.
Count tokens in a text string.
Count tokens in a list of chat messages, including message overhead.
The model this counter is calibrated for.
TokenManagerProtocol
Section titled “TokenManagerProtocol”Protocol for token management implementations.
Defines the contract for JWT token creation, verification, and refresh operations.
Example
class JWTTokenManager: def create_token(self, user: AuthenticatedUserProtocol) -> AuthToken: payload = {"sub": user.user_id, "roles": user.roles} access = jwt.encode(payload, self._secret, algorithm="HS256") return AuthToken(access_token=access, ...)def create_token(user: AuthenticatedUserProtocol) -> Any
Create an authentication token for a user.
| Parameter | Type | Description |
|---|---|---|
| `user` | AuthenticatedUserProtocol | The authenticated user. |
| Type | Description |
|---|---|
| Any | AuthToken containing access and refresh tokens. |
def verify_token(token: str) -> Result[VerifiedToken, TokenError]
Verify and decode a token.
Returns a Result rather than raising domain exceptions so that
the caller can pattern-match on success vs. failure explicitly.
Infrastructure errors (cache unavailable, network failure) are still
raised as exceptions and must not be wrapped in Result.
| Parameter | Type | Description |
|---|---|---|
| `token` | str | The JWT token string. |
| Type | Description |
|---|---|
| Result[VerifiedToken, TokenError] | ``Ok(VerifiedToken)`` if the token is valid and not revoked, or ``Err(TokenError)`` for any expected domain failure. |
def refresh_token(refresh_token: str) -> Result[Any, TokenError]
Refresh an access token using a refresh token.
| Parameter | Type | Description |
|---|---|---|
| `refresh_token` | str | The refresh token string. |
| Type | Description |
|---|---|
| Result[Any, TokenError] | ``Ok(AuthToken)`` if the refresh token is valid, or ``Err(TokenError)`` for expected domain failures. |
ToolProtocol
Section titled “ToolProtocol”Protocol for agent tools.
Tools are the atomic capabilities an agent can invoke during reasoning. Each tool has a name, description, JSON parameter schema (for LLM function calling), and an async execute method.
Satisfied by:
- @tool decorated functions (FunctionTool)
- Classes extending Tool base class
Unique tool identifier.
Human-readable description for the LLM.
JSON Schema describing the tool’s parameters.
Auto-generated from type hints by the @tool decorator, or manually defined for class-based tools.
Format follows OpenAI function calling schema
{ "type": "object", "properties": { "order_id": {"type": "string"}, "reason": {"type": "string"} }, "required": ["order_id"]}Execute the tool with the given arguments.
Returns the tool’s result. Errors should be raised as exceptions — the executor wraps them in Result.
ToolRegistryProtocol
Section titled “ToolRegistryProtocol”Protocol for tool registries.
A registry stores tools by name and provides execution with error handling. When module visibility is enabled, tool access is checked against the compiled module graph.
def register( tool: ToolProtocol, module_class: type | None = None ) -> None
Register a tool.
def get(name: str) -> ToolProtocol | None
Get a tool by name.
def list_tools() -> list[ToolProtocol]
List all registered tools.
def list_visible_tools() -> list[ToolProtocol]
List tools visible to the current caller module.
List names of tools visible to the current caller module.
Set the compiled module graph for visibility enforcement.
Set the calling module for visibility checks.
Execute a tool by name.
Returns Result[Any, ToolError].
UnitOfWorkProtocol
Section titled “UnitOfWorkProtocol”Protocol for Unit of Work pattern.
Coordinates multiple repository operations within a single transaction boundary.
Example
async with uow: user = await uow.users.get(user_id) user.email = new_email await uow.users.save(user) await uow.audit_log.save(AuditEntry(...)) await uow.commit()Commit all changes in this unit of work.
Rollback all changes in this unit of work.
Register a new entity for insertion.
Register a domain event with this unit of work.
Handlers or repositories may call this method when they detect that a domain event needs to be published once the transaction successfully commits. The unit of work is responsible for retaining the events until they are gathered by the application and dispatched via an event bus.
Return and clear all domain events registered with this unit of work.
Calling this method yields the list of events that have been registered
either explicitly via register_event or implicitly by the UoW
when entities with collect_events semantics are registered. The
returned list is cleared from the unit of work; subsequent calls will
return an empty list until more events are registered.
Register an entity for update.
Register an entity for deletion.
UserProtocol
Section titled “UserProtocol”Protocol for user entity.
Defines the minimal contract for a user in the system.
Unique user identifier.
User email address.
Whether user account is active.
VectorStoreProtocol
Section titled “VectorStoreProtocol”Top-level vector store lifecycle and collection management.
Implementations manage connections, collection CRUD, and delegate
vector operations to VectorCollectionProtocol instances.
Establish connection to the vector store.
Close all connections and release resources.
Check store connectivity and readiness.
List all collections with metadata.
Create a new vector collection.
| Exception | Description |
|---|---|
| CollectionAlreadyExistsError | If collection name is taken. |
| VectorConfigError | If config is invalid for this backend. |
Delete a collection and all its vectors.
| Exception | Description |
|---|---|
| CollectionNotFoundError | If collection does not exist. |
Check whether a collection exists.
Get a handle to an existing collection.
| Exception | Description |
|---|---|
| CollectionNotFoundError | If collection does not exist. |
WebhookSignatureVerifierProtocol
Section titled “WebhookSignatureVerifierProtocol”Verifies the authenticity of inbound webhook payloads.
Implementations must provide both a verification method and a signature computation method so callers can independently validate or generate signatures without exposing the underlying algorithm.
The canonical implementation is HMAC-SHA256, but any MAC or asymmetric scheme that fulfils this protocol is acceptable.
Typical usage
verifier = HMACWebhookVerifier()if not verifier.verify(payload=body, signature=sig_header, secret=secret): raise PermissionError("Invalid webhook signature")Return True when the signature matches the payload.
Implementations must use a constant-time comparison to prevent timing side-channel attacks.
| Parameter | Type | Description |
|---|---|---|
| `payload` | bytes | Raw request body bytes. |
| `signature` | str | Signature string as received in the request header (may include algorithm prefix such as ``"sha256=..."``). |
| `secret` | str | Shared secret used to compute the expected signature. |
| Type | Description |
|---|---|
| bool | ``True`` if the signature is valid, ``False`` otherwise. |
Compute the expected signature for payload using secret.
| Parameter | Type | Description |
|---|---|---|
| `payload` | bytes | Raw request body bytes. |
| `secret` | str | Shared secret. |
| Type | Description |
|---|---|
| str | Hex-encoded signature string in the same format that verify expects as input. |
WorkflowNodeProtocol
Section titled “WorkflowNodeProtocol”Protocol for individual workflow step nodes.
A workflow node represents a single unit of work in a directed graph. Nodes receive the current shared state, perform their work, and return a state update dict that is merged into the global state.
Unique node identifier within the workflow.
Execute this node with the current workflow state.
| Parameter | Type | Description |
|---|---|---|
| `state` | dict[str, Any] | Current shared workflow state. |
| Type | Description |
|---|---|
| dict[str, Any] | Dict of state updates to merge into the shared state. |
WorkingMemoryProtocol
Section titled “WorkingMemoryProtocol”Protocol for working memory that assembles context for the current request.
Working memory is the in-context window that gets passed to the LLM, assembled from episodic and semantic memory based on token budgets.
Assemble context window from available memory tiers.
Retrieves relevant entries from episodic and semantic memory and fits them within the token budget.
| Parameter | Type | Description |
|---|---|---|
| `query` | str | The current query/prompt |
| `token_budget` | int | Maximum tokens available for context |
| Type | Description |
|---|---|
| list[MemoryEntry] | Ordered list of memory entries for context |
Add a new entry to the working memory stream.
| Parameter | Type | Description |
|---|---|---|
| `entry` | MemoryEntry | The entry to add |
Get current assembled context entries.
| Type | Description |
|---|---|
| list[MemoryEntry] | List of entries currently in context window |
Clear the current context assembly.
Check if the working memory backend is reachable and healthy.
| Parameter | Type | Description |
|---|---|---|
| `timeout` | float | Maximum seconds to wait for a response. |
| Type | Description |
|---|---|
| HealthCheckResult | Health check result with status and details. |
Classes
Section titled “Classes”AgentResponse
Section titled “AgentResponse”Complete response from an agent execution.
Contains the final message, the full reasoning trace (steps), all tool calls made, token usage, cost, and timing metadata.
Note: ToolCall and ReasoningStep are defined in lexigram-ai-agents and imported here for use in this type’s field annotations.
Number of tool calls made.
Number of reasoning steps taken.
Tool calls that completed without error.
Tool calls that failed.
Serialize to a JSON-compatible dict.
AggregateHealthResult
Section titled “AggregateHealthResult”Composite health result that collects checks from multiple components.
The aggregate status follows a worst-case rule:
- Any
UNHEALTHYcheck → overallUNHEALTHY - Any
DEGRADEDcheck (no UNHEALTHY) → overallDEGRADED - All
HEALTHY→ overallHEALTHY - No checks registered →
UNKNOWN
Overall status, computed from component checks.
Return True only if all components are healthy.
Convert to a dictionary suitable for a /health HTTP response.
AuditEntry
Section titled “AuditEntry”Immutable record of a security-relevant or compliance-relevant operation.
Canonical audit type used by all packages. Supersedes the former
AuditEvent (simpler, no old/new values) and the AuditEntry
from contracts/observability/audit.
Attributes:
action: Dot-notation action identifier (e.g. "user.update").
actor_id: ID of the user or service that performed the action.
resource_type: Kind of affected resource (e.g. "User").
resource_id: ID of the affected resource.
outcome: "success" or "failure".
severity: Severity level (defaults to MEDIUM).
occurred_at: UTC datetime of the event (defaults to now).
metadata: Arbitrary additional context.
old_values: Field values before the action (optional).
new_values: Field values after the action (optional).
source: Originating subsystem (e.g. "sql", "admin", "ai").
tenant_id: Multi-tenant scoping (optional).
CircuitBreakerConfig
Section titled “CircuitBreakerConfig”Configuration for circuit breaker.
Attributes:
failure_threshold: Number of failures before opening the circuit.
recovery_timeout: Seconds in open state before attempting half-open.
expected_exception: Exception types that count as failures.
success_threshold: Consecutive successes required to close from half-open.
timeout: Per-call timeout in seconds.
name: Human-readable identifier for this breaker instance.
sliding_window_seconds: Window for computing the failure rate.
failure_rate_threshold: Fraction of calls that must fail to trip.
backend: State store backend for distributed circuit breaker coordination.
"memory" (default) — in-process state, no coordination.
"redis" — uses a CacheBackendProtocol
resolved from the DI container.
"consul" — uses Consul KV for cross-datacenter coordination.
CursorPage
Section titled “CursorPage”Cursor-based pagination for large datasets.
Attributes: items: The entities in this page. next_cursor: Opaque cursor for the next page, or None if no more. prev_cursor: Opaque cursor for the previous page, or None. has_more: Whether there are more results after this page. has_previous: Whether there are results before this page. total_count: Optional total count (may be None for performance).
DeleteResult
Section titled “DeleteResult”Result of a delete operation.
DomainEvent
Section titled “DomainEvent”Base class for domain events.
Initialize the event setting base fields and any extra subclass fields.
Declared dataclass fields receive their default values when not
supplied. Extra keyword arguments (e.g. fields declared on plain
subclasses without @dataclass) are set directly on the instance
via object.__setattr__, which bypasses the frozen=True
guard safely during construction.
Return a JSON-serializable dictionary representation.
Duration
Section titled “Duration”Immutable duration value object.
The class stores total seconds internally and provides lightweight parsing, formatting, and arithmetic helpers for configuration and API boundaries.
def seconds( cls, value: float ) -> Duration
Create a duration from seconds.
def minutes( cls, value: float ) -> Duration
Create a duration from minutes.
def hours( cls, value: float ) -> Duration
Create a duration from hours.
def days( cls, value: float ) -> Duration
Create a duration from days.
def zero(cls) -> Duration
Create a zero duration.
def parse( cls, value: str ) -> Duration
Parse a human-readable duration string.
Supported units are seconds (s), minutes (m), hours (h),
and days (d). Chained forms like 1h30m are supported.
Backward-compatible alias for the total seconds.
Convert the duration to datetime.timedelta.
ErrorDetail
Section titled “ErrorDetail”Single error detail in an HTTP error response.
Attributes: code: Machine-readable error code (e.g., “INVALID_INPUT”). message: Human-readable error message. field: Optional field name that caused the error (for form validation).
ErrorResponseDTO
Section titled “ErrorResponseDTO”Standard HTTP error response envelope.
Provides a consistent structure for error responses across all endpoints. Should be used with appropriate HTTP status codes (4xx, 5xx).
Attributes: error: High-level error category. message: Human-readable summary of what went wrong. details: List of specific error details (empty for simple errors). request_id: Optional request identifier for tracing and support.
FlagEvaluation
Section titled “FlagEvaluation”The result of evaluating a single feature flag.
Attributes: key: The flag identifier. value: The evaluated value (type depends on FlagType). flag_type: The type of flag evaluated. reason: Machine-readable reason code (e.g. “DEFAULT”, “TARGETING”). variant: Variant key for VARIANT-type flags, None otherwise. metadata: Arbitrary evaluation metadata from the provider.
FlagType
Section titled “FlagType”The evaluation strategy of a feature flag.
GeneratorDefinition
Section titled “GeneratorDefinition”Describes a single executable scaffolding generator contributed to the CLI.
Generators are discovered via CliContributorProtocol.get_generators()
and assembled into the unified gen command by CommandAssembler.
generator_path is required so every definition can be executed once it
has been discovered and registered.
GeneratorOption
Section titled “GeneratorOption”A single CLI option/flag accepted by a generator command.
Used for auto-generated help text and input validation.
HealthCheckResult
Section titled “HealthCheckResult”Result of a health check.
Convert to dictionary format.
Check if status is healthy.
Check if status is degraded.
HealthStatus
Section titled “HealthStatus”Unified health status.
IdStrategy
Section titled “IdStrategy”Available ID generation strategies.
InsertResult
Section titled “InsertResult”Result of an insert operation.
JobStatus
Section titled “JobStatus”JobProtocol execution status.
Lifecycle
Section titled “Lifecycle”Provider lifecycle stages.
LockInfo
Section titled “LockInfo”Immutable snapshot of a distributed lock's state.
Attributes: resource: The resource being locked. holder: Identifier of the current holder. acquired_at: Unix timestamp when the lock was acquired. expires_at: Unix timestamp when the lock expires (TTL). metadata: Additional implementation-specific data.
Check if the lock has expired.
Get remaining TTL in seconds.
MigrationRecord
Section titled “MigrationRecord”Record of a database migration.
PaginatedResponseDTO
Section titled “PaginatedResponseDTO”Standard paginated HTTP response envelope.
Encapsulates a page of results with metadata for navigation. Supports both offset-based and cursor-based pagination.
Attributes: items: The entities in this page. total: Total count of items across all pages. page: Current page number (1-indexed, 0-indexed for cursor). page_size: Maximum items returned per page. has_next: Whether there are more pages after this one. has_prev: Whether there are pages before this one. next_cursor: Opaque cursor for the next page (for cursor-based pagination).
ProviderPriority
Section titled “ProviderPriority”Provider initialization priority.
Providers are booted in ascending order of priority. Lower values run first; the typical ordering is:
CRITICAL(0) – absolutely foundational services that others depend on (e.g. configuration, diagnostics).INFRASTRUCTURE(10) – low-level plumbing such as database connections, messaging clients, and cache providers.SECURITY(20) – authentication/authorization infrastructure.NORMAL(30) – everyday domain services with no special ordering.APPLICATION(40) – application-level tools (CLI, admin utilities) that depend on domain services but are not themselves domain logic.DOMAIN(50) – business-logic providers that may depend on earlier layers.PRESENTATION(80) – web/API layers and other entry points.COMMS(90) – outbound communication providers (email, SMS, webhooks) often run late to avoid interfering with core initialization.LOW(100) – lowest-priority, optional providers that can boot last.
QueryLogEntry
Section titled “QueryLogEntry”Represents a database query log entry.
This is a concrete dataclass rather than a Protocol so that callers can instantiate it directly.
QueryResult
Section titled “QueryResult”Result of a database query.
Implements the iterator and sequence protocols so that code expecting
a plain list[dict] from a query result continues to work after the
return type is normalised to QueryResult.
Example
result = await provider.execute_query("SELECT * FROM users")for row in result: # iterate directly print(row["email"])if not result: # bool coercion raise LookupError("no rows")first = result[0] # index accessrows = list(result) # convert to plain listResult
Section titled “Result”Base Result type. Not abstract — Ok and Err are the only variants.
Wrap a caught exception into an Err result.
RetryConfig
Section titled “RetryConfig”Configuration for retry policy.
ServiceScope
Section titled “ServiceScope”Dependency injection scopes.
SpecificationProtocol
Section titled “SpecificationProtocol”Protocol for the SpecificationProtocol pattern.
This class was previously defined in lexigram.contracts.specification
before the 2026 reorg. It has been moved here alongside the other
DDD primitives. A migration mapping ensures imports are rewritten.
TenantInfo
Section titled “TenantInfo”Core tenant identity record.
The config field here is the tenant’s static provisioning config
(plan limits, feature flags set at creation time). Runtime per-tenant
overrides are managed separately by TenantConfigProviderProtocol /
TenantConfigService. The two are independent — TenantInfo.config
is a snapshot stored alongside the tenant record; TenantConfigService
is a live, cached, key-value overlay.
Attributes:
tenant_id: Unique identifier for the tenant.
slug: URL-safe, human-readable identifier (e.g. acme-corp).
name: Display name of the tenant.
status: Current lifecycle status.
plan: Subscription plan name (optional).
config: Static provisioning configuration snapshot.
metadata: Arbitrary application-defined metadata.
created_at: Timestamp when the tenant was created.
TenantResolutionContext
Section titled “TenantResolutionContext”Immutable snapshot of request data available for tenant resolution.
Passed to every TenantResolverProtocol during the resolution chain so resolvers can inspect request metadata without depending on any web framework type.
Attributes:
headers: HTTP request headers (lowercased keys).
host: The Host header value (e.g. acme.app.com).
path: The request path (e.g. /api/tenants/acme/users).
claims: Decoded JWT claims from the current authentication context.
TenantStatus
Section titled “TenantStatus”Lifecycle status of a tenant.
Attributes: ACTIVE: Tenant is fully operational and accepts requests. INACTIVE: Tenant has been deactivated and no longer accepts requests. SUSPENDED: Tenant has been suspended (e.g. for non-payment) and is temporarily blocked from accessing the system. PROVISIONING: Tenant is being created; isolation resources are being set up.
TokenBudget
Section titled “TokenBudget”Immutable token budget that pipeline stages consult.
Every field is calculated once at the start of a request. Stages read remaining capacity via properties — they never mutate the budget. Builder methods return new instances (immutable value semantics).
Total tokens consumed by all components.
Tokens available for additional content.
Tokens available specifically for chat history.
True if total consumption exceeds the model context limit.
def with_rag_tokens(rag_tokens: int) -> TokenBudget
Return a new budget with updated RAG token count.
def with_history_tokens(history_tokens: int) -> TokenBudget
Return a new budget with updated history token count.
UpdateResult
Section titled “UpdateResult”Result of an update operation.
Exceptions
Section titled “Exceptions”AgentError
Section titled “AgentError”Base exception for all agent errors.
DuplicateHandlerError
Section titled “DuplicateHandlerError”Duplicate handler registration.
Raised when attempting to register a handler for a type that already has one.
HandlerNotFoundError
Section titled “HandlerNotFoundError”Event/command handler not found.
Raised when no handler is registered for a specific event or command type.
MCPError
Section titled “MCPError”Base exception for all MCP errors.
MCPInitializationError
Section titled “MCPInitializationError”MCP server initialization failed.
Raised when the MCP server cannot be initialized, usually due to missing required handlers or configuration errors.
MCPMethodNotFoundError
Section titled “MCPMethodNotFoundError”Unknown MCP method requested by client.
Raised when the client requests an MCP method that the server does not support.
MCPPromptError
Section titled “MCPPromptError”Prompt retrieval or list failed.
Raised when a prompt operation fails, such as when a prompt is not found or arguments are invalid.
MCPProtocolError
Section titled “MCPProtocolError”Protocol violation (malformed message, invalid state).
Raised when an MCP message violates the protocol specification, such as missing required fields or invalid JSON-RPC structure.
MCPResourceError
Section titled “MCPResourceError”Resource read or list failed.
Raised when a resource operation fails, such as when a resource is not found or cannot be read.
MCPToolCallError
Section titled “MCPToolCallError”Tool call failed during MCP execution.
Raised when a tool invocation fails, either due to the tool not existing or raising an exception.
SecretAccessError
Section titled “SecretAccessError”Raised when the caller lacks permission to access or modify a secret.
Attributes: secret_name: Name of the secret that was denied access. operation: The operation that was denied (read, write, delete, etc.).
SecretNotFoundError
Section titled “SecretNotFoundError”Raised when a requested secret does not exist.
StrategyError
Section titled “StrategyError”Reasoning strategy failed.
Raised when the agent’s strategy encounters an error during reasoning (LLM failure, invalid response, etc.).
TenantConfigError
Section titled “TenantConfigError”Raised when per-tenant configuration access or mutation fails.
Initialise a TenantConfigError.
| Parameter | Type | Description |
|---|---|---|
| `message` | str | Human-readable description of the config error. **kwargs: Additional context forwarded to the base class. |
TenantError
Section titled “TenantError”Base class for all tenancy-related domain errors.
Initialise a TenantError.
| Parameter | Type | Description |
|---|---|---|
| `message` | str | Human-readable description of the error. **kwargs: Additional context forwarded to the base class. |
TenantInactiveError
Section titled “TenantInactiveError”Raised when an operation is attempted on an inactive tenant.
Initialise a TenantInactiveError.
| Parameter | Type | Description |
|---|---|---|
| `tenant_id` | str | The inactive tenant identifier. **kwargs: Additional context forwarded to the base class. |
TenantNotFoundError
Section titled “TenantNotFoundError”Raised when a requested tenant does not exist.
Initialise a TenantNotFoundError.
| Parameter | Type | Description |
|---|---|---|
| `tenant_id` | str | The tenant identifier that was not found. **kwargs: Additional context forwarded to the base class. |
TenantProvisioningError
Section titled “TenantProvisioningError”Raised when tenant provisioning (isolation setup) fails.
Initialise a TenantProvisioningError.
| Parameter | Type | Description |
|---|---|---|
| `message` | str | Human-readable description of the provisioning failure. **kwargs: Additional context forwarded to the base class. |
TenantResolutionError
Section titled “TenantResolutionError”Raised when tenant resolution fails unexpectedly.
Initialise a TenantResolutionError.
| Parameter | Type | Description |
|---|---|---|
| `message` | str | Human-readable description of the resolution failure. **kwargs: Additional context forwarded to the base class. |
TenantSlugConflictError
Section titled “TenantSlugConflictError”Raised when a tenant slug is already in use.
Initialise a TenantSlugConflictError.
| Parameter | Type | Description |
|---|---|---|
| `slug` | str | The conflicting tenant slug. **kwargs: Additional context forwarded to the base class. |
TenantSuspendedError
Section titled “TenantSuspendedError”Raised when an operation is attempted on a suspended tenant.
Initialise a TenantSuspendedError.
| Parameter | Type | Description |
|---|---|---|
| `tenant_id` | str | The suspended tenant identifier. **kwargs: Additional context forwarded to the base class. |
ToolError
Section titled “ToolError”Base exception for tool errors.
ValidationError
Section titled “ValidationError”Data validation error.
def __init__( message: str = 'Validation failed', errors: list[FieldError] | None = None, **kwargs: Any ) -> None
property errors() -> list[FieldError]
Return the list of field errors.
def add_error( field: str, message: str, code: str = 'invalid' ) -> ValidationError
Add a field error and return self for chaining.