| spec_type | module_implementation | |||||
|---|---|---|---|---|---|---|
| module_type | provider | |||||
| last_modified | 2025-01-29 | |||||
| related_contracts |
|
Providers translate between the platform's unified message format and vendor-specific LLM APIs.
The authoritative definitions live in code:
| What | Where | Key Classes |
|---|---|---|
| Provider Protocol | amplifier_core/interfaces.py |
Provider |
| Request/Response | amplifier_core/message_models.py |
ChatRequest, ChatResponse, Message |
| Content Blocks (envelope) | amplifier_core/message_models.py |
TextBlock, ThinkingBlock, ToolCallBlock, etc. |
| Content Blocks (events) | amplifier_core/content_models.py |
ContentBlock, TextContent, ThinkingContent, ToolCallContent |
| Tool Calls | amplifier_core/message_models.py |
ToolCall (used in ChatResponse.tool_calls and parse_tool_calls()) |
| Metadata Models | amplifier_core/models.py |
ProviderInfo, ModelInfo, ConfigField |
Note: message_models.py provides Pydantic models for request/response envelopes. content_models.py provides dataclass types for event emission and streaming UI.
Read the code docstrings. This spec covers implementation guidance that code cannot express.
class Provider(Protocol):
@property
def name(self) -> str: ...
def get_info(self) -> ProviderInfo: ...
async def list_models(self) -> list[ModelInfo]: ...
async def complete(self, request: ChatRequest, **kwargs) -> ChatResponse: ...
def parse_tool_calls(self, response: ChatResponse) -> list[ToolCall]: ...Providers are loaded via Python entry points. See MOUNT_PLAN_SPECIFICATION.md for how modules are configured.
async def mount(coordinator: ModuleCoordinator, config: dict) -> Provider | None:
"""
Initialize and return provider instance.
Returns None for graceful degradation (e.g., missing API key).
"""
api_key = config.get("api_key") or os.environ.get("MY_API_KEY")
if not api_key:
logger.warning("No API key - provider not mounted")
return None
provider = MyProvider(api_key=api_key, config=config, coordinator=coordinator)
await coordinator.mount("providers", provider, name="my-provider")
# Optional: Register cleanup
async def cleanup():
await provider.client.close()
return cleanup# pyproject.toml
[project.entry-points."amplifier.modules"]
my-provider = "my_provider:mount"All content block types must round-trip without loss. Key gotchas:
| Block | Preservation Requirement |
|---|---|
ThinkingBlock |
Preserve signature field (required for multi-turn) |
ReasoningBlock |
Preserve content and summary arrays |
ToolCallBlock |
Preserve id for result correlation |
Platform Role → Common Vendor Mapping
─────────────────────────────────────────
system → system / instructions parameter
developer → user (XML-wrapped for context separation)
user → user
assistant → assistant
tool → user (with tool_result blocks)
Validate that all ToolCallBlock entries have corresponding ToolResultBlock with matching tool_call_id. If missing:
- Log warning (indicates context management bug)
- Either synthesize placeholder result OR let API error
Some APIs return truncated responses. Handle transparently:
while response.status == "incomplete" and iterations < MAX:
response = await self._continue(accumulated_output)
accumulated_output.extend(response.output)providers:
- module: my-provider
source: git+https://github.com/org/my-provider@main
config:
api_key: "${MY_API_KEY}"
default_model: model-v1
debug: trueProviders declare configuration needs via get_info().config_fields:
ConfigField(
id="api_key",
field_type="secret",
env_var="MY_API_KEY",
prompt="Enter API key",
)Conditional fields: Use show_when and requires_model for model-dependent configuration.
Orchestrators emit standard provider:request/response/error events. Providers may emit additional events via contribution channels (see CONTRIBUTION_CHANNELS.md):
coordinator.register_contributor(
"observability.events",
"my-provider",
lambda: ["my-provider:rate_limit", "my-provider:retry"]
)Support via config flags:
| Flag | Events | Content |
|---|---|---|
| (default) | llm:request, llm:response |
Summary only |
debug: true |
llm:request:debug, llm:response:debug |
Truncated payloads |
debug: true, raw_debug: true |
llm:request:raw, llm:response:raw |
Complete API I/O |
- Implement
Providerprotocol (5 methods) -
mount()function with entry point in pyproject.toml - Preserve all content block types
- Report
Usage(input/output/total tokens)
- Graceful degradation on missing config (return None from mount)
- Validate tool call/result sequences
- Support debug configuration flags
- Register cleanup function
| Type | Key Fields | Notes |
|---|---|---|
text |
text |
Standard text content |
thinking |
thinking, signature |
Vendor thinking (signature critical) |
redacted_thinking |
data |
Redacted by vendor policy |
reasoning |
content, summary |
Reasoning chain (o-series style) |
tool_call |
id, name, input |
Correlate with results via id |
tool_result |
tool_call_id, output |
Must match tool_call.id |
image |
source |
Vendor-specific source format |
All blocks support visibility field and extra="allow" for vendor extensions.