Skip to content

The assistant

The location editor can look a place up on the web and suggest a category, tags, notes, an address, links and coordinates. Every suggestion is accepted or rejected per field, anything that would replace existing text is marked as such, and nothing is written until you press Save.

It is off unless you configure it. When it is off the endpoint is not usable and the control does not render. It needs a model endpoint and usually an API key — infrastructure not everyone has, and which can cost money — so it is opt-in rather than something to switch off.

Environment variables only, never the database

An API key in the database is an API key in every backup and every dump you share while debugging. That is also why there is no admin screen for these: the instance owner sets them where secrets already live.

Turning it on

Variable Purpose
CARAVEL_LLM_URL An OpenAI-compatible endpoint. Either the base URL the provider documents (https://openrouter.ai/api/v1) or the full /chat/completions path. The value stub selects a built-in fake, used by the test suite
CARAVEL_LLM_KEY Bearer token. Omit for a local Ollama or llama.cpp that needs none
CARAVEL_LLM_MODEL Model name. Required whenever CARAVEL_LLM_URL is set

Setting one of the URL/model pair without the other is refused at startup rather than at first use, so a half-configured instance fails immediately instead of when somebody presses the button.

Optional but strongly recommended: without it the assistant has only what the model already knows and the pages it can name itself. Set CARAVEL_SEARCH_PROVIDER and its key or URL — Web search compares the providers and how to set each one up. The same setting also powers the image picker's web search, so it does not need the assistant to be on.

Coordinates are never taken from the model

The model proposes a name and an address, and the position is looked up separately. A plausible latitude and longitude 40km from the real hotel looks entirely correct in the form and is wrong only on the map — the one error with no visible tell.

Two things are asked, when both are available:

  • CARAVEL_GEOCODER_URL, the address search, is asked for the place name first and the postal address only if that finds nothing. The order matters: a postal address is a question about a delivery point, and Nominatim answers it with a house-number node, an interpolated point along the street, or the street itself — a pin outside the door rather than on it. Searching the name finds the element somebody actually mapped. The address still earns its place as the fallback: it is what positions a rented flat with no findable name. It is also the check on the name: when both are given, a name match more than 10 km from where the address resolves is not used, because a name without its town is often shared by a place elsewhere. The pin then falls back to the address, in the right town if not at the door.
  • A places search, when the search provider is serper or brave. Serper's is Google Maps data, and it is far better than OpenStreetMap on the restaurants, cafés, bars, shops and hotels a trip is mostly made of — for those, its pin is the business's own position rather than an address interpolation. Brave's agrees with it to the metre for most places, and is given the postal address as the area to search in, which makes a name with no town in it more likely to be found near the address than at the best-known place of that name. Either costs one paid request per lookup, and up to six for one trip-level suggestion run. With ollama, ddgs or none, only the geocoder is asked and everything still works.

Where the two agree, a precise OpenStreetMap match wins, because it is the only one of the two that carries an OSM element identity — which is what makes the "view on OpenStreetMap" link on a location possible. Where OpenStreetMap only found a street, the places search wins.

Where they disagree by more than 150 metres, neither is trusted. Both are offered and nothing is preselected, the row is skipped by Accept all, and on the trip-level suggestions screen the place is added with its address and no pin for you to set on the map. Picking between two places kilometres apart is not a decision to make on somebody's behalf.

The proposed position always shows the name of the place that was matched rather than only its coordinates, plus which service found it, and says so when the match is street-level. Six decimal places is not something anybody can check; a name is.

Limits

Every guard rail is settable, because these are the numbers worth changing quickly when a model turns out chattier or a bill turns out larger. The defaults are tuned against a real model and a real search backend.

Variable Default Bounds
CARAVEL_ASSIST_MAX_TOKENS 120000 Tokens one run may spend
CARAVEL_ASSIST_ANSWER_RESERVE 20000 Held back from the above, so there is always enough left to write the answer
CARAVEL_ASSIST_MAX_TURNS 12 Conversation turns
CARAVEL_ASSIST_MAX_TOOL_CALLS 20 Searches and page reads
CARAVEL_ASSIST_TIMEOUT 90s Time spent researching
CARAVEL_ASSIST_ANSWER_TIMEOUT 2m Time to compose the answer, outside the above
CARAVEL_ASSIST_RATE_LIMIT 6 Runs per minute, per client address
CARAVEL_ASSIST_MAX_CONCURRENT 4 Runs in flight at once, across the instance

Three things worth knowing.

The token budget counts billed tokens rather than context size: every turn resends the whole conversation, so a long run costs more than the numbers suggest.

The first six bound one run. The last two are what bound an instance, so the worst case is roughly them multiplied together. Of those two, CARAVEL_ASSIST_MAX_CONCURRENT is the one that actually caps a bill: CARAVEL_ASSIST_RATE_LIMIT is per client address, so ten people on ten addresses get ten allowances, not one shared between them.

Hitting a limit does not throw the run away: research stops and the assistant answers with what it found.

The effective values are printed at startup when the assistant is enabled, so the log is the place to confirm a change took.