Make local LM Studio and Ollama Docker-friendly
Add shipped local-provider defaults for LM Studio and Ollama so Dockerized Agent Zero can reach host-running services without manual api_base edits. Map host.docker.internal in the sample Compose file for Linux Docker, document the behavior, and cover the provider defaults and compose mapping with focused regression tests.
Alessandro committed
Jun 15, 2026 at 04:17 UTC
c38808259b0623b527da87d623d8e4a5e695472e
4 files changed
+82
-4
conf/model_providers.yaml
+11
-1
@@ -14,7 +14,7 @@
14
#
15
# Optional fields:
16
# kwargs: A dictionary of extra parameters to pass to LiteLLM.
17
-# This is useful for `api_base`, `extra_headers`, etc.
17
+# This is useful for `api_base`, `extra_headers`, non-secret local placeholders, etc.
18
#
19
# Optional model listing fields (used by the Model Configuration plugin):
20
# models_list:
@@ -83,6 +83,9 @@ chat:
83
models_list:
84
endpoint_url: "/v1/models"
85
default_base: "http://host.docker.internal:1234"
86
+ kwargs:
87
+ api_base: "http://host.docker.internal:1234/v1"
88
+ api_key: "lm-studio"
89
mistral:
90
name: Mistral AI
91
litellm_provider: mistral
@@ -107,6 +110,8 @@ chat:
110
endpoint_url: "/api/tags"
111
format: "ollama"
112
default_base: "http://host.docker.internal:11434"
113
+ kwargs:
114
+ api_base: "http://host.docker.internal:11434"
115
ollama_cloud:
116
name: Ollama Cloud
117
litellm_provider: openai
@@ -186,12 +191,17 @@ embedding:
191
lm_studio:
192
name: LM Studio
193
litellm_provider: lm_studio
194
+ kwargs:
195
+ api_base: "http://host.docker.internal:1234/v1"
196
+ api_key: "lm-studio"
197
mistral:
198
name: Mistral AI
199
litellm_provider: mistral
200
ollama:
201
name: Ollama
202
litellm_provider: ollama
203
+ kwargs:
204
+ api_base: "http://host.docker.internal:11434"
205
openai:
206
name: OpenAI
207
litellm_provider: openai
docker/run/docker-compose.yml
+3
-1
@@ -5,4 +5,6 @@ services:
5
volumes:
6
- ./agent-zero:/a0
7
ports:
8
- - "50080:80"
\ No newline at end of file
8
+ - "50080:80"
9
+ extra_hosts:
10
+ - "host.docker.internal:host-gateway"
docs/setup/installation.md
+2
-2
@@ -527,13 +527,13 @@ Replace `<model-name>` with the name of the model you want to use. For example:
527
1. Once you've downloaded your model(s), select it in the Settings page of the GUI.
528
2. Within the Chat model, Utility model, or Embedding model section, choose **Ollama** as provider.
529
3. Write your model code as expected by Ollama, in the format `llama3.2` or `qwen2.5:7b`
530
-4. Provide your API base URL to your Ollama API endpoint, usually `http://host.docker.internal:11434`
530
+4. Agent Zero includes Docker-friendly defaults for Ollama on the host at `http://host.docker.internal:11434`. Override the API base URL only if your Ollama server runs somewhere else.
531
5. Click `Save` to confirm your settings.
532
533

534
535
> [!NOTE]
536
-> If Agent Zero runs in Docker and Ollama runs on the host, ensure port **11434** is reachable from the container. If both services are in the same Docker network, you can use `http://<container_name>:11434` instead of `host.docker.internal`.
536
+> If Agent Zero runs in Docker and Ollama runs on the host, ensure port **11434** is reachable from the container. The shipped Docker Compose file maps `host.docker.internal` to the host gateway for Linux Docker. If both services are in the same Docker network, you can use `http://<container_name>:11434` instead of `host.docker.internal`.
537
538
### Managing Downloaded Models
539
tests/test_model_config_api_keys.py
+66
@@ -276,3 +276,69 @@ def test_provider_key_modes_for_local_and_ollama_cloud():
276
assert model_config.provider_requires_api_key("lm_studio") is False
277
assert model_config.provider_requires_api_key("other") is False
278
assert model_config.provider_requires_api_key("ollama_cloud") is True
279
+
280
+
281
+def test_local_provider_defaults_are_docker_friendly():
282
+ import yaml
283
+
284
+ provider_path = PROJECT_ROOT / "conf" / "model_providers.yaml"
285
+ provider_config = yaml.safe_load(provider_path.read_text(encoding="utf-8"))
286
+
287
+ assert provider_config["chat"]["lm_studio"]["kwargs"]["api_base"] == (
288
+ "http://host.docker.internal:1234/v1"
289
+ )
290
+ assert provider_config["chat"]["lm_studio"]["kwargs"]["api_key"] == "lm-studio"
291
+ assert provider_config["chat"]["lm_studio"]["models_list"]["default_base"] == (
292
+ "http://host.docker.internal:1234"
293
+ )
294
+ assert provider_config["chat"]["ollama"]["kwargs"]["api_base"] == (
295
+ "http://host.docker.internal:11434"
296
+ )
297
+ assert provider_config["chat"]["ollama"]["models_list"]["default_base"] == (
298
+ "http://host.docker.internal:11434"
299
+ )
300
+ assert provider_config["embedding"]["lm_studio"]["kwargs"]["api_base"] == (
301
+ "http://host.docker.internal:1234/v1"
302
+ )
303
+ assert provider_config["embedding"]["lm_studio"]["kwargs"]["api_key"] == "lm-studio"
304
+ assert provider_config["embedding"]["ollama"]["kwargs"]["api_base"] == (
305
+ "http://host.docker.internal:11434"
306
+ )
307
+
308
+
309
+def test_local_provider_runtime_defaults_and_overrides(monkeypatch):
310
+ monkeypatch.setattr(models, "get_api_key", lambda provider: "None")
311
+
312
+ lm_chat = models.get_chat_model("lm_studio", "local-chat-model")
313
+ assert lm_chat.model_name == "lm_studio/local-chat-model"
314
+ assert lm_chat.kwargs["api_base"] == "http://host.docker.internal:1234/v1"
315
+ assert lm_chat.kwargs["api_key"] == "lm-studio"
316
+
317
+ lm_embedding = models.get_embedding_model("lm_studio", "nomic-embed-text")
318
+ assert lm_embedding.model_name == "lm_studio/nomic-embed-text"
319
+ assert lm_embedding.kwargs["api_base"] == "http://host.docker.internal:1234/v1"
320
+ assert lm_embedding.kwargs["api_key"] == "lm-studio"
321
+
322
+ custom_lm_embedding = models.get_embedding_model(
323
+ "lm_studio",
324
+ "nomic-embed-text",
325
+ api_base="http://127.0.0.1:1234/v1",
326
+ api_key="real-local-key",
327
+ )
328
+ assert custom_lm_embedding.kwargs["api_base"] == "http://127.0.0.1:1234/v1"
329
+ assert custom_lm_embedding.kwargs["api_key"] == "real-local-key"
330
+
331
+ ollama_embedding = models.get_embedding_model("ollama", "nomic-embed-text")
332
+ assert ollama_embedding.model_name == "ollama/nomic-embed-text"
333
+ assert ollama_embedding.kwargs["api_base"] == "http://host.docker.internal:11434"
334
+ assert "api_key" not in ollama_embedding.kwargs
335
+
336
+
337
+def test_docker_compose_maps_host_docker_internal_for_local_models():
338
+ import yaml
339
+
340
+ compose_path = PROJECT_ROOT / "docker" / "run" / "docker-compose.yml"
341
+ compose = yaml.safe_load(compose_path.read_text(encoding="utf-8"))
342
+ service = compose["services"]["agent-zero"]
343
+
344
+ assert "host.docker.internal:host-gateway" in service["extra_hosts"]