README.md

<p align="center">
  <img src="logo.png" alt="Sycophant" width="256">
</p>

<h1 align="center">Sycophant</h1>

<p align="center">You are absolutely right if you use this lib!</p>

> **Warning:** Sycophant is under active development and the API is not yet
> stable. Expect breaking changes between versions until 1.0.

Sycophant abstracts the differences between OpenAI, Anthropic, Google Gemini,
AWS Bedrock, Azure AI Foundry, and OpenRouter behind a single composable API.
Provider-specific wire protocols, authentication, and parameter validation are
handled automatically based on the model identifier.

## Features

- **Multi-provider** -- OpenAI, Anthropic, Google Gemini, AWS Bedrock, Azure, OpenRouter
- **Text generation** -- synchronous and streaming responses
- **Structured output** -- validated against Zoi schemas
- **Tool use** -- auto-execution loop or manual handling
- **Embeddings** -- unified embedding API across providers
- **Multi-turn conversations** -- extract context from a response to continue
- **Automatic cost calculation** -- token costs from LLMDB pricing data
- **Telemetry** -- `:telemetry` events with optional OpenTelemetry bridge
- **Serialization** -- JSON round-trip for all core structs (database persistence)
- **Smart credentials** -- per-request, app config, or environment variable fallback

## Quick Start

```elixir
# Generate text
messages = [Sycophant.Message.user("What is the capital of France?")]

{:ok, response} = Sycophant.generate_text("openai:gpt-4o-mini", messages)
response.text
#=> "The capital of France is Paris."
```

```elixir
# Continue the conversation
alias Sycophant.Context

ctx = response.context |> Context.add(Sycophant.Message.user("Tell me more"))
{:ok, follow_up} = Sycophant.generate_text("openai:gpt-4o-mini", ctx)
```

```elixir
# Structured output with schema validation
schema = Zoi.object(%{name: Zoi.string(), age: Zoi.integer()})
messages = [Sycophant.Message.user("Extract: John is 30 years old")]

{:ok, response} = Sycophant.generate_object("openai:gpt-4o-mini", messages, schema)
response.object
#=> %{name: "John", age: 30}
```

```elixir
# Streaming
Sycophant.generate_text("openai:gpt-4o-mini", messages,
  stream: fn chunk -> IO.write(chunk.data) end
)
```

```elixir
# Tool use with auto-execution
weather_tool = %Sycophant.Tool{
  name: "get_weather",
  description: "Gets current weather for a city",
  parameters: Zoi.object(%{city: Zoi.string()}),
  function: fn %{"city" => city} -> "72F sunny in #{city}" end
}

Sycophant.generate_text("openai:gpt-4o-mini", messages,
  tools: [weather_tool]
)
```

```elixir
# Embeddings
request = %Sycophant.EmbeddingRequest{
  inputs: ["Hello world"],
  model: "amazon_bedrock:cohere.embed-english-v3"
}
{:ok, response} = Sycophant.embed(request)
```

## Installation

Add `sycophant` to your list of dependencies in `mix.exs`:

```elixir
def deps do
  [
    {:sycophant, github: "edlontech/sycophant", branch: "main"}
  ]
end
```

## Configuration

Credentials are resolved in order: per-request options, application config,
then environment variables.

```elixir
# config/runtime.exs
config :sycophant, :providers,
  openai: [api_key: System.get_env("OPENAI_API_KEY")],
  anthropic: [api_key: System.get_env("ANTHROPIC_API_KEY")],
  google: [api_key: System.get_env("GOOGLE_API_KEY")]
```

See the [Getting Started](guides/getting-started.md) guide for detailed setup
instructions and the full [documentation](https://hexdocs.pm/sycophant) for
API reference.

## Supported Providers

| Provider | Model Prefix | Auth | Wire Protocol |
|----------|-------------|------|---------------|
| OpenAI | `openai:` | Bearer token | Chat Completions / Responses |
| Anthropic | `anthropic:` | x-api-key | Messages |
| Google Gemini | `google:` | API key | Gemini |
| AWS Bedrock | `amazon_bedrock:` | AWS SigV4 | Converse |
| Azure AI Foundry | `azure:` | Bearer / API key | OpenAI Completions |
| OpenRouter | `openrouter:` | Bearer token | OpenAI Completions |

## Acknowledgements

Sycophant builds on the shoulders of great Elixir projects:

- [LLMDB](https://github.com/agentjido/llm_db) -- the model metadata database
  that powers model resolution, provider discovery, and pricing data.
- [Req LLM](https://github.com/agentjido/req_llm) -- a major source of
  inspiration for Sycophant's API design and multi-provider approach.

## License

See [LICENSE](LICENSE) for details.