Current section
Files
Jump to
Current section
Files
lib/altar/ai.ex
defmodule Altar.AI do
@moduledoc """
Unified AI adapter foundation for Elixir.
Provides protocol-based abstractions for AI operations with adapters
for gemini_ex, claude_agent_sdk, and codex_sdk.
## Quick Start
# Create an adapter
adapter = Altar.AI.Adapters.Gemini.new()
# Or use composite for fallback
adapter = Altar.AI.Adapters.Composite.default()
# Generate text
{:ok, response} = Altar.AI.generate(adapter, "Hello, world!")
# Check capabilities
Altar.AI.capabilities(adapter)
#=> %{generate: true, embed: true, classify: false, ...}
## Architecture
Altar.AI uses **protocols** instead of behaviours for maximum flexibility:
- `Altar.AI.Generator` - Text generation and streaming
- `Altar.AI.Embedder` - Vector embeddings
- `Altar.AI.Classifier` - Text classification
- `Altar.AI.CodeGenerator` - Code generation and explanation
This allows:
- Runtime capability detection
- Cleaner composite adapter implementation
- Dispatching on adapter structs
## Adapters
Available adapters (when SDKs are installed):
- `Altar.AI.Adapters.Gemini` - Google Gemini (gemini_ex)
- `Altar.AI.Adapters.Claude` - Anthropic Claude (claude_agent_sdk)
- `Altar.AI.Adapters.Codex` - OpenAI (codex_sdk)
- `Altar.AI.Adapters.Composite` - Fallback chain
- `Altar.AI.Adapters.Mock` - Testing
- `Altar.AI.Adapters.Fallback` - Heuristic fallback
## Examples
# Use a specific adapter
gemini = Altar.AI.Adapters.Gemini.new(api_key: "...")
{:ok, response} = Altar.AI.generate(gemini, "Explain protocols")
# Use composite with automatic fallback
composite = Altar.AI.Adapters.Composite.default()
{:ok, response} = Altar.AI.generate(composite, "Hello")
# Check what an adapter can do
Altar.AI.supports?(gemini, :embed) #=> true
Altar.AI.supports?(gemini, :classify) #=> false
# Get embeddings
{:ok, vector} = Altar.AI.embed(gemini, "semantic search")
# Classification (with fallback adapter)
fallback = Altar.AI.Adapters.Fallback.new()
{:ok, classification} = Altar.AI.classify(fallback, "Great!", ["positive", "negative"])
"""
alias Altar.AI.{Generator, Embedder, Classifier, CodeGenerator, Capabilities}
# Delegate to protocols
defdelegate generate(adapter, prompt, opts \\ []), to: Generator
defdelegate stream(adapter, prompt, opts \\ []), to: Generator
defdelegate embed(adapter, text, opts \\ []), to: Embedder
defdelegate batch_embed(adapter, texts, opts \\ []), to: Embedder
defdelegate classify(adapter, text, labels, opts \\ []), to: Classifier
defdelegate generate_code(adapter, prompt, opts \\ []), to: CodeGenerator
defdelegate explain_code(adapter, code, opts \\ []), to: CodeGenerator
# Capability detection
defdelegate capabilities(adapter), to: Capabilities
defdelegate supports?(adapter, capability), to: Capabilities
@doc """
Get default adapter based on available SDKs.
Returns a Composite adapter with automatic fallback chain.
## Examples
iex> adapter = Altar.AI.default_adapter()
iex> Altar.AI.capabilities(adapter)
"""
def default_adapter do
Altar.AI.Adapters.Composite.default()
end
@doc """
List all available adapters (SDKs that are installed).
## Examples
iex> Altar.AI.available_adapters()
[Altar.AI.Adapters.Gemini, Altar.AI.Adapters.Fallback]
"""
def available_adapters do
[
Altar.AI.Adapters.Gemini,
Altar.AI.Adapters.Claude,
Altar.AI.Adapters.Codex,
Altar.AI.Adapters.Fallback,
Altar.AI.Adapters.Mock
]
|> Enum.filter(& &1.available?())
end
end