Repository navigation
ExAgent v2.2.0
ExAgent 2.2.0 adds model fallback with retries, prompt caching, multimodal prompts and a final answer at the step limit, and refreshes ReqLLM to 1.28. It is additive: agents and models that do not use the new options behave as in 2.1.
Retry and fall back to another model
primary = ExAgent.Models.ReqLLM.new(primary_options ++ [foreign_history: :portable])
backup = ExAgent.Models.ReqLLM.new(backup_options ++ [foreign_history: :portable])
agent = ExAgent.new(model: ExAgent.Models.Fallback.new(models: [primary, backup]), tools: tools)- Retries HTTP 408/429/5xx/529 without output, with exponential backoff and jitter; connection failures only with
retry_transport: true. - Each attempt keeps
ModelSettings.timeout; the run deadline (newModelRequestParameters.deadline) bounds all attempts. Streams retry only before their first event. - One admitted request per model call; every retry emits
[:exagent, :model, :retry]telemetry. foreign_history: :portablesends another model's history as plain text and tool calls, so the backup can continue the conversation.
Prompt caching
ExAgent.Models.ReqLLM option prompt_cache: cache_control breakpoints on OpenRouter (true or [ttl: "5m" | "1h"]) or a stable prompt_cache_key on OpenAI ([key: key]).
Images and documents in the prompt
ExAgent.run/3 accepts a list of content parts: text, image_url, image and file (PDF). Parts are validated and stored with string keys before any request.
Finish at the step limit
ExAgent.new(on_max_steps: :final) keeps tools declared but disallows calls in the last step and asks for a final answer. The instruction stays out of history.
Dependencies
req_llm ~> 1.28.0(withllm_db 2026.10.3) anddecimal 3.2.0. Update your application lock.- A sparse OpenAI-style usage map now keeps the reported counter instead of normalizing every counter to 0.
Verification
- Offline suite: 2,305 of 2,306 passed, 28 excluded. The one failure was a test pinning the agent struct's fields, updated for
on_max_steps; that file passes 5/5. - Live OpenRouter E2E, new
featuressuite (fallback, caching, final step, PNG + PDF prompt): 4/4 with GPT-6-Luna and 4/4 with DeepSeek V4.1 Flash, including real cache hits on later turns. - GPT-6-Luna: smoke 23/23, skills 4/4, complex 4/4.
- DeepSeek V4.1 Flash: smoke 22/23, skills 2/4 and complex 3/4. These failures come from the model's output: it doesn't copy a literal JSON value, returns reasoning with reasoning disabled, or skips a skill. ReqLLM's reasoning decoding is unchanged between 1.27 and 1.28.
Full details in the changelog.