Distiller API¶
Distiller is AI Refinery’s underlying multi-agent collaboration framework. It provides convenient abstractions that let developers quickly create autonomous, collaborative agents capable of advanced reasoning and decision-making.
Before you begin, you must create an authenticated AsyncAIRefinery
client, as shown below. All Distiller-related APIs are accessed via client.distiller
.
import os
from air import AsyncAIRefinery
from dotenv import load_dotenv
load_dotenv() # loads your API_KEY from your local '.env' file
api_key=str(os.getenv("API_KEY"))
client = AsyncAIRefinery(api_key=api_key)
Preliminaries¶
Validating Your Configuration File¶
client.distiller.validate_config()
(synchronous)¶
Validates a distiller configuration file to ensure it works with AI Refinery. This method helps catch configuration errors early in the development workflow by sending your configuration to the server for validation without actually creating a project.
Parameters:
config_path
(Optional[str]): Path to a YAML configuration file. If provided, the file will be loaded and validated. Note: You must provide eitherconfig_path
ORconfig
, but not both. An error will be raised if both parameters are provided.config
(Optional[dict | str]): Either a configuration dictionary (JSON format) or a YAML string. Used when you want to validate a configuration without saving it to a file first.Note: You must provide either
config_path
ORconfig
, but not both. An error will be raised if both parameters are provided.send_yaml_string
(bool, optional): IfTrue
andconfig_path
is provided, sends the raw YAML text to the server. IfFalse
(default), converts the YAML to JSON before sending. This parameter is useful when you need the server to validate the exact YAML syntax.timeout
(float, optional): Request timeout in seconds. Defaults to15.0
.
Returns:
bool
:True
if the configuration is valid and passes all server-side validation checks.False
if validation fails due to configuration errors, network issues, or server problems.
Usage Examples:
# Basic validation with a YAML configuration file
is_valid = client.distiller.validate_config(config_path="example.yaml")
if is_valid:
print("Configuration is valid!")
else:
print("Configuration validation failed.")
# Validate a configuration dictionary
config_dict = {
"orchestrator": {...},
"utility_agents": [...],
"super_agents": [...],
"base_config": {...},
"memory_config": {...}
}
is_valid = client.distiller.validate_config(config=config_dict)
# Send raw YAML string for validation (preserves exact YAML syntax)
is_valid = client.distiller.validate_config(
config_path="example.yaml",
send_yaml_string=True
)
# Usage with custom timeout for large configurations
is_valid = client.distiller.validate_config(
config_path="large_config.yaml",
timeout=30.0
)
Error Handling and Best Practices:
-
Validation Failures: When
validate_config()
returnsFalse
, check your configuration file for common issues such as:- Invalid YAML syntax
- Missing required fields in agent configurations
- Incorrect agent class names
- Invalid model names or parameters
- Malformed nested configurations
-
Error Logging Example: When validation fails, detailed error information is logged. For example, a typo in an agent class name will produce an error log like this:
2025-10-13 11:59:43,999 ERROR air.distiller.client:
Config validation failed: status=422
body={'error': {'code': 'distiller.schema.validation_error', 'message': 'Distiller Configuration Validation Error',
'detail': {'pydantic_errors': [{'type': 'value_error', 'loc': ['utility_agents', 0, 'agent_class'], 'msg':
"Agent class 'AnalyticsAgnt' is not registered.", 'input': 'AnalyticsAgnt', 'ctx': {'error': "Agent class
'AnalyticsAgnt' is not registered."}}]}}}
In this example, the error shows that 'AnalyticsAgnt'
should be 'AnalyticsAgent'
(missing 'e'). The error details include:
- **Location:** `['utility_agents', 0, 'agent_class']` - the exact path in your configuration
- **Issue:** The agent class name has a typo and is not registered
- **Input:** The incorrect value that caused the error
-
Network Issues: If validation fails due to network problems, the method will return
False
. Consider increasing thetimeout
parameter for slow connections. -
Recommended Workflow: Always validate your configuration before calling
create_project()
to catch errors early and avoid failed project creation attempts. -
Configuration Formats: You can validate configurations in multiple ways:
- YAML files via
config_path
- Python dictionaries via
config
- Raw YAML strings via
config
parameter - Choose
send_yaml_string=True
when YAML-specific validation is needed
- YAML files via
Creating Your Project¶
client.distiller.create_project()
(synchronous)¶
Creates a new project based on the specified YAML configuration file.
Parameters:
config_path
(str): The path to the YAML configuration file.project
(str): A name for your project (letters, digits, hyphens, underscores only).
Returns:
bool
:True
if the project is successfully created.
Project Versioning:
- Distiller automatically handles project versioning, starting at version 0.
- The first time you create a project with a given name, it is assigned version 0. If you create another project with the same name, Distiller increments the version to 1, and so on.
- By default, connections are made to the latest project version unless a specific version is specified. For more details, refer to the distiller connection section below.
Example:
# This command registers the project "example" using the "example.yaml" configuration file.
client.distiller.create_project(config_path="example.yaml", project="example")
Downloading Your Project Configuration¶
client.distiller.download_project()
(synchronous)¶
Retrieves the configuration of a specified project from the server.
Parameters:
project
(str): The name of the project whose configuration you want to download.project_version
(str, optional): The version of the project configuration to download. Defaults to the latest version if not provided.
Returns:
dict
: A Python dictionary containing the downloaded configuration.
Example:
# This command downloads version "1" of the "example" project.
project_config = client.distiller.download_project(project="example", project_version="1")
Connecting to Distiller¶
client.distiller.__call__()
(asynchronous)¶
Establishes an asynchronous connection (via a WebSocket) to the Distiller endpoint for a specific project. Usage of this function within an async context manager allows easy management of all Distiller-related operations.
Parameters:
project
(str): The project name (letters, digits, hyphens, underscores only).uuid
(str): A unique user identifier (letters, digits, hyphens, underscores only).executor_dict
(dict[str, Callable], optional): A dictionary mapping custom agent names to callable functions. These callables are invoked when their corresponding agents are triggered by the super agent or orchestrator. Defaults to{}
.project_version
(str, optional): The project version to connect to. If not provided, Distiller uses the latest version.
Returns:
_DistillerContextManager
: An asynchronous context manager that handles operations within the given project.
Example:
async with client.distiller(
project="example",
uuid="test"
) as dc:
# Your asynchronous operations here
pass
client.distiller.query()
(asynchronous)¶
Sends a query message to the WebSocket asynchronously.
Parameters:
query
(str): The text of your query.image
(Optional[str], optional): An image to include in the query. Defaults toNone
.**kwargs
: Additional keyword arguments.
Returns:
Coroutine
: A coroutine that, when awaited, sends the query request.
Example:
async with client.distiller(
project="example",
uuid="test"
) as dc:
responses = await dc.query(query="hi")
async for response in responses:
print(response)
client.distiller.add_memory()
(asynchronous)¶
Adds memory to the WebSocket asynchronously.
Parameters:
**kwargs
: Any keyword arguments you want to store as memory.
Returns:
Coroutine
: A coroutine that, when awaited, adds the specified memory.
Example:
async with client.distiller(
project="example",
uuid="test"
) as dc:
# Adding environment variables to memory
await dc.add_memory(
source="env_variable",
variables_dict={"travel_destinations": "Hidden gems and cultural hotspots"},
)
client.distiller.retrieve_memory()
(asynchronous)¶
Retrieves memory from the WebSocket asynchronously.
Parameters:
**kwargs
: Keyword arguments for memory retrieval.
Returns:
Coroutine
: A coroutine that, when awaited, retrieves the requested memory.
Example:
async with client.distiller(
project="example",
uuid="test"
) as dc:
# Retrieve environment variables
retrieved_env_variables = await dc.retrieve_memory(
source="env_variable"
)
AsyncAIRefinery.distiller.reset_memory()
(asynchronous)¶
Resets memory in the WebSocket asynchronously.
Parameters:
**kwargs
: Keyword arguments indicating which memory to reset (if applied).
Returns:
Coroutine
: A coroutine that, when awaited, resets the specified memory.
Example:
async with client.distiller(
project="example",
uuid="test"
) as dc:
# Reset Memory
await dc.reset_memory()
To learn more about Distiller, visit the Distiller section in the AI Refinery documentation. For detailed examples of building complex multi-agent projects, check out the Tutorial pages.