OpenHands
OpenHands is an open-source autonomous software agent. It reaches models through LiteLLM, so any OpenAI-compatible endpoint works once the model name carries the right prefix.
Verified against the OpenHands CLI 1.16.0. The config below is re-run against that release every week, including a tool call round trip. Upstream has stopped maintaining the standalone CLI; it still runs, and it is the only OpenHands entry point with a headless mode. The OpenHands web app takes the same three values (see Web app below).
Install
The CLI needs Python 3.12 or later:
uv tool install openhands==1.16.0 --python 3.12Configure
Three environment variables describe the model:
export LLM_MODEL=openai/auto/mistralai/mistral-large-2512
export LLM_BASE_URL=https://api.lowrouter.ai/v1
export LLM_API_KEY=sk-lr-...The CLI ignores them unless you pass --override-with-envs. Without
the flag it reads the model from its saved settings in
~/.openhands/, and the variables have no effect. The override is
not written back to those settings.
openhands --headless --override-with-envs -t "Summarise what this repository does"--headless runs without the terminal UI and approves every action
the agent takes, shell commands included. Run it in a directory, or a
container, where that is acceptable. Drop --headless for the
interactive UI.
Two details in the variables are easy to get wrong:
LLM_MODELstarts withopenai/. That prefix tells LiteLLM to use its OpenAI-compatible client; LiteLLM strips it, and LowRouter receivesauto/mistralai/mistral-large-2512unchanged. Without the prefix LiteLLM does not recognise the provider and no request is sent.LLM_BASE_URLends in/v1. LiteLLM appends only/chat/completions, so the bare origin gives a404.
Neither mistake shows up in the exit code. Headless mode exits 0
and prints its own system prompt as the “last message sent by the
agent” when the model call failed. If the summary shows a system
prompt, check the two variables above.
Picking a model
OpenHands works through function calling for every step: reading files, editing them, running commands. Pick a model with the function-calling tag. The model browser filtered to them lists every one.
Tasks run for many turns and resend the whole conversation on each
one, so input tokens dominate the bill. The example uses
auto/mistralai/mistral-large-2512, served from the EU. Models we
have run through OpenHands’ tool loop:
auto/qwen/qwen3-coder-30b-a3b-instruct, a coding model served from the EU (128k context).auto/anthropic/claude-haiku-4.5, a cheaper Anthropic model (200k context).
OpenHands sends model IDs containing gpt-5 or gpt-6 to the
Responses API (/v1/responses) instead of Chat Completions.
LowRouter serves both, so those models work without extra settings.
Cost tracking
OpenHands’ Conversation Metrics shows a per-conversation cost. On
LowRouter the number comes from the response itself, so auto/… and
alias/… models report it like any other:
- Non-streaming calls carry an
x-litellm-response-costresponse header — the figure OpenHands’ metrics read. It is in USD and informational; your invoice is in your billing currency, and thex-lowrouter-response-cost+x-lowrouter-response-cost-currencyheaders carry that billed figure. - Streaming calls cannot carry a late-computed header, so their cost
rides the final chunk’s
usage.costfield, which LiteLLM forwards. - Tracing setups read the same figures as OpenTelemetry span
attributes (
gen_ai.usage.costin USD — but only when a stored EUR/USD rate exists —lowrouter.cost.amount+lowrouter.cost.currencyin the billing currency).
Web app
The OpenHands web app sets the same values in its LLM settings under
Advanced: custom model openai/auto/mistralai/mistral-large-2512,
base URL https://api.lowrouter.ai/v1, and your API key. The web
app has no headless mode, so this path is documented but not re-run
by the weekly check.
Recommended setup
- Use a dedicated key. An autonomous agent left running overnight can spend a lot, and a key of its own keeps that spend attributable and revocable without touching anything else.
- Cap the run. OpenHands stops a conversation after
max_iterationssteps, 500 by default; lower it in the saved settings for unattended tasks. - Keep it in a container or a throwaway checkout when using
--headless, which approves every command.
Troubleshooting
- The summary shows the system prompt, and nothing happened:
LLM_MODELis missing theopenai/prefix, orLLM_BASE_URLis missing/v1. - The CLI uses a different model from the one you exported:
--override-with-envsis missing, so the saved settings won. - Tool calls fail or the agent loops without acting: check that the model supports function calling on its page in the model browser.
