{"id":31271691,"url":"https://github.com/agentjido/req_llm","last_synced_at":"2026-05-22T22:05:49.603Z","repository":{"id":314661007,"uuid":"1051339863","full_name":"agentjido/req_llm","owner":"agentjido","description":"Req plugin to query AI providers","archived":false,"fork":false,"pushed_at":"2026-05-19T15:14:10.000Z","size":15311,"stargazers_count":521,"open_issues_count":1,"forks_count":151,"subscribers_count":6,"default_branch":"main","last_synced_at":"2026-05-19T18:43:30.210Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/agentjido.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2025-09-05T20:23:26.000Z","updated_at":"2026-05-19T15:38:01.000Z","dependencies_parsed_at":"2025-09-13T23:31:07.950Z","dependency_job_id":"7d2ba25a-be70-4f3c-9335-638d83cbcb6c","html_url":"https://github.com/agentjido/req_llm","commit_stats":null,"previous_names":["agentjido/req_llm"],"tags_count":25,"template":false,"template_full_name":null,"purl":"pkg:github/agentjido/req_llm","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agentjido%2Freq_llm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agentjido%2Freq_llm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agentjido%2Freq_llm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agentjido%2Freq_llm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/agentjido","download_url":"https://codeload.github.com/agentjido/req_llm/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agentjido%2Freq_llm/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33372739,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-22T21:56:13.512Z","status":"ssl_error","status_checked_at":"2026-05-22T21:56:10.769Z","response_time":265,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-09-23T20:01:42.176Z","updated_at":"2026-05-22T22:05:49.596Z","avatar_url":"https://github.com/agentjido.png","language":"Elixir","funding_links":[],"categories":["LLM Clients \u0026 SDKs","Elixir","Artificial Intelligence","Generative AI","LLM Clients and APIs"],"sub_categories":["How to Join","LLM Tools"],"readme":"# ReqLLM\n\n[![Hex.pm](https://img.shields.io/hexpm/v/req_llm.svg)](https://hex.pm/packages/req_llm)\n[![Hex Docs](https://img.shields.io/badge/hex-docs-lightgreen.svg)](https://hexdocs.pm/req_llm/)\n[![CI](https://github.com/agentjido/req_llm/actions/workflows/ci.yml/badge.svg)](https://github.com/agentjido/req_llm/actions/workflows/ci.yml)\n[![License](https://img.shields.io/hexpm/l/req_llm.svg)](https://github.com/agentjido/req_llm/blob/main/LICENSE)\n[![Website](https://img.shields.io/badge/website-jido.run-0f172a.svg)](https://jido.run)\n[![Ecosystem](https://img.shields.io/badge/ecosystem-jido.run-0ea5e9.svg)](https://jido.run/ecosystem)\n[![Discord](https://img.shields.io/badge/discord-join-5865F2.svg?logo=discord\u0026logoColor=white)](https://jido.run/discord)\n\n\u003e **Join the community!** Come chat about building AI tools with Elixir and coding Elixir with LLMs in [The Swarm: Elixir AI Collective](https://jido.run/discord) Discord server.\n\nA [Req](https://github.com/wojtekmach/req)-based package to call LLM APIs that standardizes the API calls and responses for LLM providers.\n\n## Why Req LLM?\n\nLLM APIs are inconsistent. ReqLLM provides a unified, idiomatic Elixir interface with standardized requests and responses across providers.\n\n**Two-layer architecture:**\n\n- **High-level API** – Vercel AI SDK-inspired functions (`generate_text/3`, `stream_text/3`, `generate_object/4` and more) that work uniformly across providers. Standard features, minimal configuration.\n- **Low-level API** – Direct Req plugin access for full HTTP control. Built around OpenAI Chat Completions baseline with provider-specific callbacks for non-compatible APIs (e.g., Anthropic).\n\n**21 Supported Providers:**\n\n| Provider | ID | Guide |\n|---|---|---|\n| [Alibaba Cloud Bailian](https://www.alibabacloud.com/help/en/model-studio) | `alibaba` | — |\n| [Alibaba Cloud Bailian (China)](https://www.alibabacloud.com/help/en/model-studio) | `alibaba_cn` | — |\n| [Anthropic](https://anthropic.com) | `anthropic` | [Guide](guides/anthropic.md) |\n| [OpenAI](https://openai.com) | `openai` | [Guide](guides/openai.md) |\n| [Google Gemini](https://ai.google.dev) | `google` | [Guide](guides/google.md) |\n| [Google Vertex AI](https://cloud.google.com/vertex-ai) | `google_vertex` | [Guide](guides/google_vertex.md) |\n| [Amazon Bedrock](https://aws.amazon.com/bedrock/) | `amazon_bedrock` | [Guide](guides/amazon_bedrock.md) |\n| [Azure OpenAI](https://azure.microsoft.com/en-us/products/ai-services/openai-service) | `azure` | [Guide](guides/azure.md) |\n| [Groq](https://groq.com) | `groq` | [Guide](guides/groq.md) |\n| [xAI](https://x.ai) | `xai` | [Guide](guides/xai.md) |\n| [OpenRouter](https://openrouter.ai) | `openrouter` | [Guide](guides/openrouter.md) |\n| [Cerebras](https://cerebras.ai) | `cerebras` | [Guide](guides/cerebras.md) |\n| [Fireworks AI](https://fireworks.ai) | `fireworks_ai` | [Guide](guides/fireworks_ai.md) |\n| [Meta Llama](https://llama.meta.com) | `meta` | [Guide](guides/meta.md) |\n| [MiniMax](https://www.minimax.io) | `minimax` | — |\n| [NEAR AI Cloud](https://cloud.near.ai) | `nearai` | [Guide](guides/nearai.md) |\n| [Z.AI](https://z.ai) | `zai` | [Guide](guides/zai.md) |\n| [Z.AI Coder](https://z.ai) | `zai_coder` | [Guide](guides/zai_coder.md) |\n| [Zenmux](https://zenmux.ai) | `zenmux` | [Guide](guides/zenmux.md) |\n| [Venice](https://venice.ai) | `venice` | — |\n| [vLLM](https://docs.vllm.ai) | `vllm` | [Ollama](guides/ollama.md) |\n\n\\* _Streaming uses Finch directly due to known Req limitations with SSE responses._\n\n## Installation\n\n### Igniter Installation (Recommended)\n\nThe fastest way to get started is with [Igniter](https://hex.pm/packages/igniter):\n\n```bash\nmix igniter.install req_llm\n```\n\n### Manual Installation\n\nAdd `req_llm` to your list of dependencies in `mix.exs`:\n\n```elixir\ndef deps do\n  [\n    {:req_llm, \"~\u003e 1.6\"}\n  ]\nend\n```\n\nThen run:\n\n```bash\nmix deps.get\n```\n\n## Quick Start\n\n```elixir\n# Keys are picked up from .env files or environment variables - see `ReqLLM.Keys`\nmodel = \"anthropic:claude-haiku-4-5\"\n\nReqLLM.generate_text!(model, \"Hello world\")\n#=\u003e \"Hello! How can I assist you today?\"\n\nschema = [name: [type: :string, required: true], age: [type: :pos_integer]]\nperson = ReqLLM.generate_object!(model, \"Generate a person\", schema)\n#=\u003e %{name: \"John Doe\", age: 30}\n\n{:ok, image_response} = ReqLLM.generate_image(\"openai:gpt-image-1\", \"A simple red square\")\nimage_bytes = ReqLLM.Response.image_data(image_response)\nFile.write!(\"red_square.png\", image_bytes)\n\nNote: Google image models gemini-2.5-flash-image and gemini-3-pro-image-preview reject :n; specify the image count in the prompt.\n\n{:ok, response} = ReqLLM.generate_text(\n  model,\n  ReqLLM.Context.new([\n    ReqLLM.Context.system(\"You are a helpful coding assistant\"),\n    ReqLLM.Context.user(\"Explain recursion in Elixir\")\n  ]),\n  temperature: 0.7,\n  max_tokens: 200\n)\n\n\n{:ok, response} = ReqLLM.generate_text(\n  model,\n  \"What's the weather in Paris?\",\n  tools: [\n    ReqLLM.tool(\n      name: \"get_weather\",\n      description: \"Get current weather for a location\",\n      parameter_schema: [\n        location: [type: :string, required: true, doc: \"City name\"]\n      ],\n      callback: {Weather, :fetch_weather, [:extra, :args]}\n    )\n  ]\n)\n\n# Streaming text generation\n{:ok, response} = ReqLLM.stream_text(model, \"Write a short story\")\nReqLLM.StreamResponse.tokens(response)\n|\u003e Stream.each(\u0026IO.write/1)\n|\u003e Stream.run()\n\n# Access usage metadata after streaming\nusage = ReqLLM.StreamResponse.usage(response)\n```\n\n## Features\n\n- **Provider-agnostic model registry**\n  - 45 providers / 665+ models sourced from [models.dev](https://models.dev) via the `llm_db` dependency\n  - Cost, context length, modality, capability and deprecation metadata included\n\n- **Canonical data model**\n  - Typed `Context`, `Message`, `ContentPart`, `Tool`, `StreamChunk`, `Response`, `Usage`\n  - Multi-modal content parts (text, image URL, tool call, binary)\n  - All structs implement `Jason.Encoder` for simple persistence / inspection\n\n- **Two client layers**\n  - Low-level Req plugin with full HTTP control (`Provider.prepare_request/4`, `attach/3`)\n  - High-level Vercel-AI style helpers (`generate_text/3`, `stream_text/3`, `generate_object/4`, bang variants)\n\n- **Structured object generation**\n  - `generate_object/4` renders JSON-compatible Elixir maps validated by a NimbleOptions-compiled schema\n  - Zero-copy mapping to provider JSON-schema / function-calling endpoints\n  - OpenAI native structured outputs with three modes (`:auto` (default), `:json_schema`, `:tool_strict`)\n\n- **Provider-specific capabilities**\n  - Anthropic web search for real-time content access (via `provider_options: [web_search: %{max_uses: 5}]`)\n  - Extended thinking/reasoning for supported models\n  - Prompt caching for cost optimization\n  - All provider-specific options documented in provider guides\n\n- **Embedding generation**\n  - Single or batch embeddings via `Embedding.generate/3` (Not all providers support this)\n  - Automatic dimension / encoding validation and usage accounting\n\n- **Production-grade streaming**\n  - `stream_text/3` returns a `StreamResponse` with both real-time tokens and async metadata\n  - Finch-based streaming with HTTP/2 multiplexing and automatic connection pooling\n  - OpenAI Responses models can opt into WebSocket mode with `provider_options: [openai_stream_transport: :websocket]`\n  - Concurrent metadata collection (usage, finish_reason) without blocking token flow\n  - Works uniformly across providers with internal SSE / chunked-response adaptation\n\n- **Experimental OpenAI realtime sessions**\n  - `ReqLLM.OpenAI.Realtime` exposes a low-level WebSocket session API for Realtime models\n  - Designed for explicit event-driven workflows that do not map cleanly to `stream_text/3`\n\n- **Usage \u0026 cost tracking**\n  - `response.usage` exposes normalized usage and best-effort USD cost from model metadata and provider response data\n\n- **Schema-driven option validation**\n  - All public APIs validate options with NimbleOptions; errors are raised as `ReqLLM.Error.Invalid.*` (Splode)\n\n- **Automatic parameter translation \u0026 codecs**\n  - Provider DSL translates canonical options (e.g. `max_tokens` -\u003e `max_completion_tokens` for o1 \u0026 o3) to provider-specific names\n  - Built-in OpenAI-style encoding/decoding with provider callback overrides for custom formats\n\n- **Flexible model specification**\n  - Accepts `\"provider:model\"`, tuples, `%LLMDB.Model{}` structs, and plain-map model specs\n  - `ReqLLM.model!/1` is the recommended way to validate and normalize full model specs\n\n- **Secure, layered key management** (`ReqLLM.Keys`)\n  - Per-request override → application config → env vars / .env files\n- **OAuth bearer auth for supported providers**\n  - Direct `access_token` support for OpenAI and Anthropic\n  - OpenAI can load and refresh `openai-codex` credentials from `oauth.json` / `auth.json`\n  - `openai_codex:*` targets the ChatGPT Codex backend with OAuth-only auth and automatic account-id extraction\n\n- **Extensive reliability tooling**\n  - Fixture-backed test matrix (`LiveFixture`) supports cached, live, or provider-filtered runs\n  - Dialyzer, Credo strict rules, and no-comment enforcement keep code quality high\n\n## API Key Management\n\nReqLLM makes key management as easy and flexible as possible - this needs to _just work_.\n\n**Please submit a PR if your key management use case is not covered**\n\nKeys are pulled from multiple sources with clear precedence: per-request override → in-memory storage → application config → environment variables → .env files.\n\n```elixir\n# Store keys in memory (recommended)\nReqLLM.put_key(:openai_api_key, \"sk-...\")\nReqLLM.put_key(:anthropic_api_key, \"sk-ant-...\")\n\n# Retrieve keys with source info\n{:ok, key, source} = ReqLLM.get_key(:openai)\n```\n\nAll functions accept an `api_key` parameter to override the stored key:\n\n```elixir\nReqLLM.generate_text(\"anthropic:claude-haiku-4-5\", \"Hello\", api_key: \"sk-ant-...\")\n{:ok, response} = ReqLLM.stream_text(\"anthropic:claude-haiku-4-5\", \"Story\", api_key: \"sk-ant-...\")\n```\n\nBy default, ReqLLM loads `.env` files from the current working directory at startup. To disable this behavior (e.g., if you manage environment variables yourself):\n\n```elixir\nconfig :req_llm, load_dotenv: false\n```\n\n## Model Specs\n\nReqLLM can call models that are not in LLMDB yet. This is the recommended advanced\nworkflow for local development, debugging new releases, and custom provider setups.\n\nSee the [Model Specs](guides/model-specs.md) guide for the full explanation of\nstring specs, exact dated releases, `%LLMDB.Model{}` structs, and the full explicit\nmodel specification path.\n\nFor backwards compatibility, you can pass a plain map directly to the major APIs.\nThe clearer path is to normalize it first with `ReqLLM.model!/1`, which returns an\nenriched `%LLMDB.Model{}`.\n\n```elixir\nmodel =\n  ReqLLM.model!(%{\n    provider: :openai,\n    id: \"gpt-6-mini\",\n    base_url: \"http://localhost:8000/v1\"\n  })\n\nReqLLM.generate_text!(model, \"Hello world\")\n```\n\nYou can still pass the plain-map model spec directly:\n\n```elixir\nReqLLM.generate_text!(\n  %{provider: :openai, id: \"gpt-6-mini\", base_url: \"http://localhost:8000/v1\"},\n  \"Hello world\"\n)\n```\n\nUse additional metadata only when the provider needs it:\n\n```elixir\nmodel =\n  ReqLLM.model!(%{\n    provider: :google_vertex,\n    id: \"zai-org/glm-4.7-maas\",\n    extra: %{family: \"glm\"}\n  })\n```\n\nReqLLM hard-fails early when the model spec is missing required routing data, with\nerrors aimed at advanced users:\n\n- Inline models always need `provider` and `id` (or `model`)\n- Azure still needs a `base_url`\n- Google Vertex MaaS models may need `extra.family` when the model family cannot be inferred\n\n## Usage Cost Tracking\n\nEvery response includes detailed usage and best-effort cost information calculated from normalized provider usage data plus model pricing metadata:\n\n```elixir\n{:ok, response} = ReqLLM.generate_text(\"anthropic:claude-haiku-4-5\", \"Hello\")\n\nresponse.usage\n#=\u003e %{\n#     input_tokens: 8,\n#     output_tokens: 12,\n#     total_tokens: 20,\n#     input_cost: 0.00024,\n#     output_cost: 0.00036,\n#     total_cost: 0.0006\n#   }\n```\n\nReqLLM treats pricing as an observability and estimation feature, not an invoice guarantee. When provider billing accuracy matters, compare these values against your own provider-side reporting. See the [Pricing Policy](guides/pricing-policy.md) guide for the full contract and known limitations.\n\n### Tool \u0026 Image Usage\n\nWhen using web search or generating images, additional usage metadata is available:\n\n```elixir\n# Web search usage (Anthropic, OpenAI, xAI, Google)\n{:ok, response} = ReqLLM.generate_text(model, prompt,\n  provider_options: [web_search: %{max_uses: 5}])\n\nresponse.usage.tool_usage\n#=\u003e %{web_search: %{count: 2, unit: \"call\"}}\n\nresponse.usage.cost\n#=\u003e %{tokens: 0.001, tools: 0.02, images: 0.0, total: 0.021}\n\n# Image generation usage\n{:ok, response} = ReqLLM.generate_image(\"openai:gpt-image-1\", prompt)\n\nresponse.usage.image_usage\n#=\u003e %{generated: %{count: 1, size_class: \"1024x1024\"}}\n```\n\nA native ReqLLM telemetry surface is published for every request, including streaming:\n\n- `[:req_llm, :request, :start | :stop | :exception]` for lifecycle timing, summaries, and usage\n- `[:req_llm, :reasoning, :start | :update | :stop]` for standardized thinking and reasoning milestones\n- `[:req_llm, :token_usage]` for backwards-compatible token and cost measurements\n\nAll events share a `request_id` so you can correlate request lifecycle, reasoning lifecycle, and billing data across providers.\n\nFor OpenTelemetry, attach `ReqLLM.OpenTelemetry` once to emit GenAI client spans, optional GenAI metrics, cost attributes, and Langfuse-friendly message capture.\n\n```elixir\nReqLLM.OpenTelemetry.attach(\"req-llm-otel\", content: :attributes, langfuse: true)\n```\n\nSee `examples/scripts/usage_cost_search_image.exs` and run it from `examples/` with `mix run scripts/usage_cost_search_image.exs` for a multi-provider smoke test that validates search tool and image generation cost metadata. For comprehensive documentation, see the [Telemetry Guide](guides/telemetry.md) and [Usage \u0026 Billing Guide](guides/usage-and-billing.md).\n\n## Streaming Configuration\n\nReqLLM uses Finch for streaming connections with automatic connection pooling. By default, we use HTTP/1-only pools to work around a known Finch bug with large request bodies:\n\n```elixir\n# Default configuration (automatic)\nconfig :req_llm,\n  finch: [\n    name: ReqLLM.Finch,\n    pools: %{\n      :default =\u003e [protocols: [:http1], size: 1, count: 8]\n    }\n  ]\n```\n\n### HTTP/2 Configuration (Advanced)\n\n**Important:** Due to [Finch issue #265](https://github.com/sneako/finch/issues/265), HTTP/2 pools may fail when sending request bodies larger than 64KB (large prompts, extensive context windows). This is a bug in Finch's HTTP/2 flow control implementation, not a limitation of HTTP/2 itself.\n\nIf you want to use HTTP/2 pools (e.g., for performance testing or if you know your prompts are small), you can configure it:\n\n```elixir\n# HTTP/2 configuration (use with caution)\nconfig :req_llm,\n  finch: [\n    name: ReqLLM.Finch,\n    pools: %{\n      :default =\u003e [protocols: [:http2, :http1], size: 1, count: 8]\n    }\n  ]\n```\n\n**ReqLLM will error with a helpful message if you try to send a large request body with HTTP/2 pools.** The error will reference this section for configuration guidance.\n\nFor high-scale deployments with small prompts, you can increase the connection count:\n\n```elixir\n# High-scale configuration\nconfig :req_llm,\n  finch: [\n    name: ReqLLM.Finch,\n    pools: %{\n      :default =\u003e [protocols: [:http1], size: 1, count: 32]  # More connections\n    }\n  ]\n```\n\nAdvanced users can specify custom Finch instances per request:\n\n```elixir\n{:ok, response} = ReqLLM.stream_text(model, messages, finch_name: MyApp.CustomFinch)\n```\n\n### StreamResponse Usage Patterns\n\nThe new `StreamResponse` provides flexible access patterns:\n\n```elixir\n# Real-time streaming for UI\n{:ok, response} = ReqLLM.stream_text(model, \"Tell me a story\")\n\nReqLLM.StreamResponse.tokens(response)\n|\u003e Stream.each(\u0026broadcast_to_liveview/1)\n|\u003e Stream.run()\n\n# Concurrent metadata collection (non-blocking)\nTask.start(fn -\u003e\n  usage = ReqLLM.StreamResponse.usage(response)\n  log_usage(usage)\nend)\n\n# Simple text collection\ntext = ReqLLM.StreamResponse.text(response)\n\n# Backward compatibility with legacy Response\n{:ok, legacy_response} = ReqLLM.StreamResponse.to_response(response)\n```\n\n## Adding a Provider\n\nReqLLM uses OpenAI Chat Completions as the baseline API standard. Providers that support this format (like Groq, OpenRouter, xAI) require minimal overrides using the `ReqLLM.Provider.DSL`. Model metadata is automatically synced from [models.dev](https://models.dev).\n\nProviders implement the `ReqLLM.Provider` behavior with functions like `encode_body/1`, `decode_response/1`, and optional parameter translation via `translate_options/3`.\n\nSee the [Adding a Provider Guide](guides/adding_a_provider.md) for detailed implementation instructions.\n\n## Lower-Level Req Plugin API\n\nFor advanced use cases, you can use ReqLLM providers directly as Req plugins. This is the canonical implementation used by `ReqLLM.generate_text/3`:\n\n```elixir\n# The canonical pattern from ReqLLM.Generation.generate_text/3\nwith {:ok, model} \u003c- ReqLLM.model(\"anthropic:claude-haiku-4-5\"), # Parse model spec\n     {:ok, provider_module} \u003c- ReqLLM.provider(model.provider),        # Get provider module\n     {:ok, request} \u003c- provider_module.prepare_request(:chat, model, \"Hello!\", temperature: 0.7), # Build Req request\n     {:ok, %Req.Response{body: response}} \u003c- Req.request(request) do   # Execute HTTP request\n  {:ok, response}\nend\n\n# Customize the Req pipeline with additional headers or middleware\n{:ok, model} = ReqLLM.model(\"anthropic:claude-haiku-4-5\")\n{:ok, provider_module} = ReqLLM.provider(model.provider)\n{:ok, request} = provider_module.prepare_request(:chat, model, \"Hello!\", temperature: 0.7)\n\n# Add custom headers or middleware before sending\ncustom_request =\n  request\n  |\u003e Req.Request.put_header(\"x-request-id\", \"my-custom-id\")\n  |\u003e Req.Request.put_header(\"x-source\", \"my-app\")\n\n{:ok, response} = Req.request(custom_request)\n```\n\nThis approach gives you full control over the Req pipeline, allowing you to add custom middleware, modify requests, or integrate with existing Req-based applications. Native ReqLLM telemetry still applies to this low-level Req path, and it is the recommended observability surface if you also need streaming coverage.\n\n## Documentation\n\n- [Getting Started](guides/getting-started.md) – first call and basic concepts\n- [Configuration](guides/configuration.md) – timeouts, connection pools, and global settings\n- [Telemetry](guides/telemetry.md) – request lifecycle, reasoning lifecycle, payload capture\n- [Core Concepts](guides/core-concepts.md) – architecture \u0026 data model\n- [Data Structures](guides/data-structures.md) – detailed type information\n- [Pricing Policy](guides/pricing-policy.md) – cost-calculation scope, guarantees, and known gaps\n- [Usage \u0026 Billing](guides/usage-and-billing.md) – token costs, tool usage, image costs\n- [Image Generation](guides/image-generation.md) – generating images with OpenAI and Google\n- [Mix Tasks](guides/mix-tasks.md) – model sync, compatibility testing, code generation\n- [Fixture Testing](guides/fixture-testing.md) – model validation and supported models\n- [Adding a Provider](guides/adding_a_provider.md) – extend with new providers\n- Provider Guides: [Anthropic](guides/anthropic.md), [OpenAI](guides/openai.md), [Google](guides/google.md), [Google Vertex](guides/google_vertex.md), [xAI](guides/xai.md), [Groq](guides/groq.md), [OpenRouter](guides/openrouter.md), [Amazon Bedrock](guides/amazon_bedrock.md), [Azure](guides/azure.md), [Cerebras](guides/cerebras.md), [Meta](guides/meta.md), [NEAR AI Cloud](guides/nearai.md), [Z.AI](guides/zai.md), [Z.AI Coder](guides/zai_coder.md), [Zenmux](guides/zenmux.md), [Ollama/vLLM](guides/ollama.md)\n\n## Roadmap \u0026 Status\n\nReqLLM has now reached v1.0.0. The core API is stable and ready for production use. We're continuing to refine the library and would love community feedback as we plan the next set of improvements. If you run into anything or have suggestions, please open an issue or PR.\n\n### Test Coverage \u0026 Quality Commitment\n\n**130+ models currently pass our comprehensive fixture-based test suite** across 10 providers. The LLM API landscape is highly dynamic. We guarantee that all supported models pass our fixture tests for basic functionality (text generation, streaming, tool calling, structured output, and embeddings where applicable).\n\nThese fixture tests are regularly refreshed against live APIs to ensure accuracy and catch provider-side changes. While we can't guarantee every edge case in production, our fixture-based approach provides a reliable baseline that you can verify with `mix mc \"*:*\"`.\n\n**We welcome bug reports and feedback!** If you encounter issues with any supported model, please open a GitHub issue with details. The more feedback we receive, the stronger the code will be!\n\n## Development\n\n```bash\n# Install dependencies\nmix deps.get\n\n# Run tests with cached fixtures\nmix test\n\n# Run quality checks\nmix quality  # format, compile, credo --strict, dialyzer\n\n# Generate documentation\nmix docs\n```\n\n### Testing with Fixtures\n\nTests use cached JSON fixtures by default. To regenerate fixtures against live APIs (optional):\n\n```bash\n# Regenerate all fixtures\nLIVE=true mix test\n\n# Regenerate specific provider fixtures using test tags\nLIVE=true mix test --only \"provider:anthropic\"\n```\n\n## Contributing\n\nWe welcome contributions! ReqLLM uses a fixture-based testing approach to ensure reliability across all providers.\n\nPlease read [CONTRIBUTING.md](CONTRIBUTING.md) for detailed guidelines on:\n\n- Core library contributions\n- Adding new providers\n- Extending provider features\n- Testing requirements and fixture generation\n- Code quality standards\n\nQuick start:\n\n1. Fork the repository\n2. Create a feature branch\n3. Add tests with fixtures for your changes\n4. Run `mix test` and `mix quality` to ensure standards\n5. Verify `mix mc \"*:*\"` passes for affected providers\n6. Submit a pull request\n\n## License\n\nCopyright 2025 Mike Hostetler\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fagentjido%2Freq_llm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fagentjido%2Freq_llm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fagentjido%2Freq_llm/lists"}