-
Notifications
You must be signed in to change notification settings - Fork 1
Development Guide
How to extend Amadeus: adding LLM providers, tools, writing tests, and coding standards.
Create src/infra/llm/<name>_adapter.py and inherit from src.core.interfaces.llm.LLMAdapter:
from src.core.interfaces.llm import LLMAdapter
class MyAdapter(LLMAdapter):
def __init__(self, api_key: str) -> None:
self.api_key = api_key
async def is_available(self) -> bool:
# Return True if the provider can accept requests right now
return bool(self.api_key)
async def generate_response(
self,
prompt: str,
context: list[dict],
temperature: float = 0.7,
max_tokens: int = 1024,
) -> str:
# Call provider API and return the response string
...In src/container.py → _build_llm_router():
my_adapter = MyAdapter(api_key=settings.MY_API_KEY)
return LLMRouter(..., my_adapter=my_adapter)In LLMRouter:
DAILY_LIMITS = {
...,
"my_provider": 5000,
}
COST_PER_REQUEST = {
...,
"my_provider": 0.0001,
}Create tests/unit/test_<name>_adapter.py with mocked HTTP calls.
Tools live in src/infra/tools/. Use the @tool decorator:
from src.infra.tools.base import tool, ToolCategory
@tool(
name="my_tool",
description="Does something useful. Trigger: 'do X', 'run Y'",
category=ToolCategory.INFORMATION,
parameters={
"query": {"type": "string", "description": "The thing to process"},
},
requires_confirmation=False, # Set True for destructive operations
)
async def my_tool(query: str) -> str:
return f"Processed: {query}"In AmadeusService._register_all_tools():
from src.infra.tools.my_tools import get_my_tools
for tool in get_my_tools():
self.tool_registry.register(tool)The SemanticToolRouter picks it up automatically on the next startup — no retraining needed.
Tip: Write a compelling
descriptionwith example trigger phrases. The semantic router uses this text to embed the tool, so richer descriptions lead to better routing accuracy.
uv run pytest tests/unit/ -vuv run pytest tests/ --cov=src --cov-report=term-missingCoverage gate: 80% — enforced in CI and via pyproject.toml:
[tool.pytest.ini_options]
addopts = "--cov=src --cov-fail-under=80"uv run pytest tests/ -m integrationuv run pytest tests/ -m "not slow"locust -f locustfile.py --host http://localhost:8000| Tool | Purpose | Command |
|---|---|---|
ruff |
Lint + format (100 char line length) | uv run ruff check src/ tests/ |
mypy |
Strict type checking | uv run mypy src/ |
bandit |
Security scan (0 HIGH gate) | uv run bandit -r src/ -ll |
pip-audit |
CVE dependency audit | uv run pip-audit |
-
Type hints everywhere —
disallow_untyped_defs = trueinmypyconfig. - Use domain exceptions from
src.core.exceptions— never raiseLLMRateLimitErrorfor non-rate-limit errors. -
No bare
except Exception: pass— always log at minimumlogger.warning(...). - Use lazy
%slogging:logger.info("Processing %s", value)not f-strings in log calls. - Docstrings on all public classes and methods.
- Follow Conventional Commits:
feat(llm):,fix(tools):,docs:,test:, etc.
pre-commit installRuns ruff, mypy, and GitGuardian secret scanning on every commit.
| Script | Purpose |
|---|---|
scripts/index_workspace.py |
Build / update the hybrid workspace search index |
scripts/calibrate_semantic_threshold.py |
Find the optimal routing threshold for your tool set |
scripts/initialize_amadeus_identity.py |
Seed identity memories into Qdrant |
scripts/verify_identity_storage.py |
Verify identity memories are correctly stored |
scripts/build_backend_binary.py |
Build a Windows executable via PyInstaller |
scripts/install_windows_service.ps1 |
Install Amadeus as a Windows NSSM service |
← Deployment | Observability →
Amadeus-AI · v6.0.0· Apache License 2.0 · Report a Bug
Getting Started
Architecture
Reference
Integrations
Operations
Development
Project
Links