modified
.tickets/issues/0210-acp-create-mode-mm-acp-create-mm-init-from-an-acp.yaml +2 -2 | @@ -175,6 +175,8 @@ tasks: | ||
| 175 | 175 | name: k33g |
| 176 | 176 | email: ph.charriere@gmail.com |
| 177 | 177 | createdAt: 2026-11-14T05:41:20.000Z |
| 178 | + updatedAt: 2026-11-14T05:56:48.000Z | |
| 179 | + closedAt: 2026-11-14T05:56:48.000Z | |
| 178 | 180 | comments: |
| 179 | 181 | - id: 1 |
| 180 | 182 | author: |
| @@ -194,8 +196,6 @@ comments: | ||
| 194 | 196 | client by hand), the acceptance "tried in two real clients", |
| 195 | 197 | permission buttons for choices in conversation mode, and session |
| 196 | 198 | config options. qlty not run (not installed in this sandbox). |
| 197 | - updatedAt: 2026-11-14T05:56:48.000Z | |
| 198 | - closedAt: 2026-11-14T05:56:48.000Z | |
| 199 | 199 | - id: 2 |
| 200 | 200 | author: |
| 201 | 201 | name: k33g |
| @@ -175,6 +175,8 @@ tasks: | |||
| 175 | name: k33g | 175 | name: k33g |
| 176 | email: ph.charriere@gmail.com | 176 | email: ph.charriere@gmail.com |
| 177 | createdAt: 2026-11-14T05:41:20.000Z | 177 | createdAt: 2026-11-14T05:41:20.000Z |
| 178 | + updatedAt: 2026-11-14T05:56:48.000Z | ||
| 179 | + closedAt: 2026-11-14T05:56:48.000Z | ||
| 178 | comments: | 180 | comments: |
| 179 | - id: 1 | 181 | - id: 1 |
| 180 | author: | 182 | author: |
| @@ -194,8 +196,6 @@ comments: | |||
| 194 | client by hand), the acceptance "tried in two real clients", | 196 | client by hand), the acceptance "tried in two real clients", |
| 195 | permission buttons for choices in conversation mode, and session | 197 | permission buttons for choices in conversation mode, and session |
| 196 | config options. qlty not run (not installed in this sandbox). | 198 | config options. qlty not run (not installed in this sandbox). |
| 197 | - updatedAt: 2026-11-14T05:56:48.000Z | ||
| 198 | - closedAt: 2026-11-14T05:56:48.000Z | ||
| 199 | - id: 2 | 199 | - id: 2 |
| 200 | author: | 200 | author: |
| 201 | name: k33g | 201 | name: k33g |
modified
.tickets/issues/0211-check-if-llamacpp-1-0-0-is-working.yaml +2 -2 | @@ -6,9 +6,9 @@ author: | ||
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-11-14T05:56:02.153Z |
| 9 | -updatedAt: 2026-11-14T06:35:10.000Z | |
| 9 | +updatedAt: 2026-11-14T18:45:26.000Z | |
| 10 | 10 | labels: [] |
| 11 | -milestone: v1.1.0 | |
| 11 | +milestone: v2.0.0 | |
| 12 | 12 | epic: Providers (LLM Engine) |
| 13 | 13 | body: "" |
| 14 | 14 | tasks: [] |
| @@ -6,9 +6,9 @@ author: | |||
| 6 | name: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-11-14T05:56:02.153Z | 8 | createdAt: 2026-11-14T05:56:02.153Z |
| 9 | -updatedAt: 2026-11-14T06:35:10.000Z | 9 | +updatedAt: 2026-11-14T18:45:26.000Z |
| 10 | labels: [] | 10 | labels: [] |
| 11 | -milestone: v1.1.0 | 11 | +milestone: v2.0.0 |
| 12 | epic: Providers (LLM Engine) | 12 | epic: Providers (LLM Engine) |
| 13 | body: "" | 13 | body: "" |
| 14 | tasks: [] | 14 | tasks: [] |
modified
.tickets/issues/0212-mm-dockerinit-know-the-mm-folder-project-layout.yaml +2 -2 | @@ -137,6 +137,8 @@ tasks: | ||
| 137 | 137 | name: k33g |
| 138 | 138 | email: ph.charriere@gmail.com |
| 139 | 139 | createdAt: 2026-11-14T06:29:41.000Z |
| 140 | + updatedAt: 2026-11-14T06:37:57.000Z | |
| 141 | + closedAt: 2026-11-14T06:37:57.000Z | |
| 140 | 142 | comments: |
| 141 | 143 | - id: 1 |
| 142 | 144 | author: |
| @@ -159,8 +161,6 @@ comments: | ||
| 159 | 161 | Also asked in the same session: `mm sbxinit` now prints |
| 160 | 162 | `Run the sandbox <name>: sbx env run --force` (and the line in the |
| 161 | 163 | sbxenv.yaml comments). |
| 162 | - updatedAt: 2026-11-14T06:37:57.000Z | |
| 163 | - closedAt: 2026-11-14T06:37:57.000Z | |
| 164 | 164 | - id: 2 |
| 165 | 165 | author: |
| 166 | 166 | name: k33g |
| @@ -137,6 +137,8 @@ tasks: | |||
| 137 | name: k33g | 137 | name: k33g |
| 138 | email: ph.charriere@gmail.com | 138 | email: ph.charriere@gmail.com |
| 139 | createdAt: 2026-11-14T06:29:41.000Z | 139 | createdAt: 2026-11-14T06:29:41.000Z |
| 140 | + updatedAt: 2026-11-14T06:37:57.000Z | ||
| 141 | + closedAt: 2026-11-14T06:37:57.000Z | ||
| 140 | comments: | 142 | comments: |
| 141 | - id: 1 | 143 | - id: 1 |
| 142 | author: | 144 | author: |
| @@ -159,8 +161,6 @@ comments: | |||
| 159 | Also asked in the same session: `mm sbxinit` now prints | 161 | Also asked in the same session: `mm sbxinit` now prints |
| 160 | `Run the sandbox <name>: sbx env run --force` (and the line in the | 162 | `Run the sandbox <name>: sbx env run --force` (and the line in the |
| 161 | sbxenv.yaml comments). | 163 | sbxenv.yaml comments). |
| 162 | - updatedAt: 2026-11-14T06:37:57.000Z | ||
| 163 | - closedAt: 2026-11-14T06:37:57.000Z | ||
| 164 | - id: 2 | 164 | - id: 2 |
| 165 | author: | 165 | author: |
| 166 | name: k33g | 166 | name: k33g |
modified
.tickets/issues/0214-mm-acp-create-start-ollama-models-are-listed-fro.yaml +63 -7 | @@ -1,12 +1,12 @@ | ||
| 1 | 1 | # Managed by IssueSpec. Hand edits are welcome; keep the schema valid. |
| 2 | 2 | id: 214 |
| 3 | 3 | title: "mm acp-create (/start): Ollama models are listed from the container address instead of the local one" |
| 4 | -state: open | |
| 4 | +state: closed | |
| 5 | 5 | author: |
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-11-14T07:40:50.000Z |
| 9 | -updatedAt: 2026-11-14T07:47:59.000Z | |
| 9 | +updatedAt: 2026-11-14T18:14:17.000Z | |
| 10 | 10 | labels: |
| 11 | 11 | - bug |
| 12 | 12 | - kind::bug |
| @@ -76,44 +76,54 @@ body: | | ||
| 76 | 76 | tasks: |
| 77 | 77 | - id: 1 |
| 78 | 78 | title: Reproduce - mm acp-create from Zed and mm init in a terminal, Ollama on the host, note the address used |
| 79 | - state: open | |
| 79 | + state: closed | |
| 80 | 80 | priority: high |
| 81 | 81 | author: |
| 82 | 82 | name: k33g |
| 83 | 83 | email: ph.charriere@gmail.com |
| 84 | 84 | createdAt: 2026-11-14T07:40:50.000Z |
| 85 | + updatedAt: 2026-11-14T18:14:17.000Z | |
| 86 | + closedAt: 2026-11-14T18:14:17.000Z | |
| 85 | 87 | - id: 2 |
| 86 | 88 | title: Find why the local address is not taken (probe timeout, localhost vs 127.0.0.1 / IPv6, environment of the editor's process) |
| 87 | - state: open | |
| 89 | + state: closed | |
| 88 | 90 | priority: high |
| 89 | 91 | author: |
| 90 | 92 | name: k33g |
| 91 | 93 | email: ph.charriere@gmail.com |
| 92 | 94 | createdAt: 2026-11-14T07:40:50.000Z |
| 95 | + updatedAt: 2026-11-14T18:14:17.000Z | |
| 96 | + closedAt: 2026-11-14T18:14:17.000Z | |
| 93 | 97 | - id: 3 |
| 94 | 98 | title: Fix - the wizard lists the models from the local address when mm is not in a container |
| 95 | - state: open | |
| 99 | + state: closed | |
| 96 | 100 | priority: high |
| 97 | 101 | author: |
| 98 | 102 | name: k33g |
| 99 | 103 | email: ph.charriere@gmail.com |
| 100 | 104 | createdAt: 2026-11-14T07:40:50.000Z |
| 105 | + updatedAt: 2026-11-14T17:54:42.000Z | |
| 106 | + closedAt: 2026-11-14T17:54:42.000Z | |
| 101 | 107 | - id: 4 |
| 102 | 108 | title: Show the address the models were listed from in the model question (both modes) |
| 103 | - state: open | |
| 109 | + state: closed | |
| 104 | 110 | priority: medium |
| 105 | 111 | author: |
| 106 | 112 | name: k33g |
| 107 | 113 | email: ph.charriere@gmail.com |
| 108 | 114 | createdAt: 2026-11-14T07:40:50.000Z |
| 115 | + updatedAt: 2026-11-14T17:54:42.000Z | |
| 116 | + closedAt: 2026-11-14T17:54:42.000Z | |
| 109 | 117 | - id: 5 |
| 110 | 118 | title: Tests - a local server answering slowly or only on 127.0.0.1 keeps the local address |
| 111 | - state: open | |
| 119 | + state: closed | |
| 112 | 120 | priority: medium |
| 113 | 121 | author: |
| 114 | 122 | name: k33g |
| 115 | 123 | email: ph.charriere@gmail.com |
| 116 | 124 | createdAt: 2026-11-14T07:40:50.000Z |
| 125 | + updatedAt: 2026-11-14T17:54:42.000Z | |
| 126 | + closedAt: 2026-11-14T17:54:42.000Z | |
| 117 | 127 | comments: |
| 118 | 128 | - id: 1 |
| 119 | 129 | author: |
| @@ -128,3 +138,49 @@ comments: | ||
| 128 | 138 | it: look at what is specific to Ollama — its `/v1/models` answering |
| 129 | 139 | later than 2 s or not 200, Ollama listening on IPv4 only while DMR |
| 130 | 140 | answers on both, or `OLLAMA_HOST` on the user's machine. |
| 141 | + - id: 2 | |
| 142 | + author: | |
| 143 | + name: k33g | |
| 144 | + email: ph.charriere@gmail.com | |
| 145 | + createdAt: 2026-11-14T17:54:42.000Z | |
| 146 | + body: | | |
| 147 | + Fixed on `fix/wizard-local-address` (uncommitted), without waiting for | |
| 148 | + the exact cause on the user's machine: the fix covers hypotheses 1 | |
| 149 | + (slow probe), 2 (IPv4 only) and 4 (Docker Desktop resolving | |
| 150 | + host.docker.internal on the host, which hid the failed probe). | |
| 151 | + | |
| 152 | + - The wizard (mm init and mm acp-create) no longer takes the engine's | |
| 153 | + resolution (2 s probe of `/models`, then a silent switch to the | |
| 154 | + container fallback). `resolveBase` → `AGENT_BASE_URL` (or the | |
| 155 | + legacy variable) when set; else the first local address whose model | |
| 156 | + list answers (the provider's own list endpoint, `/api/tags` for | |
| 157 | + Ollama, 5 s): the default, then the same with `127.0.0.1` when it | |
| 158 | + names `localhost`; the fallback only when none answers; a provider | |
| 159 | + without a fallback is not probed. `engine.EnvBaseURL` added. | |
| 160 | + - The model question names the address: `Model? (listed from …)`. | |
| 161 | + - The written file is unchanged (no `baseUrl` for the default). | |
| 162 | + - Runtime (`mm acp` with the written file) still uses the engine's | |
| 163 | + resolution — not touched here. | |
| 164 | + | |
| 165 | + Tests: `TestChooseBasePrefersALocalAddress`, `TestLocalAddresses`, | |
| 166 | + `TestResolveBaseKeepsASlowLocalServer` (a server whose `/v1/models` | |
| 167 | + takes 3 s: the engine's probe takes the fallback, the wizard keeps the | |
| 168 | + local address), `TestResolveBaseHonoursAgentBaseURL`. | |
| 169 | + | |
| 170 | + End to end, real binary, `mm acp-create --provider ollama`, a fake | |
| 171 | + Ollama on 127.0.0.1:11434 whose `/v1/models` takes 3 s: before → | |
| 172 | + `Model ID? (no list from http://host.docker.internal:11434/v1 …)`; | |
| 173 | + after → `Model? (listed from http://localhost:11434/v1)`. | |
| 174 | + | |
| 175 | + Not done: tasks 1 and 2 (reproduce on the user's Mac with the real | |
| 176 | + Ollama, and name the exact cause) — the curl checks given in the | |
| 177 | + conversation would tell. | |
| 178 | + - id: 3 | |
| 179 | + author: | |
| 180 | + name: k33g | |
| 181 | + email: ph.charriere@gmail.com | |
| 182 | + createdAt: 2026-11-14T18:14:17.000Z | |
| 183 | + body: | | |
| 184 | + Tested by the user with the real Ollama: it works (local models | |
| 185 | + listed). Closed. The exact cause on the user's machine was not named | |
| 186 | + (tasks 1–2 closed with the user's test as the reproduction). | |
| @@ -1,12 +1,12 @@ | |||
| 1 | # Managed by IssueSpec. Hand edits are welcome; keep the schema valid. | 1 | # Managed by IssueSpec. Hand edits are welcome; keep the schema valid. |
| 2 | id: 214 | 2 | id: 214 |
| 3 | title: "mm acp-create (/start): Ollama models are listed from the container address instead of the local one" | 3 | title: "mm acp-create (/start): Ollama models are listed from the container address instead of the local one" |
| 4 | -state: open | 4 | +state: closed |
| 5 | author: | 5 | author: |
| 6 | name: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-11-14T07:40:50.000Z | 8 | createdAt: 2026-11-14T07:40:50.000Z |
| 9 | -updatedAt: 2026-11-14T07:47:59.000Z | 9 | +updatedAt: 2026-11-14T18:14:17.000Z |
| 10 | labels: | 10 | labels: |
| 11 | - bug | 11 | - bug |
| 12 | - kind::bug | 12 | - kind::bug |
| @@ -76,44 +76,54 @@ body: | | |||
| 76 | tasks: | 76 | tasks: |
| 77 | - id: 1 | 77 | - id: 1 |
| 78 | title: Reproduce - mm acp-create from Zed and mm init in a terminal, Ollama on the host, note the address used | 78 | title: Reproduce - mm acp-create from Zed and mm init in a terminal, Ollama on the host, note the address used |
| 79 | - state: open | 79 | + state: closed |
| 80 | priority: high | 80 | priority: high |
| 81 | author: | 81 | author: |
| 82 | name: k33g | 82 | name: k33g |
| 83 | email: ph.charriere@gmail.com | 83 | email: ph.charriere@gmail.com |
| 84 | createdAt: 2026-11-14T07:40:50.000Z | 84 | createdAt: 2026-11-14T07:40:50.000Z |
| 85 | + updatedAt: 2026-11-14T18:14:17.000Z | ||
| 86 | + closedAt: 2026-11-14T18:14:17.000Z | ||
| 85 | - id: 2 | 87 | - id: 2 |
| 86 | title: Find why the local address is not taken (probe timeout, localhost vs 127.0.0.1 / IPv6, environment of the editor's process) | 88 | title: Find why the local address is not taken (probe timeout, localhost vs 127.0.0.1 / IPv6, environment of the editor's process) |
| 87 | - state: open | 89 | + state: closed |
| 88 | priority: high | 90 | priority: high |
| 89 | author: | 91 | author: |
| 90 | name: k33g | 92 | name: k33g |
| 91 | email: ph.charriere@gmail.com | 93 | email: ph.charriere@gmail.com |
| 92 | createdAt: 2026-11-14T07:40:50.000Z | 94 | createdAt: 2026-11-14T07:40:50.000Z |
| 95 | + updatedAt: 2026-11-14T18:14:17.000Z | ||
| 96 | + closedAt: 2026-11-14T18:14:17.000Z | ||
| 93 | - id: 3 | 97 | - id: 3 |
| 94 | title: Fix - the wizard lists the models from the local address when mm is not in a container | 98 | title: Fix - the wizard lists the models from the local address when mm is not in a container |
| 95 | - state: open | 99 | + state: closed |
| 96 | priority: high | 100 | priority: high |
| 97 | author: | 101 | author: |
| 98 | name: k33g | 102 | name: k33g |
| 99 | email: ph.charriere@gmail.com | 103 | email: ph.charriere@gmail.com |
| 100 | createdAt: 2026-11-14T07:40:50.000Z | 104 | createdAt: 2026-11-14T07:40:50.000Z |
| 105 | + updatedAt: 2026-11-14T17:54:42.000Z | ||
| 106 | + closedAt: 2026-11-14T17:54:42.000Z | ||
| 101 | - id: 4 | 107 | - id: 4 |
| 102 | title: Show the address the models were listed from in the model question (both modes) | 108 | title: Show the address the models were listed from in the model question (both modes) |
| 103 | - state: open | 109 | + state: closed |
| 104 | priority: medium | 110 | priority: medium |
| 105 | author: | 111 | author: |
| 106 | name: k33g | 112 | name: k33g |
| 107 | email: ph.charriere@gmail.com | 113 | email: ph.charriere@gmail.com |
| 108 | createdAt: 2026-11-14T07:40:50.000Z | 114 | createdAt: 2026-11-14T07:40:50.000Z |
| 115 | + updatedAt: 2026-11-14T17:54:42.000Z | ||
| 116 | + closedAt: 2026-11-14T17:54:42.000Z | ||
| 109 | - id: 5 | 117 | - id: 5 |
| 110 | title: Tests - a local server answering slowly or only on 127.0.0.1 keeps the local address | 118 | title: Tests - a local server answering slowly or only on 127.0.0.1 keeps the local address |
| 111 | - state: open | 119 | + state: closed |
| 112 | priority: medium | 120 | priority: medium |
| 113 | author: | 121 | author: |
| 114 | name: k33g | 122 | name: k33g |
| 115 | email: ph.charriere@gmail.com | 123 | email: ph.charriere@gmail.com |
| 116 | createdAt: 2026-11-14T07:40:50.000Z | 124 | createdAt: 2026-11-14T07:40:50.000Z |
| 125 | + updatedAt: 2026-11-14T17:54:42.000Z | ||
| 126 | + closedAt: 2026-11-14T17:54:42.000Z | ||
| 117 | comments: | 127 | comments: |
| 118 | - id: 1 | 128 | - id: 1 |
| 119 | author: | 129 | author: |
| @@ -128,3 +138,49 @@ comments: | |||
| 128 | it: look at what is specific to Ollama — its `/v1/models` answering | 138 | it: look at what is specific to Ollama — its `/v1/models` answering |
| 129 | later than 2 s or not 200, Ollama listening on IPv4 only while DMR | 139 | later than 2 s or not 200, Ollama listening on IPv4 only while DMR |
| 130 | answers on both, or `OLLAMA_HOST` on the user's machine. | 140 | answers on both, or `OLLAMA_HOST` on the user's machine. |
| 141 | + - id: 2 | ||
| 142 | + author: | ||
| 143 | + name: k33g | ||
| 144 | + email: ph.charriere@gmail.com | ||
| 145 | + createdAt: 2026-11-14T17:54:42.000Z | ||
| 146 | + body: | | ||
| 147 | + Fixed on `fix/wizard-local-address` (uncommitted), without waiting for | ||
| 148 | + the exact cause on the user's machine: the fix covers hypotheses 1 | ||
| 149 | + (slow probe), 2 (IPv4 only) and 4 (Docker Desktop resolving | ||
| 150 | + host.docker.internal on the host, which hid the failed probe). | ||
| 151 | + | ||
| 152 | + - The wizard (mm init and mm acp-create) no longer takes the engine's | ||
| 153 | + resolution (2 s probe of `/models`, then a silent switch to the | ||
| 154 | + container fallback). `resolveBase` → `AGENT_BASE_URL` (or the | ||
| 155 | + legacy variable) when set; else the first local address whose model | ||
| 156 | + list answers (the provider's own list endpoint, `/api/tags` for | ||
| 157 | + Ollama, 5 s): the default, then the same with `127.0.0.1` when it | ||
| 158 | + names `localhost`; the fallback only when none answers; a provider | ||
| 159 | + without a fallback is not probed. `engine.EnvBaseURL` added. | ||
| 160 | + - The model question names the address: `Model? (listed from …)`. | ||
| 161 | + - The written file is unchanged (no `baseUrl` for the default). | ||
| 162 | + - Runtime (`mm acp` with the written file) still uses the engine's | ||
| 163 | + resolution — not touched here. | ||
| 164 | + | ||
| 165 | + Tests: `TestChooseBasePrefersALocalAddress`, `TestLocalAddresses`, | ||
| 166 | + `TestResolveBaseKeepsASlowLocalServer` (a server whose `/v1/models` | ||
| 167 | + takes 3 s: the engine's probe takes the fallback, the wizard keeps the | ||
| 168 | + local address), `TestResolveBaseHonoursAgentBaseURL`. | ||
| 169 | + | ||
| 170 | + End to end, real binary, `mm acp-create --provider ollama`, a fake | ||
| 171 | + Ollama on 127.0.0.1:11434 whose `/v1/models` takes 3 s: before → | ||
| 172 | + `Model ID? (no list from http://host.docker.internal:11434/v1 …)`; | ||
| 173 | + after → `Model? (listed from http://localhost:11434/v1)`. | ||
| 174 | + | ||
| 175 | + Not done: tasks 1 and 2 (reproduce on the user's Mac with the real | ||
| 176 | + Ollama, and name the exact cause) — the curl checks given in the | ||
| 177 | + conversation would tell. | ||
| 178 | + - id: 3 | ||
| 179 | + author: | ||
| 180 | + name: k33g | ||
| 181 | + email: ph.charriere@gmail.com | ||
| 182 | + createdAt: 2026-11-14T18:14:17.000Z | ||
| 183 | + body: | | ||
| 184 | + Tested by the user with the real Ollama: it works (local models | ||
| 185 | + listed). Closed. The exact cause on the user's machine was not named | ||
| 186 | + (tasks 1–2 closed with the user's test as the reproduction). | ||
modified
.tickets/issues/0215-mm-acp-create-start-test-every-provider-address.yaml +34 -5 | @@ -1,12 +1,12 @@ | ||
| 1 | 1 | # Managed by IssueSpec. Hand edits are welcome; keep the schema valid. |
| 2 | 2 | id: 215 |
| 3 | 3 | title: "mm acp-create (/start): test every provider - address used and model list" |
| 4 | -state: open | |
| 4 | +state: closed | |
| 5 | 5 | author: |
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-11-14T07:41:16.000Z |
| 9 | -updatedAt: 2026-11-14T08:07:53.000Z | |
| 9 | +updatedAt: 2026-11-14T18:45:13.000Z | |
| 10 | 10 | labels: |
| 11 | 11 | - kind::chore |
| 12 | 12 | - To be tested |
| @@ -79,12 +79,14 @@ tasks: | ||
| 79 | 79 | closedAt: 2026-11-14T07:47:59.000Z |
| 80 | 80 | - id: 3 |
| 81 | 81 | title: llamacpp - llama-server on 127.0.0.1:8080 |
| 82 | - state: open | |
| 82 | + state: closed | |
| 83 | 83 | priority: medium |
| 84 | 84 | author: |
| 85 | 85 | name: k33g |
| 86 | 86 | email: ph.charriere@gmail.com |
| 87 | 87 | createdAt: 2026-11-14T07:41:16.000Z |
| 88 | + updatedAt: 2026-11-14T18:24:44.000Z | |
| 89 | + closedAt: 2026-11-14T18:24:44.000Z | |
| 88 | 90 | - id: 4 |
| 89 | 91 | title: kronk |
| 90 | 92 | state: closed |
| @@ -107,20 +109,24 @@ tasks: | ||
| 107 | 109 | closedAt: 2026-11-14T08:07:53.000Z |
| 108 | 110 | - id: 6 |
| 109 | 111 | title: Same checks with mm in a container or a Docker Sandbox (the fallback must be taken there) |
| 110 | - state: open | |
| 112 | + state: closed | |
| 111 | 113 | priority: medium |
| 112 | 114 | author: |
| 113 | 115 | name: k33g |
| 114 | 116 | email: ph.charriere@gmail.com |
| 115 | 117 | createdAt: 2026-11-14T07:41:16.000Z |
| 118 | + updatedAt: 2026-11-14T18:45:13.000Z | |
| 119 | + closedAt: 2026-11-14T18:45:13.000Z | |
| 116 | 120 | - id: 7 |
| 117 | 121 | title: Write the results in a comment (version, client, address used, list ok or not); a ticket per bug found |
| 118 | - state: open | |
| 122 | + state: closed | |
| 119 | 123 | priority: low |
| 120 | 124 | author: |
| 121 | 125 | name: k33g |
| 122 | 126 | email: ph.charriere@gmail.com |
| 123 | 127 | createdAt: 2026-11-14T07:41:16.000Z |
| 128 | + updatedAt: 2026-11-14T18:45:13.000Z | |
| 129 | + closedAt: 2026-11-14T18:45:13.000Z | |
| 124 | 130 | comments: |
| 125 | 131 | - id: 1 |
| 126 | 132 | author: |
| @@ -148,3 +154,26 @@ comments: | ||
| 148 | 154 | body: | |
| 149 | 155 | User (2026-11-14): **openai works** too. Still to try: llamacpp, and |
| 150 | 156 | inside a container / sandbox. |
| 157 | + - id: 4 | |
| 158 | + author: | |
| 159 | + name: k33g | |
| 160 | + email: ph.charriere@gmail.com | |
| 161 | + createdAt: 2026-11-14T18:24:44.000Z | |
| 162 | + body: | | |
| 163 | + User (2026-11-14): **llamacpp works** too. Every provider now checked | |
| 164 | + on the host: dmr, llmman, kronk, openai, llamacpp, and ollama after | |
| 165 | + the fix of #214. Still to try: inside a container / Docker Sandbox | |
| 166 | + (task 6). | |
| 167 | + - id: 5 | |
| 168 | + author: | |
| 169 | + name: k33g | |
| 170 | + email: ph.charriere@gmail.com | |
| 171 | + createdAt: 2026-11-14T18:45:13.000Z | |
| 172 | + body: | | |
| 173 | + Closed at the user's request. Summary: on the host, every provider | |
| 174 | + lists its models in `/start` (dmr, llmman, kronk, openai, llamacpp; | |
| 175 | + ollama after #214). In a container, the fallback works for ollama and | |
| 176 | + llmman; llamacpp had none — added by #217 (on a branch, not in a | |
| 177 | + release yet: a container built by `mm dockerinit` runs the latest | |
| 178 | + release, v1.0.9, which does not have it). Docker Sandbox not tried. | |
| 179 | + | |
| @@ -1,12 +1,12 @@ | |||
| 1 | # Managed by IssueSpec. Hand edits are welcome; keep the schema valid. | 1 | # Managed by IssueSpec. Hand edits are welcome; keep the schema valid. |
| 2 | id: 215 | 2 | id: 215 |
| 3 | title: "mm acp-create (/start): test every provider - address used and model list" | 3 | title: "mm acp-create (/start): test every provider - address used and model list" |
| 4 | -state: open | 4 | +state: closed |
| 5 | author: | 5 | author: |
| 6 | name: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-11-14T07:41:16.000Z | 8 | createdAt: 2026-11-14T07:41:16.000Z |
| 9 | -updatedAt: 2026-11-14T08:07:53.000Z | 9 | +updatedAt: 2026-11-14T18:45:13.000Z |
| 10 | labels: | 10 | labels: |
| 11 | - kind::chore | 11 | - kind::chore |
| 12 | - To be tested | 12 | - To be tested |
| @@ -79,12 +79,14 @@ tasks: | |||
| 79 | closedAt: 2026-11-14T07:47:59.000Z | 79 | closedAt: 2026-11-14T07:47:59.000Z |
| 80 | - id: 3 | 80 | - id: 3 |
| 81 | title: llamacpp - llama-server on 127.0.0.1:8080 | 81 | title: llamacpp - llama-server on 127.0.0.1:8080 |
| 82 | - state: open | 82 | + state: closed |
| 83 | priority: medium | 83 | priority: medium |
| 84 | author: | 84 | author: |
| 85 | name: k33g | 85 | name: k33g |
| 86 | email: ph.charriere@gmail.com | 86 | email: ph.charriere@gmail.com |
| 87 | createdAt: 2026-11-14T07:41:16.000Z | 87 | createdAt: 2026-11-14T07:41:16.000Z |
| 88 | + updatedAt: 2026-11-14T18:24:44.000Z | ||
| 89 | + closedAt: 2026-11-14T18:24:44.000Z | ||
| 88 | - id: 4 | 90 | - id: 4 |
| 89 | title: kronk | 91 | title: kronk |
| 90 | state: closed | 92 | state: closed |
| @@ -107,20 +109,24 @@ tasks: | |||
| 107 | closedAt: 2026-11-14T08:07:53.000Z | 109 | closedAt: 2026-11-14T08:07:53.000Z |
| 108 | - id: 6 | 110 | - id: 6 |
| 109 | title: Same checks with mm in a container or a Docker Sandbox (the fallback must be taken there) | 111 | title: Same checks with mm in a container or a Docker Sandbox (the fallback must be taken there) |
| 110 | - state: open | 112 | + state: closed |
| 111 | priority: medium | 113 | priority: medium |
| 112 | author: | 114 | author: |
| 113 | name: k33g | 115 | name: k33g |
| 114 | email: ph.charriere@gmail.com | 116 | email: ph.charriere@gmail.com |
| 115 | createdAt: 2026-11-14T07:41:16.000Z | 117 | createdAt: 2026-11-14T07:41:16.000Z |
| 118 | + updatedAt: 2026-11-14T18:45:13.000Z | ||
| 119 | + closedAt: 2026-11-14T18:45:13.000Z | ||
| 116 | - id: 7 | 120 | - id: 7 |
| 117 | title: Write the results in a comment (version, client, address used, list ok or not); a ticket per bug found | 121 | title: Write the results in a comment (version, client, address used, list ok or not); a ticket per bug found |
| 118 | - state: open | 122 | + state: closed |
| 119 | priority: low | 123 | priority: low |
| 120 | author: | 124 | author: |
| 121 | name: k33g | 125 | name: k33g |
| 122 | email: ph.charriere@gmail.com | 126 | email: ph.charriere@gmail.com |
| 123 | createdAt: 2026-11-14T07:41:16.000Z | 127 | createdAt: 2026-11-14T07:41:16.000Z |
| 128 | + updatedAt: 2026-11-14T18:45:13.000Z | ||
| 129 | + closedAt: 2026-11-14T18:45:13.000Z | ||
| 124 | comments: | 130 | comments: |
| 125 | - id: 1 | 131 | - id: 1 |
| 126 | author: | 132 | author: |
| @@ -148,3 +154,26 @@ comments: | |||
| 148 | body: | | 154 | body: | |
| 149 | User (2026-11-14): **openai works** too. Still to try: llamacpp, and | 155 | User (2026-11-14): **openai works** too. Still to try: llamacpp, and |
| 150 | inside a container / sandbox. | 156 | inside a container / sandbox. |
| 157 | + - id: 4 | ||
| 158 | + author: | ||
| 159 | + name: k33g | ||
| 160 | + email: ph.charriere@gmail.com | ||
| 161 | + createdAt: 2026-11-14T18:24:44.000Z | ||
| 162 | + body: | | ||
| 163 | + User (2026-11-14): **llamacpp works** too. Every provider now checked | ||
| 164 | + on the host: dmr, llmman, kronk, openai, llamacpp, and ollama after | ||
| 165 | + the fix of #214. Still to try: inside a container / Docker Sandbox | ||
| 166 | + (task 6). | ||
| 167 | + - id: 5 | ||
| 168 | + author: | ||
| 169 | + name: k33g | ||
| 170 | + email: ph.charriere@gmail.com | ||
| 171 | + createdAt: 2026-11-14T18:45:13.000Z | ||
| 172 | + body: | | ||
| 173 | + Closed at the user's request. Summary: on the host, every provider | ||
| 174 | + lists its models in `/start` (dmr, llmman, kronk, openai, llamacpp; | ||
| 175 | + ollama after #214). In a container, the fallback works for ollama and | ||
| 176 | + llmman; llamacpp had none — added by #217 (on a branch, not in a | ||
| 177 | + release yet: a container built by `mm dockerinit` runs the latest | ||
| 178 | + release, v1.0.9, which does not have it). Docker Sandbox not tried. | ||
| 179 | + | ||
modified
.tickets/issues/0216-mm-dockerinit-i-have-no-name-in-the-container-th.yaml +11 -4 | @@ -1,12 +1,12 @@ | ||
| 1 | 1 | # Managed by IssueSpec. Hand edits are welcome; keep the schema valid. |
| 2 | 2 | id: 216 |
| 3 | 3 | title: "mm dockerinit: \"I have no name!\" in the container - the mm account has uid 1000, compose runs as the user's uid" |
| 4 | -state: open | |
| 4 | +state: closed | |
| 5 | 5 | author: |
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-11-14T17:31:27.000Z |
| 9 | -updatedAt: 2026-11-14T17:35:14.000Z | |
| 9 | +updatedAt: 2026-11-14T17:50:32.000Z | |
| 10 | 10 | labels: |
| 11 | 11 | - bug |
| 12 | 12 | - kind::bug |
| @@ -143,6 +143,8 @@ tasks: | ||
| 143 | 143 | name: k33g |
| 144 | 144 | email: ph.charriere@gmail.com |
| 145 | 145 | createdAt: 2026-11-14T17:31:27.000Z |
| 146 | + updatedAt: 2026-11-14T17:35:14.000Z | |
| 147 | + closedAt: 2026-11-14T17:35:14.000Z | |
| 146 | 148 | comments: |
| 147 | 149 | - id: 1 |
| 148 | 150 | author: |
| @@ -170,5 +172,10 @@ comments: | ||
| 170 | 172 | identity. Unrelated to the fix — the docs say to set `user.name` / |
| 171 | 173 | `user.email` or the `GIT_*` variables. Not tried: `mm tui` in the |
| 172 | 174 | container (no terminal here), ssh, Docker Desktop on macOS. |
| 173 | - updatedAt: 2026-11-14T17:35:14.000Z | |
| 174 | - closedAt: 2026-11-14T17:35:14.000Z | |
| 175 | + - id: 2 | |
| 176 | + author: | |
| 177 | + name: k33g | |
| 178 | + email: ph.charriere@gmail.com | |
| 179 | + createdAt: 2026-11-14T17:50:32.000Z | |
| 180 | + body: | | |
| 181 | + Closed at the user's request. | |
| @@ -1,12 +1,12 @@ | |||
| 1 | # Managed by IssueSpec. Hand edits are welcome; keep the schema valid. | 1 | # Managed by IssueSpec. Hand edits are welcome; keep the schema valid. |
| 2 | id: 216 | 2 | id: 216 |
| 3 | title: "mm dockerinit: \"I have no name!\" in the container - the mm account has uid 1000, compose runs as the user's uid" | 3 | title: "mm dockerinit: \"I have no name!\" in the container - the mm account has uid 1000, compose runs as the user's uid" |
| 4 | -state: open | 4 | +state: closed |
| 5 | author: | 5 | author: |
| 6 | name: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-11-14T17:31:27.000Z | 8 | createdAt: 2026-11-14T17:31:27.000Z |
| 9 | -updatedAt: 2026-11-14T17:35:14.000Z | 9 | +updatedAt: 2026-11-14T17:50:32.000Z |
| 10 | labels: | 10 | labels: |
| 11 | - bug | 11 | - bug |
| 12 | - kind::bug | 12 | - kind::bug |
| @@ -143,6 +143,8 @@ tasks: | |||
| 143 | name: k33g | 143 | name: k33g |
| 144 | email: ph.charriere@gmail.com | 144 | email: ph.charriere@gmail.com |
| 145 | createdAt: 2026-11-14T17:31:27.000Z | 145 | createdAt: 2026-11-14T17:31:27.000Z |
| 146 | + updatedAt: 2026-11-14T17:35:14.000Z | ||
| 147 | + closedAt: 2026-11-14T17:35:14.000Z | ||
| 146 | comments: | 148 | comments: |
| 147 | - id: 1 | 149 | - id: 1 |
| 148 | author: | 150 | author: |
| @@ -170,5 +172,10 @@ comments: | |||
| 170 | identity. Unrelated to the fix — the docs say to set `user.name` / | 172 | identity. Unrelated to the fix — the docs say to set `user.name` / |
| 171 | `user.email` or the `GIT_*` variables. Not tried: `mm tui` in the | 173 | `user.email` or the `GIT_*` variables. Not tried: `mm tui` in the |
| 172 | container (no terminal here), ssh, Docker Desktop on macOS. | 174 | container (no terminal here), ssh, Docker Desktop on macOS. |
| 173 | - updatedAt: 2026-11-14T17:35:14.000Z | 175 | + - id: 2 |
| 174 | - closedAt: 2026-11-14T17:35:14.000Z | 176 | + author: |
| 177 | + name: k33g | ||
| 178 | + email: ph.charriere@gmail.com | ||
| 179 | + createdAt: 2026-11-14T17:50:32.000Z | ||
| 180 | + body: | | ||
| 181 | + Closed at the user's request. | ||
added
.tickets/issues/0217-llamacpp-fall-back-on-host-docker-internal-8080.yaml +154 -0 | new file mode 100644 | ||
| @@ -0,0 +1,154 @@ | ||
| 1 | +# Managed by IssueSpec. Hand edits are welcome; keep the schema valid. | |
| 2 | +id: 217 | |
| 3 | +title: "llamacpp: fall back on host.docker.internal:8080 like the other local providers" | |
| 4 | +state: closed | |
| 5 | +author: | |
| 6 | + name: k33g | |
| 7 | + email: ph.charriere@gmail.com | |
| 8 | +createdAt: 2026-11-14T18:36:24.000Z | |
| 9 | +updatedAt: 2026-11-14T18:45:13.000Z | |
| 10 | +labels: | |
| 11 | + - enhancement | |
| 12 | + - kind::feature | |
| 13 | +milestone: v1.1.0 | |
| 14 | +epic: Providers (LLM Engine) | |
| 15 | +related: | |
| 16 | + - 215 | |
| 17 | +body: | | |
| 18 | + ## Seen (user, 2026-11-14, while testing #215) | |
| 19 | + | |
| 20 | + With mm in a container, the fallback address works for **ollama** and | |
| 21 | + **llmman**, not for **llamacpp**. | |
| 22 | + | |
| 23 | + ## Why (code read) | |
| 24 | + | |
| 25 | + 1. **llamacpp declares no fallback** ([internal/engine/openai_compat.go](internal/engine/openai_compat.go)): | |
| 26 | + dmr, ollama, llmman and kronk fall back on | |
| 27 | + `http://host.docker.internal:<port>/...` when their default does not | |
| 28 | + answer; llamacpp only has `http://127.0.0.1:8080/v1`. In a container, | |
| 29 | + that is the container itself, and nothing else is tried. The container | |
| 30 | + guide says so ("set `baseUrl: http://host.docker.internal:8080/v1`"). | |
| 31 | + The shipped `agent.llamacpp.yaml` even opts out on purpose | |
| 32 | + (`fallback: ""`, "llama-server is wherever you started it"). | |
| 33 | + 2. **llama-server listens on `127.0.0.1` by default.** On Linux and in a | |
| 34 | + Docker Sandbox, `host.docker.internal` is the host's gateway, not its | |
| 35 | + loopback: start it with `--host 0.0.0.0` (as Kronk needs | |
| 36 | + `--api-host 0.0.0.0:11435`). On Docker Desktop (Mac) the loopback is | |
| 37 | + reached anyway (Ollama on 127.0.0.1 works there) — not checked for | |
| 38 | + llama-server. | |
| 39 | + 3. **Docker Sandbox: port 8080 is not in the mini-me kit's network | |
| 40 | + policy** (12434, 11434, 17434 only): `sbx policy allow network | |
| 41 | + host.docker.internal:8080`, or a change in the kit (other repository, | |
| 42 | + mini-me-kit) — out of scope here. | |
| 43 | + | |
| 44 | + ## Change (agreed with the user) | |
| 45 | + | |
| 46 | + - llamacpp's fallback: `http://host.docker.internal:8080/v1`, the same | |
| 47 | + rule as the others (taken when the default does not answer `/models` | |
| 48 | + within 2 s; `fallback: ""` in a file still turns it off). | |
| 49 | + - Its start hint mentions `--host 0.0.0.0` for mm in a container or a | |
| 50 | + sandbox. | |
| 51 | + - `agent.llamacpp.yaml` drops `fallback: ""`, so that a copy of it gets | |
| 52 | + the fallback. Re-litigates that file's explicit choice — the user asked | |
| 53 | + for llamacpp to behave like the others. `config.samples/` and | |
| 54 | + `demos/struggle-signals/` (pinned to a fake server) are left alone. | |
| 55 | + - `mm init` writes the fallback in the file's comment, as for the others | |
| 56 | + (ticket 121); the wizard's address choice (#214) now also tries it. | |
| 57 | + | |
| 58 | + ## Acceptance criteria | |
| 59 | + | |
| 60 | + - mm in a container, no `baseUrl`, llama-server on the host started with | |
| 61 | + `--host 0.0.0.0` → mm reaches it through `host.docker.internal:8080`. | |
| 62 | + - On the host, nothing changes when llama-server answers on 127.0.0.1. | |
| 63 | + - Tests and docs EN+FR. | |
| 64 | +tasks: | |
| 65 | + - id: 1 | |
| 66 | + title: Engine - llamacpp falls back on http://host.docker.internal:8080/v1, like the other local providers | |
| 67 | + state: closed | |
| 68 | + priority: high | |
| 69 | + author: | |
| 70 | + name: k33g | |
| 71 | + email: ph.charriere@gmail.com | |
| 72 | + createdAt: 2026-11-14T18:36:24.000Z | |
| 73 | + updatedAt: 2026-11-14T18:39:34.000Z | |
| 74 | + closedAt: 2026-11-14T18:39:34.000Z | |
| 75 | + - id: 2 | |
| 76 | + title: startHint - say --host 0.0.0.0 for mm in a container or a sandbox | |
| 77 | + state: closed | |
| 78 | + priority: medium | |
| 79 | + author: | |
| 80 | + name: k33g | |
| 81 | + email: ph.charriere@gmail.com | |
| 82 | + createdAt: 2026-11-14T18:36:24.000Z | |
| 83 | + updatedAt: 2026-11-14T18:39:34.000Z | |
| 84 | + closedAt: 2026-11-14T18:39:34.000Z | |
| 85 | + - id: 3 | |
| 86 | + title: agent.llamacpp.yaml - drop fallback empty (it opted out on purpose) | |
| 87 | + state: closed | |
| 88 | + priority: medium | |
| 89 | + author: | |
| 90 | + name: k33g | |
| 91 | + email: ph.charriere@gmail.com | |
| 92 | + createdAt: 2026-11-14T18:36:24.000Z | |
| 93 | + updatedAt: 2026-11-14T18:39:34.000Z | |
| 94 | + closedAt: 2026-11-14T18:39:34.000Z | |
| 95 | + - id: 4 | |
| 96 | + title: Tests - provider resolution, mm init's comment, the wizard's address choice | |
| 97 | + state: closed | |
| 98 | + priority: medium | |
| 99 | + author: | |
| 100 | + name: k33g | |
| 101 | + email: ph.charriere@gmail.com | |
| 102 | + createdAt: 2026-11-14T18:36:24.000Z | |
| 103 | + updatedAt: 2026-11-14T18:39:34.000Z | |
| 104 | + closedAt: 2026-11-14T18:39:34.000Z | |
| 105 | + - id: 5 | |
| 106 | + title: Docs EN+FR - configuration (providers table), run-in-a-container, run-with-llama-cpp, sandbox (port 8080 policy) | |
| 107 | + state: closed | |
| 108 | + priority: medium | |
| 109 | + author: | |
| 110 | + name: k33g | |
| 111 | + email: ph.charriere@gmail.com | |
| 112 | + createdAt: 2026-11-14T18:36:24.000Z | |
| 113 | + updatedAt: 2026-11-14T18:39:34.000Z | |
| 114 | + closedAt: 2026-11-14T18:39:34.000Z | |
| 115 | +comments: | |
| 116 | + - id: 1 | |
| 117 | + author: | |
| 118 | + name: k33g | |
| 119 | + email: ph.charriere@gmail.com | |
| 120 | + createdAt: 2026-11-14T18:39:34.000Z | |
| 121 | + body: | | |
| 122 | + Implemented on `feature/llamacpp-fallback` (uncommitted). | |
| 123 | + | |
| 124 | + - Engine: llamacpp's fallback `http://host.docker.internal:8080/v1`; | |
| 125 | + start hint `… --port 8080 (add --host 0.0.0.0 when mm runs in a | |
| 126 | + container or a sandbox)`. | |
| 127 | + - `agent.llamacpp.yaml`: `fallback: ""` removed, the comment says what | |
| 128 | + the fallback is and how to turn it off. `config.samples/` and | |
| 129 | + `demos/struggle-signals/` keep their `fallback: ""`. | |
| 130 | + - Tests updated where they asserted "no fallback" | |
| 131 | + (`TestResolveURLPrecedence`: falls back when baseUrl is down, keeps | |
| 132 | + it when up; `TestConfigCompat` pins `fallback: ""`; | |
| 133 | + `TestDefaultURLs`; `TestRenderRecordsTheDefaultURLs`: mm init now | |
| 134 | + writes the fallback comment for llamacpp). Whole suite green. | |
| 135 | + - Docs EN+FR: configuration (providers table, agent.llamacpp.yaml), | |
| 136 | + mcp-configuration (EN), cli (warning example), run-in-a-container, | |
| 137 | + run-with-llama-cpp (container / sandbox variant), sandbox guide. | |
| 138 | + | |
| 139 | + Side effect, same as dmr/ollama/llmman already: on the host with | |
| 140 | + llama-server down, the start-up warning names the fallback address | |
| 141 | + (`nothing answers at http://host.docker.internal:8080/v1`). | |
| 142 | + | |
| 143 | + Not tried with a real llama-server in a container or a sandbox. | |
| 144 | + - id: 2 | |
| 145 | + author: | |
| 146 | + name: k33g | |
| 147 | + email: ph.charriere@gmail.com | |
| 148 | + createdAt: 2026-11-14T18:45:13.000Z | |
| 149 | + body: | | |
| 150 | + Closed at the user's request. mm init writes the fallback comment for | |
| 151 | + llamacpp (checked by the user). In a container, checked only with | |
| 152 | + v1.0.9 (the released binary the image downloads), which does not have | |
| 153 | + the fallback yet: the fix reaches containers with the next release. | |
| 154 | + | |
| new file mode 100644 | |||
| @@ -0,0 +1,154 @@ | |||
| 1 | +# Managed by IssueSpec. Hand edits are welcome; keep the schema valid. | ||
| 2 | +id: 217 | ||
| 3 | +title: "llamacpp: fall back on host.docker.internal:8080 like the other local providers" | ||
| 4 | +state: closed | ||
| 5 | +author: | ||
| 6 | + name: k33g | ||
| 7 | + email: ph.charriere@gmail.com | ||
| 8 | +createdAt: 2026-11-14T18:36:24.000Z | ||
| 9 | +updatedAt: 2026-11-14T18:45:13.000Z | ||
| 10 | +labels: | ||
| 11 | + - enhancement | ||
| 12 | + - kind::feature | ||
| 13 | +milestone: v1.1.0 | ||
| 14 | +epic: Providers (LLM Engine) | ||
| 15 | +related: | ||
| 16 | + - 215 | ||
| 17 | +body: | | ||
| 18 | + ## Seen (user, 2026-11-14, while testing #215) | ||
| 19 | + | ||
| 20 | + With mm in a container, the fallback address works for **ollama** and | ||
| 21 | + **llmman**, not for **llamacpp**. | ||
| 22 | + | ||
| 23 | + ## Why (code read) | ||
| 24 | + | ||
| 25 | + 1. **llamacpp declares no fallback** ([internal/engine/openai_compat.go](internal/engine/openai_compat.go)): | ||
| 26 | + dmr, ollama, llmman and kronk fall back on | ||
| 27 | + `http://host.docker.internal:<port>/...` when their default does not | ||
| 28 | + answer; llamacpp only has `http://127.0.0.1:8080/v1`. In a container, | ||
| 29 | + that is the container itself, and nothing else is tried. The container | ||
| 30 | + guide says so ("set `baseUrl: http://host.docker.internal:8080/v1`"). | ||
| 31 | + The shipped `agent.llamacpp.yaml` even opts out on purpose | ||
| 32 | + (`fallback: ""`, "llama-server is wherever you started it"). | ||
| 33 | + 2. **llama-server listens on `127.0.0.1` by default.** On Linux and in a | ||
| 34 | + Docker Sandbox, `host.docker.internal` is the host's gateway, not its | ||
| 35 | + loopback: start it with `--host 0.0.0.0` (as Kronk needs | ||
| 36 | + `--api-host 0.0.0.0:11435`). On Docker Desktop (Mac) the loopback is | ||
| 37 | + reached anyway (Ollama on 127.0.0.1 works there) — not checked for | ||
| 38 | + llama-server. | ||
| 39 | + 3. **Docker Sandbox: port 8080 is not in the mini-me kit's network | ||
| 40 | + policy** (12434, 11434, 17434 only): `sbx policy allow network | ||
| 41 | + host.docker.internal:8080`, or a change in the kit (other repository, | ||
| 42 | + mini-me-kit) — out of scope here. | ||
| 43 | + | ||
| 44 | + ## Change (agreed with the user) | ||
| 45 | + | ||
| 46 | + - llamacpp's fallback: `http://host.docker.internal:8080/v1`, the same | ||
| 47 | + rule as the others (taken when the default does not answer `/models` | ||
| 48 | + within 2 s; `fallback: ""` in a file still turns it off). | ||
| 49 | + - Its start hint mentions `--host 0.0.0.0` for mm in a container or a | ||
| 50 | + sandbox. | ||
| 51 | + - `agent.llamacpp.yaml` drops `fallback: ""`, so that a copy of it gets | ||
| 52 | + the fallback. Re-litigates that file's explicit choice — the user asked | ||
| 53 | + for llamacpp to behave like the others. `config.samples/` and | ||
| 54 | + `demos/struggle-signals/` (pinned to a fake server) are left alone. | ||
| 55 | + - `mm init` writes the fallback in the file's comment, as for the others | ||
| 56 | + (ticket 121); the wizard's address choice (#214) now also tries it. | ||
| 57 | + | ||
| 58 | + ## Acceptance criteria | ||
| 59 | + | ||
| 60 | + - mm in a container, no `baseUrl`, llama-server on the host started with | ||
| 61 | + `--host 0.0.0.0` → mm reaches it through `host.docker.internal:8080`. | ||
| 62 | + - On the host, nothing changes when llama-server answers on 127.0.0.1. | ||
| 63 | + - Tests and docs EN+FR. | ||
| 64 | +tasks: | ||
| 65 | + - id: 1 | ||
| 66 | + title: Engine - llamacpp falls back on http://host.docker.internal:8080/v1, like the other local providers | ||
| 67 | + state: closed | ||
| 68 | + priority: high | ||
| 69 | + author: | ||
| 70 | + name: k33g | ||
| 71 | + email: ph.charriere@gmail.com | ||
| 72 | + createdAt: 2026-11-14T18:36:24.000Z | ||
| 73 | + updatedAt: 2026-11-14T18:39:34.000Z | ||
| 74 | + closedAt: 2026-11-14T18:39:34.000Z | ||
| 75 | + - id: 2 | ||
| 76 | + title: startHint - say --host 0.0.0.0 for mm in a container or a sandbox | ||
| 77 | + state: closed | ||
| 78 | + priority: medium | ||
| 79 | + author: | ||
| 80 | + name: k33g | ||
| 81 | + email: ph.charriere@gmail.com | ||
| 82 | + createdAt: 2026-11-14T18:36:24.000Z | ||
| 83 | + updatedAt: 2026-11-14T18:39:34.000Z | ||
| 84 | + closedAt: 2026-11-14T18:39:34.000Z | ||
| 85 | + - id: 3 | ||
| 86 | + title: agent.llamacpp.yaml - drop fallback empty (it opted out on purpose) | ||
| 87 | + state: closed | ||
| 88 | + priority: medium | ||
| 89 | + author: | ||
| 90 | + name: k33g | ||
| 91 | + email: ph.charriere@gmail.com | ||
| 92 | + createdAt: 2026-11-14T18:36:24.000Z | ||
| 93 | + updatedAt: 2026-11-14T18:39:34.000Z | ||
| 94 | + closedAt: 2026-11-14T18:39:34.000Z | ||
| 95 | + - id: 4 | ||
| 96 | + title: Tests - provider resolution, mm init's comment, the wizard's address choice | ||
| 97 | + state: closed | ||
| 98 | + priority: medium | ||
| 99 | + author: | ||
| 100 | + name: k33g | ||
| 101 | + email: ph.charriere@gmail.com | ||
| 102 | + createdAt: 2026-11-14T18:36:24.000Z | ||
| 103 | + updatedAt: 2026-11-14T18:39:34.000Z | ||
| 104 | + closedAt: 2026-11-14T18:39:34.000Z | ||
| 105 | + - id: 5 | ||
| 106 | + title: Docs EN+FR - configuration (providers table), run-in-a-container, run-with-llama-cpp, sandbox (port 8080 policy) | ||
| 107 | + state: closed | ||
| 108 | + priority: medium | ||
| 109 | + author: | ||
| 110 | + name: k33g | ||
| 111 | + email: ph.charriere@gmail.com | ||
| 112 | + createdAt: 2026-11-14T18:36:24.000Z | ||
| 113 | + updatedAt: 2026-11-14T18:39:34.000Z | ||
| 114 | + closedAt: 2026-11-14T18:39:34.000Z | ||
| 115 | +comments: | ||
| 116 | + - id: 1 | ||
| 117 | + author: | ||
| 118 | + name: k33g | ||
| 119 | + email: ph.charriere@gmail.com | ||
| 120 | + createdAt: 2026-11-14T18:39:34.000Z | ||
| 121 | + body: | | ||
| 122 | + Implemented on `feature/llamacpp-fallback` (uncommitted). | ||
| 123 | + | ||
| 124 | + - Engine: llamacpp's fallback `http://host.docker.internal:8080/v1`; | ||
| 125 | + start hint `… --port 8080 (add --host 0.0.0.0 when mm runs in a | ||
| 126 | + container or a sandbox)`. | ||
| 127 | + - `agent.llamacpp.yaml`: `fallback: ""` removed, the comment says what | ||
| 128 | + the fallback is and how to turn it off. `config.samples/` and | ||
| 129 | + `demos/struggle-signals/` keep their `fallback: ""`. | ||
| 130 | + - Tests updated where they asserted "no fallback" | ||
| 131 | + (`TestResolveURLPrecedence`: falls back when baseUrl is down, keeps | ||
| 132 | + it when up; `TestConfigCompat` pins `fallback: ""`; | ||
| 133 | + `TestDefaultURLs`; `TestRenderRecordsTheDefaultURLs`: mm init now | ||
| 134 | + writes the fallback comment for llamacpp). Whole suite green. | ||
| 135 | + - Docs EN+FR: configuration (providers table, agent.llamacpp.yaml), | ||
| 136 | + mcp-configuration (EN), cli (warning example), run-in-a-container, | ||
| 137 | + run-with-llama-cpp (container / sandbox variant), sandbox guide. | ||
| 138 | + | ||
| 139 | + Side effect, same as dmr/ollama/llmman already: on the host with | ||
| 140 | + llama-server down, the start-up warning names the fallback address | ||
| 141 | + (`nothing answers at http://host.docker.internal:8080/v1`). | ||
| 142 | + | ||
| 143 | + Not tried with a real llama-server in a container or a sandbox. | ||
| 144 | + - id: 2 | ||
| 145 | + author: | ||
| 146 | + name: k33g | ||
| 147 | + email: ph.charriere@gmail.com | ||
| 148 | + createdAt: 2026-11-14T18:45:13.000Z | ||
| 149 | + body: | | ||
| 150 | + Closed at the user's request. mm init writes the fallback comment for | ||
| 151 | + llamacpp (checked by the user). In a container, checked only with | ||
| 152 | + v1.0.9 (the released binary the image downloads), which does not have | ||
| 153 | + the fallback yet: the fix reaches containers with the next release. | ||
| 154 | + | ||
added
.tickets/issues/0218-llamacpp-llama-server-s-default-port-will-change.yaml +114 -0 | new file mode 100644 | ||
| @@ -0,0 +1,114 @@ | ||
| 1 | +# Managed by IssueSpec. Hand edits are welcome; keep the schema valid. | |
| 2 | +id: 218 | |
| 3 | +title: "llamacpp: llama-server's default port will change from 8080 to 9931" | |
| 4 | +state: open | |
| 5 | +author: | |
| 6 | + name: k33g | |
| 7 | + email: ph.charriere@gmail.com | |
| 8 | +createdAt: 2026-11-14T18:37:23.000Z | |
| 9 | +updatedAt: 2026-11-14T18:37:23.000Z | |
| 10 | +labels: | |
| 11 | + - kind::chore | |
| 12 | +milestone: v2.0.0 | |
| 13 | +epic: Providers (LLM Engine) | |
| 14 | +related: | |
| 15 | + - 217 | |
| 16 | +body: | | |
| 17 | + ## Notice (seen by the user, 2026-11-14) | |
| 18 | + | |
| 19 | + llama-server prints at start-up: | |
| 20 | + | |
| 21 | + ```text | |
| 22 | + llama_server: NOTICE: server default port will be changed to :9931 in a future release | |
| 23 | + ``` | |
| 24 | + | |
| 25 | + The llama.cpp version that printed it, and the release that will make | |
| 26 | + the change, are not recorded yet. | |
| 27 | + | |
| 28 | + ## What depends on 8080 in mini-me (read 2026-11-14) | |
| 29 | + | |
| 30 | + - **The engine** ([internal/engine/openai_compat.go](internal/engine/openai_compat.go)): | |
| 31 | + llamacpp's default address `http://127.0.0.1:8080/v1`, its fallback | |
| 32 | + `http://host.docker.internal:8080/v1` (ticket #217) and its start hint | |
| 33 | + (`llama-server -m <model.gguf> --jinja --port 8080`). | |
| 34 | + - **Shipped files**: `agent.llamacpp.yaml` (`baseUrl: | |
| 35 | + http://127.0.0.1:8080/v1`), `config.samples/agent.llamacpp.*.yaml`, | |
| 36 | + and the demos run on llama-server (e.g. `demos/qwen-style/`, | |
| 37 | + `demos/decision-skills/`) — to check one by one: most `8080` in | |
| 38 | + `demos/` are web apps the agents build, unrelated. | |
| 39 | + - **Docs EN+FR**: `how-to/run-with-llama-cpp.md`, | |
| 40 | + `reference/configuration.md` (providers table, `agent.llamacpp.yaml`), | |
| 41 | + `reference/cli.md` (the warning example), `how-to/run-in-a-container.md`, | |
| 42 | + `how-to/run-in-a-docker-sandbox.md` (`sbx policy allow network | |
| 43 | + host.docker.internal:8080`), `how-to/verify-tool-order.md`. | |
| 44 | + | |
| 45 | + ## Who is affected | |
| 46 | + | |
| 47 | + Only someone who starts llama-server **without** `--port`: the docs and | |
| 48 | + the start hint always pass `--port 8080`, and a file with an explicit | |
| 49 | + `baseUrl` keeps working. With the new default, an agent with no | |
| 50 | + `baseUrl` would find nothing at 8080. | |
| 51 | + | |
| 52 | + ## To decide | |
| 53 | + | |
| 54 | + - Follow the new default (`9931`) once the release is out — and say so | |
| 55 | + in the release notes, since files without `baseUrl` change server. | |
| 56 | + - Keep `8080` and keep passing `--port 8080` everywhere. | |
| 57 | + - Or, during a transition, try both on the host: the wizard already | |
| 58 | + tries several local addresses in order (`localAddresses`, #214); the | |
| 59 | + engine's own resolution tries one default and one fallback. | |
| 60 | + | |
| 61 | + ## Done when | |
| 62 | + | |
| 63 | + The release is identified, the choice is made and written here, and the | |
| 64 | + engine, the shipped files and the docs agree on it. | |
| 65 | +tasks: | |
| 66 | + - id: 1 | |
| 67 | + title: Find the llama.cpp release that changes the default port, and whether it is already out | |
| 68 | + state: open | |
| 69 | + priority: high | |
| 70 | + author: | |
| 71 | + name: k33g | |
| 72 | + email: ph.charriere@gmail.com | |
| 73 | + createdAt: 2026-11-14T18:37:23.000Z | |
| 74 | + - id: 2 | |
| 75 | + title: Decide - follow the new default (9931), keep 8080, or try both during a transition | |
| 76 | + state: open | |
| 77 | + priority: high | |
| 78 | + author: | |
| 79 | + name: k33g | |
| 80 | + email: ph.charriere@gmail.com | |
| 81 | + createdAt: 2026-11-14T18:37:23.000Z | |
| 82 | + - id: 3 | |
| 83 | + title: Engine - default address, fallback and start hint of llamacpp | |
| 84 | + state: open | |
| 85 | + priority: medium | |
| 86 | + author: | |
| 87 | + name: k33g | |
| 88 | + email: ph.charriere@gmail.com | |
| 89 | + createdAt: 2026-11-14T18:37:23.000Z | |
| 90 | + - id: 4 | |
| 91 | + title: Shipped files - agent.llamacpp.yaml, config.samples/agent.llamacpp.*, demos using llamacpp | |
| 92 | + state: open | |
| 93 | + priority: medium | |
| 94 | + author: | |
| 95 | + name: k33g | |
| 96 | + email: ph.charriere@gmail.com | |
| 97 | + createdAt: 2026-11-14T18:37:23.000Z | |
| 98 | + - id: 5 | |
| 99 | + title: Docs EN+FR - run-with-llama-cpp, configuration (providers table), cli (warning example), container and sandbox guides | |
| 100 | + state: open | |
| 101 | + priority: medium | |
| 102 | + author: | |
| 103 | + name: k33g | |
| 104 | + email: ph.charriere@gmail.com | |
| 105 | + createdAt: 2026-11-14T18:37:23.000Z | |
| 106 | + - id: 6 | |
| 107 | + title: Docker Sandbox - the port in the mini-me kit's network policy, if 8080 is ever added there (mini-me-kit repository) | |
| 108 | + state: open | |
| 109 | + priority: low | |
| 110 | + author: | |
| 111 | + name: k33g | |
| 112 | + email: ph.charriere@gmail.com | |
| 113 | + createdAt: 2026-11-14T18:37:23.000Z | |
| 114 | +comments: [] | |
| new file mode 100644 | |||
| @@ -0,0 +1,114 @@ | |||
| 1 | +# Managed by IssueSpec. Hand edits are welcome; keep the schema valid. | ||
| 2 | +id: 218 | ||
| 3 | +title: "llamacpp: llama-server's default port will change from 8080 to 9931" | ||
| 4 | +state: open | ||
| 5 | +author: | ||
| 6 | + name: k33g | ||
| 7 | + email: ph.charriere@gmail.com | ||
| 8 | +createdAt: 2026-11-14T18:37:23.000Z | ||
| 9 | +updatedAt: 2026-11-14T18:37:23.000Z | ||
| 10 | +labels: | ||
| 11 | + - kind::chore | ||
| 12 | +milestone: v2.0.0 | ||
| 13 | +epic: Providers (LLM Engine) | ||
| 14 | +related: | ||
| 15 | + - 217 | ||
| 16 | +body: | | ||
| 17 | + ## Notice (seen by the user, 2026-11-14) | ||
| 18 | + | ||
| 19 | + llama-server prints at start-up: | ||
| 20 | + | ||
| 21 | + ```text | ||
| 22 | + llama_server: NOTICE: server default port will be changed to :9931 in a future release | ||
| 23 | + ``` | ||
| 24 | + | ||
| 25 | + The llama.cpp version that printed it, and the release that will make | ||
| 26 | + the change, are not recorded yet. | ||
| 27 | + | ||
| 28 | + ## What depends on 8080 in mini-me (read 2026-11-14) | ||
| 29 | + | ||
| 30 | + - **The engine** ([internal/engine/openai_compat.go](internal/engine/openai_compat.go)): | ||
| 31 | + llamacpp's default address `http://127.0.0.1:8080/v1`, its fallback | ||
| 32 | + `http://host.docker.internal:8080/v1` (ticket #217) and its start hint | ||
| 33 | + (`llama-server -m <model.gguf> --jinja --port 8080`). | ||
| 34 | + - **Shipped files**: `agent.llamacpp.yaml` (`baseUrl: | ||
| 35 | + http://127.0.0.1:8080/v1`), `config.samples/agent.llamacpp.*.yaml`, | ||
| 36 | + and the demos run on llama-server (e.g. `demos/qwen-style/`, | ||
| 37 | + `demos/decision-skills/`) — to check one by one: most `8080` in | ||
| 38 | + `demos/` are web apps the agents build, unrelated. | ||
| 39 | + - **Docs EN+FR**: `how-to/run-with-llama-cpp.md`, | ||
| 40 | + `reference/configuration.md` (providers table, `agent.llamacpp.yaml`), | ||
| 41 | + `reference/cli.md` (the warning example), `how-to/run-in-a-container.md`, | ||
| 42 | + `how-to/run-in-a-docker-sandbox.md` (`sbx policy allow network | ||
| 43 | + host.docker.internal:8080`), `how-to/verify-tool-order.md`. | ||
| 44 | + | ||
| 45 | + ## Who is affected | ||
| 46 | + | ||
| 47 | + Only someone who starts llama-server **without** `--port`: the docs and | ||
| 48 | + the start hint always pass `--port 8080`, and a file with an explicit | ||
| 49 | + `baseUrl` keeps working. With the new default, an agent with no | ||
| 50 | + `baseUrl` would find nothing at 8080. | ||
| 51 | + | ||
| 52 | + ## To decide | ||
| 53 | + | ||
| 54 | + - Follow the new default (`9931`) once the release is out — and say so | ||
| 55 | + in the release notes, since files without `baseUrl` change server. | ||
| 56 | + - Keep `8080` and keep passing `--port 8080` everywhere. | ||
| 57 | + - Or, during a transition, try both on the host: the wizard already | ||
| 58 | + tries several local addresses in order (`localAddresses`, #214); the | ||
| 59 | + engine's own resolution tries one default and one fallback. | ||
| 60 | + | ||
| 61 | + ## Done when | ||
| 62 | + | ||
| 63 | + The release is identified, the choice is made and written here, and the | ||
| 64 | + engine, the shipped files and the docs agree on it. | ||
| 65 | +tasks: | ||
| 66 | + - id: 1 | ||
| 67 | + title: Find the llama.cpp release that changes the default port, and whether it is already out | ||
| 68 | + state: open | ||
| 69 | + priority: high | ||
| 70 | + author: | ||
| 71 | + name: k33g | ||
| 72 | + email: ph.charriere@gmail.com | ||
| 73 | + createdAt: 2026-11-14T18:37:23.000Z | ||
| 74 | + - id: 2 | ||
| 75 | + title: Decide - follow the new default (9931), keep 8080, or try both during a transition | ||
| 76 | + state: open | ||
| 77 | + priority: high | ||
| 78 | + author: | ||
| 79 | + name: k33g | ||
| 80 | + email: ph.charriere@gmail.com | ||
| 81 | + createdAt: 2026-11-14T18:37:23.000Z | ||
| 82 | + - id: 3 | ||
| 83 | + title: Engine - default address, fallback and start hint of llamacpp | ||
| 84 | + state: open | ||
| 85 | + priority: medium | ||
| 86 | + author: | ||
| 87 | + name: k33g | ||
| 88 | + email: ph.charriere@gmail.com | ||
| 89 | + createdAt: 2026-11-14T18:37:23.000Z | ||
| 90 | + - id: 4 | ||
| 91 | + title: Shipped files - agent.llamacpp.yaml, config.samples/agent.llamacpp.*, demos using llamacpp | ||
| 92 | + state: open | ||
| 93 | + priority: medium | ||
| 94 | + author: | ||
| 95 | + name: k33g | ||
| 96 | + email: ph.charriere@gmail.com | ||
| 97 | + createdAt: 2026-11-14T18:37:23.000Z | ||
| 98 | + - id: 5 | ||
| 99 | + title: Docs EN+FR - run-with-llama-cpp, configuration (providers table), cli (warning example), container and sandbox guides | ||
| 100 | + state: open | ||
| 101 | + priority: medium | ||
| 102 | + author: | ||
| 103 | + name: k33g | ||
| 104 | + email: ph.charriere@gmail.com | ||
| 105 | + createdAt: 2026-11-14T18:37:23.000Z | ||
| 106 | + - id: 6 | ||
| 107 | + title: Docker Sandbox - the port in the mini-me kit's network policy, if 8080 is ever added there (mini-me-kit repository) | ||
| 108 | + state: open | ||
| 109 | + priority: low | ||
| 110 | + author: | ||
| 111 | + name: k33g | ||
| 112 | + email: ph.charriere@gmail.com | ||
| 113 | + createdAt: 2026-11-14T18:37:23.000Z | ||
| 114 | +comments: [] | ||
modified
agent.llamacpp.yaml +4 -2 | @@ -9,8 +9,10 @@ model: jetbrains/mellum2-12b-a2.5b-instruct-gguf-q4_k_m:Q4_K_M | ||
| 9 | 9 | # llama-server's default is 127.0.0.1:8080; the OpenAI routes sit under /v1. |
| 10 | 10 | baseUrl: http://127.0.0.1:8080/v1 |
| 11 | 11 | |
| 12 | -# No fallback: llama-server is wherever you started it. | |
| 13 | -fallback: "" | |
| 12 | +# No fallback line: when baseUrl does not answer, mm tries llama-server on the | |
| 13 | +# host, http://host.docker.internal:8080/v1 — what mm in a container or a | |
| 14 | +# sandbox needs (start llama-server with --host 0.0.0.0 there). fallback: "" | |
| 15 | +# turns that off. | |
| 14 | 16 | |
| 15 | 17 | # Only when llama-server was started with --api-key; unset otherwise. |
| 16 | 18 | # apiKeyEnv: LLAMA_API_KEY |
| @@ -9,8 +9,10 @@ model: jetbrains/mellum2-12b-a2.5b-instruct-gguf-q4_k_m:Q4_K_M | |||
| 9 | # llama-server's default is 127.0.0.1:8080; the OpenAI routes sit under /v1. | 9 | # llama-server's default is 127.0.0.1:8080; the OpenAI routes sit under /v1. |
| 10 | baseUrl: http://127.0.0.1:8080/v1 | 10 | baseUrl: http://127.0.0.1:8080/v1 |
| 11 | 11 | ||
| 12 | -# No fallback: llama-server is wherever you started it. | 12 | +# No fallback line: when baseUrl does not answer, mm tries llama-server on the |
| 13 | -fallback: "" | 13 | +# host, http://host.docker.internal:8080/v1 — what mm in a container or a |
| 14 | +# sandbox needs (start llama-server with --host 0.0.0.0 there). fallback: "" | ||
| 15 | +# turns that off. | ||
| 14 | 16 | ||
| 15 | # Only when llama-server was started with --api-key; unset otherwise. | 17 | # Only when llama-server was started with --api-key; unset otherwise. |
| 16 | # apiKeyEnv: LLAMA_API_KEY | 18 | # apiKeyEnv: LLAMA_API_KEY |
modified
docs/en/how-to/run-in-a-container.md +2 -2 | @@ -68,9 +68,9 @@ The project is mounted at the same path as on your machine, so the paths the edi | ||
| 68 | 68 | |
| 69 | 69 | ## Reach the model |
| 70 | 70 | |
| 71 | -From the container, `localhost` is the container. `dmr`, `llmman` and `ollama` fall back on `host.docker.internal` by themselves when their default address does not answer, as long as the agent file sets no `baseUrl`. The compose file makes that name known on Linux too. | |
| 71 | +From the container, `localhost` is the container. `dmr`, `llmman`, `ollama`, `kronk` and `llamacpp` fall back on `host.docker.internal` by themselves when their default address does not answer, as long as the agent file sets no `baseUrl`. The compose file makes that name known on Linux too. | |
| 72 | 72 | |
| 73 | -- **`llamacpp`** has no such fallback: set `baseUrl: http://host.docker.internal:8080/v1`. | |
| 73 | +- **`llamacpp`**: on Linux, start llama-server with `--host 0.0.0.0`, as it listens on the loopback only by default (see the last point). Files written before v1.1.0 may say `fallback: ""`: remove that line. | |
| 74 | 74 | - **An agent file with a `baseUrl` on `localhost` or `127.0.0.1`:** replace the host with `host.docker.internal`, or add a `fallback`. |
| 75 | 75 | - **A server on Linux that only listens on `127.0.0.1`:** make it listen on an address the container can reach. `host.docker.internal` is then the host's gateway, not its loopback. |
| 76 | 76 | |
| @@ -68,9 +68,9 @@ The project is mounted at the same path as on your machine, so the paths the edi | |||
| 68 | 68 | ||
| 69 | ## Reach the model | 69 | ## Reach the model |
| 70 | 70 | ||
| 71 | -From the container, `localhost` is the container. `dmr`, `llmman` and `ollama` fall back on `host.docker.internal` by themselves when their default address does not answer, as long as the agent file sets no `baseUrl`. The compose file makes that name known on Linux too. | 71 | +From the container, `localhost` is the container. `dmr`, `llmman`, `ollama`, `kronk` and `llamacpp` fall back on `host.docker.internal` by themselves when their default address does not answer, as long as the agent file sets no `baseUrl`. The compose file makes that name known on Linux too. |
| 72 | 72 | ||
| 73 | -- **`llamacpp`** has no such fallback: set `baseUrl: http://host.docker.internal:8080/v1`. | 73 | +- **`llamacpp`**: on Linux, start llama-server with `--host 0.0.0.0`, as it listens on the loopback only by default (see the last point). Files written before v1.1.0 may say `fallback: ""`: remove that line. |
| 74 | - **An agent file with a `baseUrl` on `localhost` or `127.0.0.1`:** replace the host with `host.docker.internal`, or add a `fallback`. | 74 | - **An agent file with a `baseUrl` on `localhost` or `127.0.0.1`:** replace the host with `host.docker.internal`, or add a `fallback`. |
| 75 | - **A server on Linux that only listens on `127.0.0.1`:** make it listen on an address the container can reach. `host.docker.internal` is then the host's gateway, not its loopback. | 75 | - **A server on Linux that only listens on `127.0.0.1`:** make it listen on an address the container can reach. `host.docker.internal` is then the host's gateway, not its loopback. |
| 76 | 76 | ||
modified
docs/en/how-to/run-in-a-docker-sandbox.md +1 -1 | @@ -203,7 +203,7 @@ Inside a sandbox `localhost` is the sandbox itself. Your model server keeps runn | ||
| 203 | 203 | |
| 204 | 204 | - The `mini-me` kit's network policy allows **`host.docker.internal:12434`** (Docker Model Runner), **`:11434`** (Ollama) and **`:17434`** (llmman). `agent.dmr.yaml` already falls back to `http://host.docker.internal:12434/engines/v1`; the configurations shipped in `demos/use-with-sbx/` use llmman (`fallback: http://host.docker.internal:17434/v1`). |
| 205 | 205 | - Kronk (`:11435`) is not in that list: allow `localhost:11435` in the policy, and start Kronk on the host with `--api-host 0.0.0.0:11435` — it listens on the loopback only otherwise. See [How to run mini-me on Kronk](run-with-kronk.md). |
| 206 | -- For another port — llama-server's `8080`, for instance — add it to the kit's `network-policy` capability, or allow it for one sandbox: | |
| 206 | +- For another port — llama-server's `8080`, for instance, which mm tries on its own (`http://host.docker.internal:8080/v1`) when started on the host with `--host 0.0.0.0` — add it to the kit's `network-policy` capability, or allow it for one sandbox: | |
| 207 | 207 | |
| 208 | 208 | ```bash |
| 209 | 209 | sbx policy allow network host.docker.internal:8080 |
| @@ -203,7 +203,7 @@ Inside a sandbox `localhost` is the sandbox itself. Your model server keeps runn | |||
| 203 | 203 | ||
| 204 | - The `mini-me` kit's network policy allows **`host.docker.internal:12434`** (Docker Model Runner), **`:11434`** (Ollama) and **`:17434`** (llmman). `agent.dmr.yaml` already falls back to `http://host.docker.internal:12434/engines/v1`; the configurations shipped in `demos/use-with-sbx/` use llmman (`fallback: http://host.docker.internal:17434/v1`). | 204 | - The `mini-me` kit's network policy allows **`host.docker.internal:12434`** (Docker Model Runner), **`:11434`** (Ollama) and **`:17434`** (llmman). `agent.dmr.yaml` already falls back to `http://host.docker.internal:12434/engines/v1`; the configurations shipped in `demos/use-with-sbx/` use llmman (`fallback: http://host.docker.internal:17434/v1`). |
| 205 | - Kronk (`:11435`) is not in that list: allow `localhost:11435` in the policy, and start Kronk on the host with `--api-host 0.0.0.0:11435` — it listens on the loopback only otherwise. See [How to run mini-me on Kronk](run-with-kronk.md). | 205 | - Kronk (`:11435`) is not in that list: allow `localhost:11435` in the policy, and start Kronk on the host with `--api-host 0.0.0.0:11435` — it listens on the loopback only otherwise. See [How to run mini-me on Kronk](run-with-kronk.md). |
| 206 | -- For another port — llama-server's `8080`, for instance — add it to the kit's `network-policy` capability, or allow it for one sandbox: | 206 | +- For another port — llama-server's `8080`, for instance, which mm tries on its own (`http://host.docker.internal:8080/v1`) when started on the host with `--host 0.0.0.0` — add it to the kit's `network-policy` capability, or allow it for one sandbox: |
| 207 | 207 | ||
| 208 | ```bash | 208 | ```bash |
| 209 | sbx policy allow network host.docker.internal:8080 | 209 | sbx policy allow network host.docker.internal:8080 |
modified
docs/en/how-to/run-with-llama-cpp.md +1 -0 | @@ -23,6 +23,7 @@ This guide shows how to point `mm` at a `llama-server` you start yourself. It as | ||
| 23 | 23 | ## Variants |
| 24 | 24 | |
| 25 | 25 | - **Different port or host.** Set `baseUrl` in the YAML to `http://<host>:<port>/v1`, or override it for one run with `AGENT_BASE_URL=http://<host>:<port>/v1 ./mm agent.llamacpp.yaml`. An environment override is taken as-is, without the fallback probe. |
| 26 | +- **From a container or a Docker Sandbox.** When `baseUrl` does not answer, mm tries `http://host.docker.internal:8080/v1`, llama-server on the host. Start it there with `--host 0.0.0.0`: by default it listens on the loopback only, which a container on Linux or a sandbox cannot reach. In a sandbox, also allow the port: `sbx policy allow network host.docker.internal:8080`. `fallback: ""` turns the fallback off. See [run mini-me in a container](run-in-a-container.md) and [run mini-me in a Docker Sandbox](run-in-a-docker-sandbox.md). | |
| 26 | 27 | - **`autoPull: true`.** llama-server cannot download a model over its API: it serves the one it was started with. `-hf <repo>:<quant>` (step 1) is what downloads it. With `autoPull` on and a `model:` the server does not list, mm says so at start-up and goes on. See [`autoPull`](../reference/configuration.md). |
| 27 | 28 | - **Server started with `--api-key`.** Export the key in `LLAMA_API_KEY` (the provider's default variable) or name another variable under `apiKeyEnv`. The key itself never goes in the YAML. |
| 28 | 29 | - **Keep `agent.yaml` and switch provider for one run.** `AGENT_PROVIDER=llamacpp ./mm` works as long as `agent.yaml` leaves `baseUrl` empty; an explicit DMR URL in the file would still be honoured and point at port 12434. |
| @@ -23,6 +23,7 @@ This guide shows how to point `mm` at a `llama-server` you start yourself. It as | |||
| 23 | ## Variants | 23 | ## Variants |
| 24 | 24 | ||
| 25 | - **Different port or host.** Set `baseUrl` in the YAML to `http://<host>:<port>/v1`, or override it for one run with `AGENT_BASE_URL=http://<host>:<port>/v1 ./mm agent.llamacpp.yaml`. An environment override is taken as-is, without the fallback probe. | 25 | - **Different port or host.** Set `baseUrl` in the YAML to `http://<host>:<port>/v1`, or override it for one run with `AGENT_BASE_URL=http://<host>:<port>/v1 ./mm agent.llamacpp.yaml`. An environment override is taken as-is, without the fallback probe. |
| 26 | +- **From a container or a Docker Sandbox.** When `baseUrl` does not answer, mm tries `http://host.docker.internal:8080/v1`, llama-server on the host. Start it there with `--host 0.0.0.0`: by default it listens on the loopback only, which a container on Linux or a sandbox cannot reach. In a sandbox, also allow the port: `sbx policy allow network host.docker.internal:8080`. `fallback: ""` turns the fallback off. See [run mini-me in a container](run-in-a-container.md) and [run mini-me in a Docker Sandbox](run-in-a-docker-sandbox.md). | ||
| 26 | - **`autoPull: true`.** llama-server cannot download a model over its API: it serves the one it was started with. `-hf <repo>:<quant>` (step 1) is what downloads it. With `autoPull` on and a `model:` the server does not list, mm says so at start-up and goes on. See [`autoPull`](../reference/configuration.md). | 27 | - **`autoPull: true`.** llama-server cannot download a model over its API: it serves the one it was started with. `-hf <repo>:<quant>` (step 1) is what downloads it. With `autoPull` on and a `model:` the server does not list, mm says so at start-up and goes on. See [`autoPull`](../reference/configuration.md). |
| 27 | - **Server started with `--api-key`.** Export the key in `LLAMA_API_KEY` (the provider's default variable) or name another variable under `apiKeyEnv`. The key itself never goes in the YAML. | 28 | - **Server started with `--api-key`.** Export the key in `LLAMA_API_KEY` (the provider's default variable) or name another variable under `apiKeyEnv`. The key itself never goes in the YAML. |
| 28 | - **Keep `agent.yaml` and switch provider for one run.** `AGENT_PROVIDER=llamacpp ./mm` works as long as `agent.yaml` leaves `baseUrl` empty; an explicit DMR URL in the file would still be honoured and point at port 12434. | 29 | - **Keep `agent.yaml` and switch provider for one run.** `AGENT_PROVIDER=llamacpp ./mm` works as long as `agent.yaml` leaves `baseUrl` empty; an explicit DMR URL in the file would still be honoured and point at port 12434. |
modified
docs/en/reference/cli.md +2 -2 | @@ -104,7 +104,7 @@ Printed on stdout in terminal mode, on stderr in ACP mode. Dimmed when stdout is | ||
| 104 | 104 | ### Example |
| 105 | 105 | |
| 106 | 106 | ``` |
| 107 | -[warning: llamacpp: nothing answers at http://127.0.0.1:8080/v1 — start it: llama-server -m <model.gguf> --jinja --port 8080] | |
| 107 | +[warning: llamacpp: nothing answers at http://host.docker.internal:8080/v1 — start it: llama-server -m <model.gguf> --jinja --port 8080 (add --host 0.0.0.0 when mm runs in a container or a sandbox)] | |
| 108 | 108 | mm v0.1.7 | config: agent.llamacpp.yaml | provider: llamacpp | model: jetbrains/mellum2-12b-a2.5b-instruct-gguf-q4_k_m:Q4_K_M | ctx: unknown | tools: bash, read_file, write_file, edit_file | skills: 0 | yolo: on |
| 109 | 109 | ``` |
| 110 | 110 | |
| @@ -240,7 +240,7 @@ An agent file outside the workspace only gives a warning: see [when the agent fi | ||
| 240 | 240 | |------|----------------------|---------| |
| 241 | 241 | | `--project yes\|no` | Keep everything in a `.mm` folder? — asked first. `yes`: the file is `.mm/agent.yaml` (the folder is created), its paths are written from the project root (`skillsDir: .mm/skills`), and `mm` / `mm tui` started there find it with no argument | `no` | |
| 242 | 242 | | `--provider` | Model server: `llmman`, `ollama`, `dmr`, `llamacpp`, `kronk`, `openai` | the first local one whose server answers, else `llmman` (`openai` is never probed: its default address is the OpenAI API) | |
| 243 | -| `--base-url` | `openai` only: Endpoint — the service's OpenAI-compatible address (OpenAI, Cerebras, Hugging Face…); for the other providers, not asked | `https://api.openai.com/v1` for `openai`; otherwise the provider's address, or its fallback when it does not answer. Written as `baseUrl` unless it is the default | | |
| 243 | +| `--base-url` | `openai` only: Endpoint — the service's OpenAI-compatible address (OpenAI, Cerebras, Hugging Face…); for the other providers, not asked | `https://api.openai.com/v1` for `openai`; otherwise `AGENT_BASE_URL` when set, else the first of the provider's local addresses whose model list answers — its default, then the same with `127.0.0.1` when the default names `localhost` — and its container fallback (`host.docker.internal`) only when none does. The model question names the address its list comes from (`Model? (listed from …)`). Written as `baseUrl` unless it is the default | | |
| 244 | 244 | | `--api-key-env` | `openai` only: Environment variable that holds the API key | `OPENAI_API_KEY`. Written as `apiKeyEnv` unless it is the default | |
| 245 | 245 | | `--model` | Model: a list of the server's models (`/api/tags` for llmman and Ollama, `/models` for the others; 5 s for a local server, 20 s for `openai`), or a name to type when there is no list — the question says why (`<VARIABLE> is not set: no list`, or the server's error). For `openai` the list is asked with the key read from the variable named above, and not asked at all when that variable is empty | the first of the list | |
| 246 | 246 | | `--family` | Model family | detected from the model's name, then from the server's family name | |
| @@ -104,7 +104,7 @@ Printed on stdout in terminal mode, on stderr in ACP mode. Dimmed when stdout is | |||
| 104 | ### Example | 104 | ### Example |
| 105 | 105 | ||
| 106 | ``` | 106 | ``` |
| 107 | -[warning: llamacpp: nothing answers at http://127.0.0.1:8080/v1 — start it: llama-server -m <model.gguf> --jinja --port 8080] | 107 | +[warning: llamacpp: nothing answers at http://host.docker.internal:8080/v1 — start it: llama-server -m <model.gguf> --jinja --port 8080 (add --host 0.0.0.0 when mm runs in a container or a sandbox)] |
| 108 | mm v0.1.7 | config: agent.llamacpp.yaml | provider: llamacpp | model: jetbrains/mellum2-12b-a2.5b-instruct-gguf-q4_k_m:Q4_K_M | ctx: unknown | tools: bash, read_file, write_file, edit_file | skills: 0 | yolo: on | 108 | mm v0.1.7 | config: agent.llamacpp.yaml | provider: llamacpp | model: jetbrains/mellum2-12b-a2.5b-instruct-gguf-q4_k_m:Q4_K_M | ctx: unknown | tools: bash, read_file, write_file, edit_file | skills: 0 | yolo: on |
| 109 | ``` | 109 | ``` |
| 110 | 110 | ||
| @@ -240,7 +240,7 @@ An agent file outside the workspace only gives a warning: see [when the agent fi | |||
| 240 | |------|----------------------|---------| | 240 | |------|----------------------|---------| |
| 241 | | `--project yes\|no` | Keep everything in a `.mm` folder? — asked first. `yes`: the file is `.mm/agent.yaml` (the folder is created), its paths are written from the project root (`skillsDir: .mm/skills`), and `mm` / `mm tui` started there find it with no argument | `no` | | 241 | | `--project yes\|no` | Keep everything in a `.mm` folder? — asked first. `yes`: the file is `.mm/agent.yaml` (the folder is created), its paths are written from the project root (`skillsDir: .mm/skills`), and `mm` / `mm tui` started there find it with no argument | `no` | |
| 242 | | `--provider` | Model server: `llmman`, `ollama`, `dmr`, `llamacpp`, `kronk`, `openai` | the first local one whose server answers, else `llmman` (`openai` is never probed: its default address is the OpenAI API) | | 242 | | `--provider` | Model server: `llmman`, `ollama`, `dmr`, `llamacpp`, `kronk`, `openai` | the first local one whose server answers, else `llmman` (`openai` is never probed: its default address is the OpenAI API) | |
| 243 | -| `--base-url` | `openai` only: Endpoint — the service's OpenAI-compatible address (OpenAI, Cerebras, Hugging Face…); for the other providers, not asked | `https://api.openai.com/v1` for `openai`; otherwise the provider's address, or its fallback when it does not answer. Written as `baseUrl` unless it is the default | | 243 | +| `--base-url` | `openai` only: Endpoint — the service's OpenAI-compatible address (OpenAI, Cerebras, Hugging Face…); for the other providers, not asked | `https://api.openai.com/v1` for `openai`; otherwise `AGENT_BASE_URL` when set, else the first of the provider's local addresses whose model list answers — its default, then the same with `127.0.0.1` when the default names `localhost` — and its container fallback (`host.docker.internal`) only when none does. The model question names the address its list comes from (`Model? (listed from …)`). Written as `baseUrl` unless it is the default | |
| 244 | | `--api-key-env` | `openai` only: Environment variable that holds the API key | `OPENAI_API_KEY`. Written as `apiKeyEnv` unless it is the default | | 244 | | `--api-key-env` | `openai` only: Environment variable that holds the API key | `OPENAI_API_KEY`. Written as `apiKeyEnv` unless it is the default | |
| 245 | | `--model` | Model: a list of the server's models (`/api/tags` for llmman and Ollama, `/models` for the others; 5 s for a local server, 20 s for `openai`), or a name to type when there is no list — the question says why (`<VARIABLE> is not set: no list`, or the server's error). For `openai` the list is asked with the key read from the variable named above, and not asked at all when that variable is empty | the first of the list | | 245 | | `--model` | Model: a list of the server's models (`/api/tags` for llmman and Ollama, `/models` for the others; 5 s for a local server, 20 s for `openai`), or a name to type when there is no list — the question says why (`<VARIABLE> is not set: no list`, or the server's error). For `openai` the list is asked with the key read from the variable named above, and not asked at all when that variable is empty | the first of the list | |
| 246 | | `--family` | Model family | detected from the model's name, then from the server's family name | | 246 | | `--family` | Model family | detected from the model's name, then from the server's family name | |
modified
docs/en/reference/configuration.md +2 -2 | @@ -197,7 +197,7 @@ tools: | ||
| 197 | 197 | | Provider | `baseUrl` | `fallback` | `apiKeyEnv` | Key required | |
| 198 | 198 | |----------|-----------|------------|-------------|--------------| |
| 199 | 199 | | `dmr` | `http://localhost:12434/engines/v1` | `http://host.docker.internal:12434/engines/v1` | none | no | |
| 200 | -| `llamacpp` | `http://127.0.0.1:8080/v1` | none | `LLAMA_API_KEY` | no | | |
| 200 | +| `llamacpp` | `http://127.0.0.1:8080/v1` | `http://host.docker.internal:8080/v1` | `LLAMA_API_KEY` | no | | |
| 201 | 201 | | `llmman` | `http://127.0.0.1:17434/v1` | `http://host.docker.internal:17434/v1` | `LLMMAN_API_KEY` | no | |
| 202 | 202 | | `ollama` | `http://localhost:11434/v1` | `http://host.docker.internal:11434/v1` | `OLLAMA_API_KEY` | no | |
| 203 | 203 | | `kronk` | `http://127.0.0.1:11435/v1` | `http://host.docker.internal:11435/v1` | `KRONK_TOKEN` | no — only Kronk's `authenticated` and `full-protected` modes check it | |
| @@ -477,7 +477,7 @@ A start-up warning, not an error, is printed when `context.enabled` is `true`, t | ||
| 477 | 477 | | File | Purpose | |
| 478 | 478 | |------|---------| |
| 479 | 479 | | `agent.yaml` | Docker Model Runner set-up: `provider: dmr`, `maxTurns: 40`, `displayCommands: true`, compression off, a system prompt named "Bob" that describes the skills and file-editing rules. | |
| 480 | -| `agent.llamacpp.yaml` | llama.cpp set-up: `provider: llamacpp`, `baseUrl: http://127.0.0.1:8080/v1`, `fallback: ""`, compression on. | | |
| 480 | +| `agent.llamacpp.yaml` | llama.cpp set-up: `provider: llamacpp`, `baseUrl: http://127.0.0.1:8080/v1`, compression on. | | |
| 481 | 481 | |
| 482 | 482 | ### Example |
| 483 | 483 | |
| @@ -197,7 +197,7 @@ tools: | |||
| 197 | | Provider | `baseUrl` | `fallback` | `apiKeyEnv` | Key required | | 197 | | Provider | `baseUrl` | `fallback` | `apiKeyEnv` | Key required | |
| 198 | |----------|-----------|------------|-------------|--------------| | 198 | |----------|-----------|------------|-------------|--------------| |
| 199 | | `dmr` | `http://localhost:12434/engines/v1` | `http://host.docker.internal:12434/engines/v1` | none | no | | 199 | | `dmr` | `http://localhost:12434/engines/v1` | `http://host.docker.internal:12434/engines/v1` | none | no | |
| 200 | -| `llamacpp` | `http://127.0.0.1:8080/v1` | none | `LLAMA_API_KEY` | no | | 200 | +| `llamacpp` | `http://127.0.0.1:8080/v1` | `http://host.docker.internal:8080/v1` | `LLAMA_API_KEY` | no | |
| 201 | | `llmman` | `http://127.0.0.1:17434/v1` | `http://host.docker.internal:17434/v1` | `LLMMAN_API_KEY` | no | | 201 | | `llmman` | `http://127.0.0.1:17434/v1` | `http://host.docker.internal:17434/v1` | `LLMMAN_API_KEY` | no | |
| 202 | | `ollama` | `http://localhost:11434/v1` | `http://host.docker.internal:11434/v1` | `OLLAMA_API_KEY` | no | | 202 | | `ollama` | `http://localhost:11434/v1` | `http://host.docker.internal:11434/v1` | `OLLAMA_API_KEY` | no | |
| 203 | | `kronk` | `http://127.0.0.1:11435/v1` | `http://host.docker.internal:11435/v1` | `KRONK_TOKEN` | no — only Kronk's `authenticated` and `full-protected` modes check it | | 203 | | `kronk` | `http://127.0.0.1:11435/v1` | `http://host.docker.internal:11435/v1` | `KRONK_TOKEN` | no — only Kronk's `authenticated` and `full-protected` modes check it | |
| @@ -477,7 +477,7 @@ A start-up warning, not an error, is printed when `context.enabled` is `true`, t | |||
| 477 | | File | Purpose | | 477 | | File | Purpose | |
| 478 | |------|---------| | 478 | |------|---------| |
| 479 | | `agent.yaml` | Docker Model Runner set-up: `provider: dmr`, `maxTurns: 40`, `displayCommands: true`, compression off, a system prompt named "Bob" that describes the skills and file-editing rules. | | 479 | | `agent.yaml` | Docker Model Runner set-up: `provider: dmr`, `maxTurns: 40`, `displayCommands: true`, compression off, a system prompt named "Bob" that describes the skills and file-editing rules. | |
| 480 | -| `agent.llamacpp.yaml` | llama.cpp set-up: `provider: llamacpp`, `baseUrl: http://127.0.0.1:8080/v1`, `fallback: ""`, compression on. | | 480 | +| `agent.llamacpp.yaml` | llama.cpp set-up: `provider: llamacpp`, `baseUrl: http://127.0.0.1:8080/v1`, compression on. | |
| 481 | 481 | ||
| 482 | ### Example | 482 | ### Example |
| 483 | 483 | ||
modified
docs/en/reference/mcp-configuration.md +2 -2 | @@ -78,7 +78,7 @@ The shipped `agent.lsp.yaml` is `agent.dmr.yaml` with this block on (gopls activ | ||
| 78 | 78 | | Provider | `baseUrl` | `fallback` | `apiKeyEnv` | Key required | |
| 79 | 79 | |----------|-----------|------------|-------------|--------------| |
| 80 | 80 | | `dmr` | `http://localhost:12434/engines/v1` | `http://host.docker.internal:12434/engines/v1` | none | no | |
| 81 | -| `llamacpp` | `http://127.0.0.1:8080/v1` | none | `LLAMA_API_KEY` | no | | |
| 81 | +| `llamacpp` | `http://127.0.0.1:8080/v1` | `http://host.docker.internal:8080/v1` | `LLAMA_API_KEY` | no | | |
| 82 | 82 | | `llmman` | `http://127.0.0.1:17434/v1` | `http://host.docker.internal:17434/v1` | `LLMMAN_API_KEY` | no | |
| 83 | 83 | | `ollama` | `http://localhost:11434/v1` | `http://host.docker.internal:11434/v1` | `OLLAMA_API_KEY` | no | |
| 84 | 84 | |
| @@ -114,7 +114,7 @@ A start-up warning, not an error, is printed when `context.enabled` is `true`, t | ||
| 114 | 114 | | File | Purpose | |
| 115 | 115 | |------|---------| |
| 116 | 116 | | `agent.yaml` | Docker Model Runner set-up: `provider: dmr`, `maxTurns: 40`, `displayCommands: true`, compression off, a system prompt named "Bob" that describes the skills and file-editing rules. | |
| 117 | -| `agent.llamacpp.yaml` | llama.cpp set-up: `provider: llamacpp`, `baseUrl: http://127.0.0.1:8080/v1`, `fallback: ""`, compression on. | | |
| 117 | +| `agent.llamacpp.yaml` | llama.cpp set-up: `provider: llamacpp`, `baseUrl: http://127.0.0.1:8080/v1`, compression on. | | |
| 118 | 118 | |
| 119 | 119 | ### Example |
| 120 | 120 | |
| @@ -78,7 +78,7 @@ The shipped `agent.lsp.yaml` is `agent.dmr.yaml` with this block on (gopls activ | |||
| 78 | | Provider | `baseUrl` | `fallback` | `apiKeyEnv` | Key required | | 78 | | Provider | `baseUrl` | `fallback` | `apiKeyEnv` | Key required | |
| 79 | |----------|-----------|------------|-------------|--------------| | 79 | |----------|-----------|------------|-------------|--------------| |
| 80 | | `dmr` | `http://localhost:12434/engines/v1` | `http://host.docker.internal:12434/engines/v1` | none | no | | 80 | | `dmr` | `http://localhost:12434/engines/v1` | `http://host.docker.internal:12434/engines/v1` | none | no | |
| 81 | -| `llamacpp` | `http://127.0.0.1:8080/v1` | none | `LLAMA_API_KEY` | no | | 81 | +| `llamacpp` | `http://127.0.0.1:8080/v1` | `http://host.docker.internal:8080/v1` | `LLAMA_API_KEY` | no | |
| 82 | | `llmman` | `http://127.0.0.1:17434/v1` | `http://host.docker.internal:17434/v1` | `LLMMAN_API_KEY` | no | | 82 | | `llmman` | `http://127.0.0.1:17434/v1` | `http://host.docker.internal:17434/v1` | `LLMMAN_API_KEY` | no | |
| 83 | | `ollama` | `http://localhost:11434/v1` | `http://host.docker.internal:11434/v1` | `OLLAMA_API_KEY` | no | | 83 | | `ollama` | `http://localhost:11434/v1` | `http://host.docker.internal:11434/v1` | `OLLAMA_API_KEY` | no | |
| 84 | 84 | ||
| @@ -114,7 +114,7 @@ A start-up warning, not an error, is printed when `context.enabled` is `true`, t | |||
| 114 | | File | Purpose | | 114 | | File | Purpose | |
| 115 | |------|---------| | 115 | |------|---------| |
| 116 | | `agent.yaml` | Docker Model Runner set-up: `provider: dmr`, `maxTurns: 40`, `displayCommands: true`, compression off, a system prompt named "Bob" that describes the skills and file-editing rules. | | 116 | | `agent.yaml` | Docker Model Runner set-up: `provider: dmr`, `maxTurns: 40`, `displayCommands: true`, compression off, a system prompt named "Bob" that describes the skills and file-editing rules. | |
| 117 | -| `agent.llamacpp.yaml` | llama.cpp set-up: `provider: llamacpp`, `baseUrl: http://127.0.0.1:8080/v1`, `fallback: ""`, compression on. | | 117 | +| `agent.llamacpp.yaml` | llama.cpp set-up: `provider: llamacpp`, `baseUrl: http://127.0.0.1:8080/v1`, compression on. | |
| 118 | 118 | ||
| 119 | ### Example | 119 | ### Example |
| 120 | 120 | ||
modified
docs/fr/how-to/run-in-a-container.md +2 -2 | @@ -68,9 +68,9 @@ Le projet est monté au même chemin que sur votre machine : les chemins envoyé | ||
| 68 | 68 | |
| 69 | 69 | ## Joindre le modèle |
| 70 | 70 | |
| 71 | -Depuis le conteneur, `localhost` désigne le conteneur. `dmr`, `llmman` et `ollama` se rabattent d'eux-mêmes sur `host.docker.internal` quand leur adresse par défaut ne répond pas, tant que le fichier d'agent ne définit pas de `baseUrl`. Le fichier compose fait aussi connaître ce nom sous Linux. | |
| 71 | +Depuis le conteneur, `localhost` désigne le conteneur. `dmr`, `llmman`, `ollama`, `kronk` et `llamacpp` se rabattent d'eux-mêmes sur `host.docker.internal` quand leur adresse par défaut ne répond pas, tant que le fichier d'agent ne définit pas de `baseUrl`. Le fichier compose fait aussi connaître ce nom sous Linux. | |
| 72 | 72 | |
| 73 | -- **`llamacpp`** n'a pas ce repli : définissez `baseUrl: http://host.docker.internal:8080/v1`. | |
| 73 | +- **`llamacpp`** : sous Linux, lancez llama-server avec `--host 0.0.0.0`, car par défaut il n'écoute que sur la boucle locale (voir le dernier point). Les fichiers écrits avant la v1.1.0 peuvent contenir `fallback: ""` : retirez cette ligne. | |
| 74 | 74 | - **Un fichier d'agent avec un `baseUrl` sur `localhost` ou `127.0.0.1` :** remplacez l'hôte par `host.docker.internal`, ou ajoutez un `fallback`. |
| 75 | 75 | - **Un serveur sous Linux qui n'écoute que sur `127.0.0.1` :** faites-le écouter sur une adresse joignable par le conteneur. `host.docker.internal` y désigne la passerelle de l'hôte, pas sa boucle locale. |
| 76 | 76 | |
| @@ -68,9 +68,9 @@ Le projet est monté au même chemin que sur votre machine : les chemins envoyé | |||
| 68 | 68 | ||
| 69 | ## Joindre le modèle | 69 | ## Joindre le modèle |
| 70 | 70 | ||
| 71 | -Depuis le conteneur, `localhost` désigne le conteneur. `dmr`, `llmman` et `ollama` se rabattent d'eux-mêmes sur `host.docker.internal` quand leur adresse par défaut ne répond pas, tant que le fichier d'agent ne définit pas de `baseUrl`. Le fichier compose fait aussi connaître ce nom sous Linux. | 71 | +Depuis le conteneur, `localhost` désigne le conteneur. `dmr`, `llmman`, `ollama`, `kronk` et `llamacpp` se rabattent d'eux-mêmes sur `host.docker.internal` quand leur adresse par défaut ne répond pas, tant que le fichier d'agent ne définit pas de `baseUrl`. Le fichier compose fait aussi connaître ce nom sous Linux. |
| 72 | 72 | ||
| 73 | -- **`llamacpp`** n'a pas ce repli : définissez `baseUrl: http://host.docker.internal:8080/v1`. | 73 | +- **`llamacpp`** : sous Linux, lancez llama-server avec `--host 0.0.0.0`, car par défaut il n'écoute que sur la boucle locale (voir le dernier point). Les fichiers écrits avant la v1.1.0 peuvent contenir `fallback: ""` : retirez cette ligne. |
| 74 | - **Un fichier d'agent avec un `baseUrl` sur `localhost` ou `127.0.0.1` :** remplacez l'hôte par `host.docker.internal`, ou ajoutez un `fallback`. | 74 | - **Un fichier d'agent avec un `baseUrl` sur `localhost` ou `127.0.0.1` :** remplacez l'hôte par `host.docker.internal`, ou ajoutez un `fallback`. |
| 75 | - **Un serveur sous Linux qui n'écoute que sur `127.0.0.1` :** faites-le écouter sur une adresse joignable par le conteneur. `host.docker.internal` y désigne la passerelle de l'hôte, pas sa boucle locale. | 75 | - **Un serveur sous Linux qui n'écoute que sur `127.0.0.1` :** faites-le écouter sur une adresse joignable par le conteneur. `host.docker.internal` y désigne la passerelle de l'hôte, pas sa boucle locale. |
| 76 | 76 | ||
modified
docs/fr/how-to/run-in-a-docker-sandbox.md +1 -1 | @@ -203,7 +203,7 @@ Dans un sandbox, `localhost` est le sandbox lui-même. Votre serveur de modèles | ||
| 203 | 203 | |
| 204 | 204 | - La politique réseau du kit `mini-me` autorise **`host.docker.internal:12434`** (Docker Model Runner), **`:11434`** (Ollama) et **`:17434`** (llmman). `agent.dmr.yaml` se replie déjà sur `http://host.docker.internal:12434/engines/v1` ; les configurations livrées dans `demos/use-with-sbx/` utilisent llmman (`fallback: http://host.docker.internal:17434/v1`). |
| 205 | 205 | - Kronk (`:11435`) n'est pas dans cette liste : autorisez `localhost:11435` dans la politique, et lancez Kronk sur l'hôte avec `--api-host 0.0.0.0:11435` — sinon il n'écoute que sur la boucle locale. Voir [Faire tourner mini-me sur Kronk](run-with-kronk.md). |
| 206 | -- Pour un autre port — le `8080` de llama-server, par exemple — ajoutez-le à la capacité `network-policy` du kit, ou autorisez-le pour un seul sandbox : | |
| 206 | +- Pour un autre port — le `8080` de llama-server, par exemple, que mm essaie de lui-même (`http://host.docker.internal:8080/v1`) quand il est lancé sur l'hôte avec `--host 0.0.0.0` — ajoutez-le à la capacité `network-policy` du kit, ou autorisez-le pour un seul sandbox : | |
| 207 | 207 | |
| 208 | 208 | ```bash |
| 209 | 209 | sbx policy allow network host.docker.internal:8080 |
| @@ -203,7 +203,7 @@ Dans un sandbox, `localhost` est le sandbox lui-même. Votre serveur de modèles | |||
| 203 | 203 | ||
| 204 | - La politique réseau du kit `mini-me` autorise **`host.docker.internal:12434`** (Docker Model Runner), **`:11434`** (Ollama) et **`:17434`** (llmman). `agent.dmr.yaml` se replie déjà sur `http://host.docker.internal:12434/engines/v1` ; les configurations livrées dans `demos/use-with-sbx/` utilisent llmman (`fallback: http://host.docker.internal:17434/v1`). | 204 | - La politique réseau du kit `mini-me` autorise **`host.docker.internal:12434`** (Docker Model Runner), **`:11434`** (Ollama) et **`:17434`** (llmman). `agent.dmr.yaml` se replie déjà sur `http://host.docker.internal:12434/engines/v1` ; les configurations livrées dans `demos/use-with-sbx/` utilisent llmman (`fallback: http://host.docker.internal:17434/v1`). |
| 205 | - Kronk (`:11435`) n'est pas dans cette liste : autorisez `localhost:11435` dans la politique, et lancez Kronk sur l'hôte avec `--api-host 0.0.0.0:11435` — sinon il n'écoute que sur la boucle locale. Voir [Faire tourner mini-me sur Kronk](run-with-kronk.md). | 205 | - Kronk (`:11435`) n'est pas dans cette liste : autorisez `localhost:11435` dans la politique, et lancez Kronk sur l'hôte avec `--api-host 0.0.0.0:11435` — sinon il n'écoute que sur la boucle locale. Voir [Faire tourner mini-me sur Kronk](run-with-kronk.md). |
| 206 | -- Pour un autre port — le `8080` de llama-server, par exemple — ajoutez-le à la capacité `network-policy` du kit, ou autorisez-le pour un seul sandbox : | 206 | +- Pour un autre port — le `8080` de llama-server, par exemple, que mm essaie de lui-même (`http://host.docker.internal:8080/v1`) quand il est lancé sur l'hôte avec `--host 0.0.0.0` — ajoutez-le à la capacité `network-policy` du kit, ou autorisez-le pour un seul sandbox : |
| 207 | 207 | ||
| 208 | ```bash | 208 | ```bash |
| 209 | sbx policy allow network host.docker.internal:8080 | 209 | sbx policy allow network host.docker.internal:8080 |
modified
docs/fr/how-to/run-with-llama-cpp.md +1 -0 | @@ -23,6 +23,7 @@ Ce guide montre comment pointer `mm` vers un `llama-server` que vous démarrez v | ||
| 23 | 23 | ## Variantes |
| 24 | 24 | |
| 25 | 25 | - **Autre port ou autre hôte.** Mettez `baseUrl` à `http://<hôte>:<port>/v1` dans le YAML, ou surchargez pour une seule exécution avec `AGENT_BASE_URL=http://<hôte>:<port>/v1 ./mm agent.llamacpp.yaml`. Une surcharge par l'environnement est prise telle quelle, sans sonde de repli. |
| 26 | +- **Depuis un conteneur ou un Docker Sandbox.** Quand `baseUrl` ne répond pas, mm essaie `http://host.docker.internal:8080/v1`, llama-server sur l'hôte. Lancez-le avec `--host 0.0.0.0` : par défaut il n'écoute que sur la boucle locale, qu'un conteneur sous Linux ou un sandbox ne peuvent pas joindre. Dans un sandbox, autorisez aussi le port : `sbx policy allow network host.docker.internal:8080`. `fallback: ""` coupe le repli. Voir [faire tourner mini-me dans un conteneur](run-in-a-container.md) et [faire tourner mini-me dans un Docker Sandbox](run-in-a-docker-sandbox.md). | |
| 26 | 27 | - **`autoPull: true`.** llama-server ne sait pas télécharger un modèle par son API : il sert celui avec lequel il a été lancé. C'est `-hf <dépôt>:<quant>` (étape 1) qui le télécharge. Avec `autoPull` actif et un `model:` que le serveur ne liste pas, mm le dit au démarrage et continue. Voir [`autoPull`](../reference/configuration.md). |
| 27 | 28 | - **Serveur démarré avec `--api-key`.** Exportez la clé dans `LLAMA_API_KEY` (la variable par défaut du fournisseur) ou nommez une autre variable dans `apiKeyEnv`. La clé elle-même ne va jamais dans le YAML. |
| 28 | 29 | - **Garder `agent.yaml` et changer de fournisseur pour une exécution.** `AGENT_PROVIDER=llamacpp ./mm` fonctionne tant qu'`agent.yaml` laisse `baseUrl` vide ; une URL DMR explicite dans le fichier serait respectée et pointerait toujours sur le port 12434. |
| @@ -23,6 +23,7 @@ Ce guide montre comment pointer `mm` vers un `llama-server` que vous démarrez v | |||
| 23 | ## Variantes | 23 | ## Variantes |
| 24 | 24 | ||
| 25 | - **Autre port ou autre hôte.** Mettez `baseUrl` à `http://<hôte>:<port>/v1` dans le YAML, ou surchargez pour une seule exécution avec `AGENT_BASE_URL=http://<hôte>:<port>/v1 ./mm agent.llamacpp.yaml`. Une surcharge par l'environnement est prise telle quelle, sans sonde de repli. | 25 | - **Autre port ou autre hôte.** Mettez `baseUrl` à `http://<hôte>:<port>/v1` dans le YAML, ou surchargez pour une seule exécution avec `AGENT_BASE_URL=http://<hôte>:<port>/v1 ./mm agent.llamacpp.yaml`. Une surcharge par l'environnement est prise telle quelle, sans sonde de repli. |
| 26 | +- **Depuis un conteneur ou un Docker Sandbox.** Quand `baseUrl` ne répond pas, mm essaie `http://host.docker.internal:8080/v1`, llama-server sur l'hôte. Lancez-le avec `--host 0.0.0.0` : par défaut il n'écoute que sur la boucle locale, qu'un conteneur sous Linux ou un sandbox ne peuvent pas joindre. Dans un sandbox, autorisez aussi le port : `sbx policy allow network host.docker.internal:8080`. `fallback: ""` coupe le repli. Voir [faire tourner mini-me dans un conteneur](run-in-a-container.md) et [faire tourner mini-me dans un Docker Sandbox](run-in-a-docker-sandbox.md). | ||
| 26 | - **`autoPull: true`.** llama-server ne sait pas télécharger un modèle par son API : il sert celui avec lequel il a été lancé. C'est `-hf <dépôt>:<quant>` (étape 1) qui le télécharge. Avec `autoPull` actif et un `model:` que le serveur ne liste pas, mm le dit au démarrage et continue. Voir [`autoPull`](../reference/configuration.md). | 27 | - **`autoPull: true`.** llama-server ne sait pas télécharger un modèle par son API : il sert celui avec lequel il a été lancé. C'est `-hf <dépôt>:<quant>` (étape 1) qui le télécharge. Avec `autoPull` actif et un `model:` que le serveur ne liste pas, mm le dit au démarrage et continue. Voir [`autoPull`](../reference/configuration.md). |
| 27 | - **Serveur démarré avec `--api-key`.** Exportez la clé dans `LLAMA_API_KEY` (la variable par défaut du fournisseur) ou nommez une autre variable dans `apiKeyEnv`. La clé elle-même ne va jamais dans le YAML. | 28 | - **Serveur démarré avec `--api-key`.** Exportez la clé dans `LLAMA_API_KEY` (la variable par défaut du fournisseur) ou nommez une autre variable dans `apiKeyEnv`. La clé elle-même ne va jamais dans le YAML. |
| 28 | - **Garder `agent.yaml` et changer de fournisseur pour une exécution.** `AGENT_PROVIDER=llamacpp ./mm` fonctionne tant qu'`agent.yaml` laisse `baseUrl` vide ; une URL DMR explicite dans le fichier serait respectée et pointerait toujours sur le port 12434. | 29 | - **Garder `agent.yaml` et changer de fournisseur pour une exécution.** `AGENT_PROVIDER=llamacpp ./mm` fonctionne tant qu'`agent.yaml` laisse `baseUrl` vide ; une URL DMR explicite dans le fichier serait respectée et pointerait toujours sur le port 12434. |
modified
docs/fr/reference/cli.md +2 -2 | @@ -104,7 +104,7 @@ Affichée sur stdout en mode terminal, sur stderr en mode ACP. Grisée quand std | ||
| 104 | 104 | ### Exemple |
| 105 | 105 | |
| 106 | 106 | ``` |
| 107 | -[warning: llamacpp: nothing answers at http://127.0.0.1:8080/v1 — start it: llama-server -m <model.gguf> --jinja --port 8080] | |
| 107 | +[warning: llamacpp: nothing answers at http://host.docker.internal:8080/v1 — start it: llama-server -m <model.gguf> --jinja --port 8080 (add --host 0.0.0.0 when mm runs in a container or a sandbox)] | |
| 108 | 108 | mm v0.1.7 | config: agent.llamacpp.yaml | provider: llamacpp | model: jetbrains/mellum2-12b-a2.5b-instruct-gguf-q4_k_m:Q4_K_M | ctx: unknown | tools: bash, read_file, write_file, edit_file | skills: 0 | yolo: on |
| 109 | 109 | ``` |
| 110 | 110 | |
| @@ -240,7 +240,7 @@ Un fichier d'agent hors du workspace ne donne qu'un avertissement : voir [quand | ||
| 240 | 240 | |--------|---------------------------------|--------| |
| 241 | 241 | | `--project yes\|no` | Tout ranger dans un dossier `.mm` ? — posée en premier. `yes` : le fichier est `.mm/agent.yaml` (le dossier est créé), ses chemins sont écrits depuis la racine du projet (`skillsDir: .mm/skills`), et `mm` / `mm tui` lancés là le trouvent sans argument | `no` | |
| 242 | 242 | | `--provider` | Serveur de modèles : `llmman`, `ollama`, `dmr`, `llamacpp`, `kronk`, `openai` | le premier serveur local qui répond, sinon `llmman` (`openai` n'est jamais sondé : son adresse par défaut est l'API d'OpenAI) | |
| 243 | -| `--base-url` | `openai` seulement : Endpoint — l'adresse compatible OpenAI du service (OpenAI, Cerebras, Hugging Face…) ; pour les autres fournisseurs, pas posée | `https://api.openai.com/v1` pour `openai` ; sinon l'adresse du fournisseur, ou son adresse de secours quand elle ne répond pas. Écrite comme `baseUrl` sauf si c'est la valeur par défaut | | |
| 243 | +| `--base-url` | `openai` seulement : Endpoint — l'adresse compatible OpenAI du service (OpenAI, Cerebras, Hugging Face…) ; pour les autres fournisseurs, pas posée | `https://api.openai.com/v1` pour `openai` ; sinon `AGENT_BASE_URL` s'il est défini, sinon la première des adresses locales du fournisseur dont la liste de modèles répond — son adresse par défaut, puis la même avec `127.0.0.1` quand elle nomme `localhost` — et son adresse de secours pour conteneur (`host.docker.internal`) seulement quand aucune ne répond. La question du modèle nomme l'adresse d'où vient sa liste (`Model? (listed from …)`). Écrite comme `baseUrl` sauf si c'est la valeur par défaut | | |
| 244 | 244 | | `--api-key-env` | `openai` seulement : variable d'environnement qui contient la clé d'API | `OPENAI_API_KEY`. Écrite comme `apiKeyEnv` sauf si c'est la valeur par défaut | |
| 245 | 245 | | `--model` | Modèle : la liste des modèles du serveur (`/api/tags` pour llmman et Ollama, `/models` pour les autres ; 5 s pour un serveur local, 20 s pour `openai`), ou un nom à taper quand il n'y a pas de liste — la question dit pourquoi (`<VARIABLE> is not set: no list`, ou l'erreur du serveur). Pour `openai`, la liste est demandée avec la clé lue dans la variable nommée plus haut, et pas demandée du tout quand cette variable est vide | le premier de la liste | |
| 246 | 246 | | `--family` | Famille du modèle | détectée d'après le nom du modèle, puis d'après le nom de famille donné par le serveur | |
| @@ -104,7 +104,7 @@ Affichée sur stdout en mode terminal, sur stderr en mode ACP. Grisée quand std | |||
| 104 | ### Exemple | 104 | ### Exemple |
| 105 | 105 | ||
| 106 | ``` | 106 | ``` |
| 107 | -[warning: llamacpp: nothing answers at http://127.0.0.1:8080/v1 — start it: llama-server -m <model.gguf> --jinja --port 8080] | 107 | +[warning: llamacpp: nothing answers at http://host.docker.internal:8080/v1 — start it: llama-server -m <model.gguf> --jinja --port 8080 (add --host 0.0.0.0 when mm runs in a container or a sandbox)] |
| 108 | mm v0.1.7 | config: agent.llamacpp.yaml | provider: llamacpp | model: jetbrains/mellum2-12b-a2.5b-instruct-gguf-q4_k_m:Q4_K_M | ctx: unknown | tools: bash, read_file, write_file, edit_file | skills: 0 | yolo: on | 108 | mm v0.1.7 | config: agent.llamacpp.yaml | provider: llamacpp | model: jetbrains/mellum2-12b-a2.5b-instruct-gguf-q4_k_m:Q4_K_M | ctx: unknown | tools: bash, read_file, write_file, edit_file | skills: 0 | yolo: on |
| 109 | ``` | 109 | ``` |
| 110 | 110 | ||
| @@ -240,7 +240,7 @@ Un fichier d'agent hors du workspace ne donne qu'un avertissement : voir [quand | |||
| 240 | |--------|---------------------------------|--------| | 240 | |--------|---------------------------------|--------| |
| 241 | | `--project yes\|no` | Tout ranger dans un dossier `.mm` ? — posée en premier. `yes` : le fichier est `.mm/agent.yaml` (le dossier est créé), ses chemins sont écrits depuis la racine du projet (`skillsDir: .mm/skills`), et `mm` / `mm tui` lancés là le trouvent sans argument | `no` | | 241 | | `--project yes\|no` | Tout ranger dans un dossier `.mm` ? — posée en premier. `yes` : le fichier est `.mm/agent.yaml` (le dossier est créé), ses chemins sont écrits depuis la racine du projet (`skillsDir: .mm/skills`), et `mm` / `mm tui` lancés là le trouvent sans argument | `no` | |
| 242 | | `--provider` | Serveur de modèles : `llmman`, `ollama`, `dmr`, `llamacpp`, `kronk`, `openai` | le premier serveur local qui répond, sinon `llmman` (`openai` n'est jamais sondé : son adresse par défaut est l'API d'OpenAI) | | 242 | | `--provider` | Serveur de modèles : `llmman`, `ollama`, `dmr`, `llamacpp`, `kronk`, `openai` | le premier serveur local qui répond, sinon `llmman` (`openai` n'est jamais sondé : son adresse par défaut est l'API d'OpenAI) | |
| 243 | -| `--base-url` | `openai` seulement : Endpoint — l'adresse compatible OpenAI du service (OpenAI, Cerebras, Hugging Face…) ; pour les autres fournisseurs, pas posée | `https://api.openai.com/v1` pour `openai` ; sinon l'adresse du fournisseur, ou son adresse de secours quand elle ne répond pas. Écrite comme `baseUrl` sauf si c'est la valeur par défaut | | 243 | +| `--base-url` | `openai` seulement : Endpoint — l'adresse compatible OpenAI du service (OpenAI, Cerebras, Hugging Face…) ; pour les autres fournisseurs, pas posée | `https://api.openai.com/v1` pour `openai` ; sinon `AGENT_BASE_URL` s'il est défini, sinon la première des adresses locales du fournisseur dont la liste de modèles répond — son adresse par défaut, puis la même avec `127.0.0.1` quand elle nomme `localhost` — et son adresse de secours pour conteneur (`host.docker.internal`) seulement quand aucune ne répond. La question du modèle nomme l'adresse d'où vient sa liste (`Model? (listed from …)`). Écrite comme `baseUrl` sauf si c'est la valeur par défaut | |
| 244 | | `--api-key-env` | `openai` seulement : variable d'environnement qui contient la clé d'API | `OPENAI_API_KEY`. Écrite comme `apiKeyEnv` sauf si c'est la valeur par défaut | | 244 | | `--api-key-env` | `openai` seulement : variable d'environnement qui contient la clé d'API | `OPENAI_API_KEY`. Écrite comme `apiKeyEnv` sauf si c'est la valeur par défaut | |
| 245 | | `--model` | Modèle : la liste des modèles du serveur (`/api/tags` pour llmman et Ollama, `/models` pour les autres ; 5 s pour un serveur local, 20 s pour `openai`), ou un nom à taper quand il n'y a pas de liste — la question dit pourquoi (`<VARIABLE> is not set: no list`, ou l'erreur du serveur). Pour `openai`, la liste est demandée avec la clé lue dans la variable nommée plus haut, et pas demandée du tout quand cette variable est vide | le premier de la liste | | 245 | | `--model` | Modèle : la liste des modèles du serveur (`/api/tags` pour llmman et Ollama, `/models` pour les autres ; 5 s pour un serveur local, 20 s pour `openai`), ou un nom à taper quand il n'y a pas de liste — la question dit pourquoi (`<VARIABLE> is not set: no list`, ou l'erreur du serveur). Pour `openai`, la liste est demandée avec la clé lue dans la variable nommée plus haut, et pas demandée du tout quand cette variable est vide | le premier de la liste | |
| 246 | | `--family` | Famille du modèle | détectée d'après le nom du modèle, puis d'après le nom de famille donné par le serveur | | 246 | | `--family` | Famille du modèle | détectée d'après le nom du modèle, puis d'après le nom de famille donné par le serveur | |
modified
docs/fr/reference/configuration.md +2 -2 | @@ -197,7 +197,7 @@ tools: | ||
| 197 | 197 | | Fournisseur | `baseUrl` | `fallback` | `apiKeyEnv` | Clé requise | |
| 198 | 198 | |-------------|-----------|------------|-------------|-------------| |
| 199 | 199 | | `dmr` | `http://localhost:12434/engines/v1` | `http://host.docker.internal:12434/engines/v1` | aucune | non | |
| 200 | -| `llamacpp` | `http://127.0.0.1:8080/v1` | aucun | `LLAMA_API_KEY` | non | | |
| 200 | +| `llamacpp` | `http://127.0.0.1:8080/v1` | `http://host.docker.internal:8080/v1` | `LLAMA_API_KEY` | non | | |
| 201 | 201 | | `llmman` | `http://127.0.0.1:17434/v1` | `http://host.docker.internal:17434/v1` | `LLMMAN_API_KEY` | non | |
| 202 | 202 | | `ollama` | `http://localhost:11434/v1` | `http://host.docker.internal:11434/v1` | `OLLAMA_API_KEY` | non | |
| 203 | 203 | | `kronk` | `http://127.0.0.1:11435/v1` | `http://host.docker.internal:11435/v1` | `KRONK_TOKEN` | non — seuls les modes `authenticated` et `full-protected` de Kronk la vérifient | |
| @@ -477,7 +477,7 @@ Un avertissement au démarrage, et non une erreur, est affiché quand `context.e | ||
| 477 | 477 | | Fichier | Rôle | |
| 478 | 478 | |---------|------| |
| 479 | 479 | | `agent.yaml` | Configuration Docker Model Runner : `provider: dmr`, `maxTurns: 40`, `displayCommands: true`, compression désactivée, un prompt système nommé « Bob » qui décrit les skills et les règles d'édition de fichiers. | |
| 480 | -| `agent.llamacpp.yaml` | Configuration llama.cpp : `provider: llamacpp`, `baseUrl: http://127.0.0.1:8080/v1`, `fallback: ""`, compression activée. | | |
| 480 | +| `agent.llamacpp.yaml` | Configuration llama.cpp : `provider: llamacpp`, `baseUrl: http://127.0.0.1:8080/v1`, compression activée. | | |
| 481 | 481 | |
| 482 | 482 | ### Exemple |
| 483 | 483 | |
| @@ -197,7 +197,7 @@ tools: | |||
| 197 | | Fournisseur | `baseUrl` | `fallback` | `apiKeyEnv` | Clé requise | | 197 | | Fournisseur | `baseUrl` | `fallback` | `apiKeyEnv` | Clé requise | |
| 198 | |-------------|-----------|------------|-------------|-------------| | 198 | |-------------|-----------|------------|-------------|-------------| |
| 199 | | `dmr` | `http://localhost:12434/engines/v1` | `http://host.docker.internal:12434/engines/v1` | aucune | non | | 199 | | `dmr` | `http://localhost:12434/engines/v1` | `http://host.docker.internal:12434/engines/v1` | aucune | non | |
| 200 | -| `llamacpp` | `http://127.0.0.1:8080/v1` | aucun | `LLAMA_API_KEY` | non | | 200 | +| `llamacpp` | `http://127.0.0.1:8080/v1` | `http://host.docker.internal:8080/v1` | `LLAMA_API_KEY` | non | |
| 201 | | `llmman` | `http://127.0.0.1:17434/v1` | `http://host.docker.internal:17434/v1` | `LLMMAN_API_KEY` | non | | 201 | | `llmman` | `http://127.0.0.1:17434/v1` | `http://host.docker.internal:17434/v1` | `LLMMAN_API_KEY` | non | |
| 202 | | `ollama` | `http://localhost:11434/v1` | `http://host.docker.internal:11434/v1` | `OLLAMA_API_KEY` | non | | 202 | | `ollama` | `http://localhost:11434/v1` | `http://host.docker.internal:11434/v1` | `OLLAMA_API_KEY` | non | |
| 203 | | `kronk` | `http://127.0.0.1:11435/v1` | `http://host.docker.internal:11435/v1` | `KRONK_TOKEN` | non — seuls les modes `authenticated` et `full-protected` de Kronk la vérifient | | 203 | | `kronk` | `http://127.0.0.1:11435/v1` | `http://host.docker.internal:11435/v1` | `KRONK_TOKEN` | non — seuls les modes `authenticated` et `full-protected` de Kronk la vérifient | |
| @@ -477,7 +477,7 @@ Un avertissement au démarrage, et non une erreur, est affiché quand `context.e | |||
| 477 | | Fichier | Rôle | | 477 | | Fichier | Rôle | |
| 478 | |---------|------| | 478 | |---------|------| |
| 479 | | `agent.yaml` | Configuration Docker Model Runner : `provider: dmr`, `maxTurns: 40`, `displayCommands: true`, compression désactivée, un prompt système nommé « Bob » qui décrit les skills et les règles d'édition de fichiers. | | 479 | | `agent.yaml` | Configuration Docker Model Runner : `provider: dmr`, `maxTurns: 40`, `displayCommands: true`, compression désactivée, un prompt système nommé « Bob » qui décrit les skills et les règles d'édition de fichiers. | |
| 480 | -| `agent.llamacpp.yaml` | Configuration llama.cpp : `provider: llamacpp`, `baseUrl: http://127.0.0.1:8080/v1`, `fallback: ""`, compression activée. | | 480 | +| `agent.llamacpp.yaml` | Configuration llama.cpp : `provider: llamacpp`, `baseUrl: http://127.0.0.1:8080/v1`, compression activée. | |
| 481 | 481 | ||
| 482 | ### Exemple | 482 | ### Exemple |
| 483 | 483 | ||
modified
internal/agentinit/decide_test.go +1 -1 | @@ -170,7 +170,7 @@ func TestRenderRecordsTheDefaultURLs(t *testing.T) { | ||
| 170 | 170 | t.Errorf("llmman's default URLs missing:\n%s", llmman) |
| 171 | 171 | } |
| 172 | 172 | llamacpp := Render(Decide(p, Choices{Provider: "llamacpp", Model: "qwen3", Usage: "assistant", Machine: "small"}, Facts{})) |
| 173 | - if !strings.Contains(llamacpp, "# baseUrl: \"http://127.0.0.1:8080/v1\"\n# (llamacpp has no fallback address)\n") { | |
| 173 | + if !strings.Contains(llamacpp, "# baseUrl: \"http://127.0.0.1:8080/v1\"\n# fallback: \"http://host.docker.internal:8080/v1\" # tried when baseUrl does not answer\n") { | |
| 174 | 174 | t.Errorf("llamacpp's default URL missing:\n%s", llamacpp) |
| 175 | 175 | } |
| 176 | 176 | own := Render(Decide(p, Choices{Provider: "llmman", BaseURL: "http://box:17434/v1", Model: "qwen3", Usage: "assistant", Machine: "small"}, Facts{})) |
| @@ -170,7 +170,7 @@ func TestRenderRecordsTheDefaultURLs(t *testing.T) { | |||
| 170 | t.Errorf("llmman's default URLs missing:\n%s", llmman) | 170 | t.Errorf("llmman's default URLs missing:\n%s", llmman) |
| 171 | } | 171 | } |
| 172 | llamacpp := Render(Decide(p, Choices{Provider: "llamacpp", Model: "qwen3", Usage: "assistant", Machine: "small"}, Facts{})) | 172 | llamacpp := Render(Decide(p, Choices{Provider: "llamacpp", Model: "qwen3", Usage: "assistant", Machine: "small"}, Facts{})) |
| 173 | - if !strings.Contains(llamacpp, "# baseUrl: \"http://127.0.0.1:8080/v1\"\n# (llamacpp has no fallback address)\n") { | 173 | + if !strings.Contains(llamacpp, "# baseUrl: \"http://127.0.0.1:8080/v1\"\n# fallback: \"http://host.docker.internal:8080/v1\" # tried when baseUrl does not answer\n") { |
| 174 | t.Errorf("llamacpp's default URL missing:\n%s", llamacpp) | 174 | t.Errorf("llamacpp's default URL missing:\n%s", llamacpp) |
| 175 | } | 175 | } |
| 176 | own := Render(Decide(p, Choices{Provider: "llmman", BaseURL: "http://box:17434/v1", Model: "qwen3", Usage: "assistant", Machine: "small"}, Facts{})) | 176 | own := Render(Decide(p, Choices{Provider: "llmman", BaseURL: "http://box:17434/v1", Model: "qwen3", Usage: "assistant", Machine: "small"}, Facts{})) |
modified
internal/agentinit/flow.go +5 -2 | @@ -222,6 +222,9 @@ func (f *Flow) Step(key string) Step { | ||
| 222 | 222 | st.Kind, st.Prompt = elicit.Text, f.typeModelPrompt() |
| 223 | 223 | break |
| 224 | 224 | } |
| 225 | + // Where the list comes from (ticket 214): a wrong address — the | |
| 226 | + // container one on the host — shows at once. | |
| 227 | + st.Prompt = fmt.Sprintf("Model? (listed from %s)", f.Base()) | |
| 225 | 228 | for _, m := range models { |
| 226 | 229 | st.Options = append(st.Options, Option{Value: m, Label: m, Detail: modelDetail(f.c.Provider, m)}) |
| 227 | 230 | } |
| @@ -578,7 +581,7 @@ func (f *Flow) Result() (Choices, Facts, string) { | ||
| 578 | 581 | // Base is the resolved server address ("" before a provider is chosen). |
| 579 | 582 | func (f *Flow) Base() string { |
| 580 | 583 | if f.base == "" && f.c.Provider != "" { |
| 581 | - f.base = resolveBase(f.c) | |
| 584 | + f.base = resolveBase(f.ctx, f.c) | |
| 582 | 585 | } |
| 583 | 586 | return f.base |
| 584 | 587 | } |
| @@ -628,7 +631,7 @@ func (f *Flow) answers(name string) bool { | ||
| 628 | 631 | if f.reachable == nil { |
| 629 | 632 | f.reachable = map[string]bool{} |
| 630 | 633 | for _, p := range local { |
| 631 | - _, err := Models(f.ctx, p, resolveBase(Choices{Provider: p})) | |
| 634 | + _, err := Models(f.ctx, p, resolveBase(f.ctx, Choices{Provider: p})) | |
| 632 | 635 | f.reachable[p] = err == nil |
| 633 | 636 | } |
| 634 | 637 | } |
| @@ -222,6 +222,9 @@ func (f *Flow) Step(key string) Step { | |||
| 222 | st.Kind, st.Prompt = elicit.Text, f.typeModelPrompt() | 222 | st.Kind, st.Prompt = elicit.Text, f.typeModelPrompt() |
| 223 | break | 223 | break |
| 224 | } | 224 | } |
| 225 | + // Where the list comes from (ticket 214): a wrong address — the | ||
| 226 | + // container one on the host — shows at once. | ||
| 227 | + st.Prompt = fmt.Sprintf("Model? (listed from %s)", f.Base()) | ||
| 225 | for _, m := range models { | 228 | for _, m := range models { |
| 226 | st.Options = append(st.Options, Option{Value: m, Label: m, Detail: modelDetail(f.c.Provider, m)}) | 229 | st.Options = append(st.Options, Option{Value: m, Label: m, Detail: modelDetail(f.c.Provider, m)}) |
| 227 | } | 230 | } |
| @@ -578,7 +581,7 @@ func (f *Flow) Result() (Choices, Facts, string) { | |||
| 578 | // Base is the resolved server address ("" before a provider is chosen). | 581 | // Base is the resolved server address ("" before a provider is chosen). |
| 579 | func (f *Flow) Base() string { | 582 | func (f *Flow) Base() string { |
| 580 | if f.base == "" && f.c.Provider != "" { | 583 | if f.base == "" && f.c.Provider != "" { |
| 581 | - f.base = resolveBase(f.c) | 584 | + f.base = resolveBase(f.ctx, f.c) |
| 582 | } | 585 | } |
| 583 | return f.base | 586 | return f.base |
| 584 | } | 587 | } |
| @@ -628,7 +631,7 @@ func (f *Flow) answers(name string) bool { | |||
| 628 | if f.reachable == nil { | 631 | if f.reachable == nil { |
| 629 | f.reachable = map[string]bool{} | 632 | f.reachable = map[string]bool{} |
| 630 | for _, p := range local { | 633 | for _, p := range local { |
| 631 | - _, err := Models(f.ctx, p, resolveBase(Choices{Provider: p})) | 634 | + _, err := Models(f.ctx, p, resolveBase(f.ctx, Choices{Provider: p})) |
| 632 | f.reachable[p] = err == nil | 635 | f.reachable[p] = err == nil |
| 633 | } | 636 | } |
| 634 | } | 637 | } |
modified
internal/agentinit/wizard.go +61 -3 | @@ -367,12 +367,70 @@ func (w *lineWizard) ask(st Step) string { | ||
| 367 | 367 | } |
| 368 | 368 | } |
| 369 | 369 | |
| 370 | -// resolveBase is the server's address: the flag's, else the provider's | |
| 371 | -// default (or its fallback, when the default does not answer). | |
| 372 | -func resolveBase(c Choices) string { | |
| 370 | +// resolveBase is the server's address the wizard lists models from: the | |
| 371 | +// flag's, else the one the environment imposes (AGENT_BASE_URL…), else the | |
| 372 | +// first that answers of the provider's local addresses, then its fallback | |
| 373 | +// (chooseBase). | |
| 374 | +// | |
| 375 | +// Ticket 214: it used to take the engine's own resolution, whose probe gives | |
| 376 | +// the default address 2 s on /models and switches to the container fallback | |
| 377 | +// (host.docker.internal) without a word. mm on a Mac with Docker Desktop — | |
| 378 | +// where that name resolves on the host too — then listed Ollama's models | |
| 379 | +// from the container address. The written file is not concerned: it carries | |
| 380 | +// no baseUrl for the default address. | |
| 381 | +func resolveBase(ctx context.Context, c Choices) string { | |
| 373 | 382 | if c.BaseURL != "" { |
| 374 | 383 | return c.BaseURL |
| 375 | 384 | } |
| 385 | + if env := engine.EnvBaseURL(c.Provider); env != "" { | |
| 386 | + return env | |
| 387 | + } | |
| 388 | + if base, fallback, ok := engine.DefaultURLs(c.Provider); ok { | |
| 389 | + return chooseBase(base, fallback, func(url string) bool { | |
| 390 | + _, err := Models(ctx, c.Provider, url) | |
| 391 | + return err == nil | |
| 392 | + }) | |
| 393 | + } | |
| 394 | + return engineBase(c) | |
| 395 | +} | |
| 396 | + | |
| 397 | +// chooseBase picks the address to list models from: the first that lists | |
| 398 | +// them among the local ones (localAddresses), else the fallback when it | |
| 399 | +// does, else the default — whose error the model question then shows. A | |
| 400 | +// provider without a fallback (llamacpp, openai) is not probed at all: there | |
| 401 | +// is nothing to choose, and openai's default is a remote service nobody | |
| 402 | +// asked mm to call yet. | |
| 403 | +func chooseBase(base, fallback string, lists func(string) bool) string { | |
| 404 | + if fallback == "" { | |
| 405 | + return base | |
| 406 | + } | |
| 407 | + for _, url := range localAddresses(base) { | |
| 408 | + if lists(url) { | |
| 409 | + return url | |
| 410 | + } | |
| 411 | + } | |
| 412 | + if lists(fallback) { | |
| 413 | + return fallback | |
| 414 | + } | |
| 415 | + return base | |
| 416 | +} | |
| 417 | + | |
| 418 | +// localAddresses is the default address, then — when it names localhost — | |
| 419 | +// the same with 127.0.0.1: a server listening on IPv4 only does not answer | |
| 420 | +// a localhost that resolves to ::1 first. | |
| 421 | +// | |
| 422 | +// localAddresses("http://localhost:11434/v1") // [http://localhost:11434/v1 http://127.0.0.1:11434/v1] | |
| 423 | +func localAddresses(base string) []string { | |
| 424 | + out := []string{base} | |
| 425 | + if strings.Contains(base, "://localhost:") || strings.HasSuffix(base, "://localhost") { | |
| 426 | + out = append(out, strings.Replace(base, "://localhost", "://127.0.0.1", 1)) | |
| 427 | + } | |
| 428 | + return out | |
| 429 | +} | |
| 430 | + | |
| 431 | +// engineBase is the engine's own resolution, for a provider the wizard has | |
| 432 | +// no addresses for. | |
| 433 | +func engineBase(c Choices) string { | |
| 376 | 434 | p, err := engine.Lookup(c.Provider) |
| 377 | 435 | if err != nil { |
| 378 | 436 | return "" |
| @@ -367,12 +367,70 @@ func (w *lineWizard) ask(st Step) string { | |||
| 367 | } | 367 | } |
| 368 | } | 368 | } |
| 369 | 369 | ||
| 370 | -// resolveBase is the server's address: the flag's, else the provider's | 370 | +// resolveBase is the server's address the wizard lists models from: the |
| 371 | -// default (or its fallback, when the default does not answer). | 371 | +// flag's, else the one the environment imposes (AGENT_BASE_URL…), else the |
| 372 | -func resolveBase(c Choices) string { | 372 | +// first that answers of the provider's local addresses, then its fallback |
| 373 | +// (chooseBase). | ||
| 374 | +// | ||
| 375 | +// Ticket 214: it used to take the engine's own resolution, whose probe gives | ||
| 376 | +// the default address 2 s on /models and switches to the container fallback | ||
| 377 | +// (host.docker.internal) without a word. mm on a Mac with Docker Desktop — | ||
| 378 | +// where that name resolves on the host too — then listed Ollama's models | ||
| 379 | +// from the container address. The written file is not concerned: it carries | ||
| 380 | +// no baseUrl for the default address. | ||
| 381 | +func resolveBase(ctx context.Context, c Choices) string { | ||
| 373 | if c.BaseURL != "" { | 382 | if c.BaseURL != "" { |
| 374 | return c.BaseURL | 383 | return c.BaseURL |
| 375 | } | 384 | } |
| 385 | + if env := engine.EnvBaseURL(c.Provider); env != "" { | ||
| 386 | + return env | ||
| 387 | + } | ||
| 388 | + if base, fallback, ok := engine.DefaultURLs(c.Provider); ok { | ||
| 389 | + return chooseBase(base, fallback, func(url string) bool { | ||
| 390 | + _, err := Models(ctx, c.Provider, url) | ||
| 391 | + return err == nil | ||
| 392 | + }) | ||
| 393 | + } | ||
| 394 | + return engineBase(c) | ||
| 395 | +} | ||
| 396 | + | ||
| 397 | +// chooseBase picks the address to list models from: the first that lists | ||
| 398 | +// them among the local ones (localAddresses), else the fallback when it | ||
| 399 | +// does, else the default — whose error the model question then shows. A | ||
| 400 | +// provider without a fallback (llamacpp, openai) is not probed at all: there | ||
| 401 | +// is nothing to choose, and openai's default is a remote service nobody | ||
| 402 | +// asked mm to call yet. | ||
| 403 | +func chooseBase(base, fallback string, lists func(string) bool) string { | ||
| 404 | + if fallback == "" { | ||
| 405 | + return base | ||
| 406 | + } | ||
| 407 | + for _, url := range localAddresses(base) { | ||
| 408 | + if lists(url) { | ||
| 409 | + return url | ||
| 410 | + } | ||
| 411 | + } | ||
| 412 | + if lists(fallback) { | ||
| 413 | + return fallback | ||
| 414 | + } | ||
| 415 | + return base | ||
| 416 | +} | ||
| 417 | + | ||
| 418 | +// localAddresses is the default address, then — when it names localhost — | ||
| 419 | +// the same with 127.0.0.1: a server listening on IPv4 only does not answer | ||
| 420 | +// a localhost that resolves to ::1 first. | ||
| 421 | +// | ||
| 422 | +// localAddresses("http://localhost:11434/v1") // [http://localhost:11434/v1 http://127.0.0.1:11434/v1] | ||
| 423 | +func localAddresses(base string) []string { | ||
| 424 | + out := []string{base} | ||
| 425 | + if strings.Contains(base, "://localhost:") || strings.HasSuffix(base, "://localhost") { | ||
| 426 | + out = append(out, strings.Replace(base, "://localhost", "://127.0.0.1", 1)) | ||
| 427 | + } | ||
| 428 | + return out | ||
| 429 | +} | ||
| 430 | + | ||
| 431 | +// engineBase is the engine's own resolution, for a provider the wizard has | ||
| 432 | +// no addresses for. | ||
| 433 | +func engineBase(c Choices) string { | ||
| 376 | p, err := engine.Lookup(c.Provider) | 434 | p, err := engine.Lookup(c.Provider) |
| 377 | if err != nil { | 435 | if err != nil { |
| 378 | return "" | 436 | return "" |
modified
internal/agentinit/wizard_test.go +102 -0 | @@ -3,13 +3,18 @@ package agentinit | ||
| 3 | 3 | import ( |
| 4 | 4 | "bytes" |
| 5 | 5 | "context" |
| 6 | + "encoding/json" | |
| 7 | + "net/http" | |
| 8 | + "net/http/httptest" | |
| 6 | 9 | "os" |
| 7 | 10 | "path/filepath" |
| 8 | 11 | "strings" |
| 9 | 12 | "testing" |
| 13 | + "time" | |
| 10 | 14 | |
| 11 | 15 | "mm/internal/config" |
| 12 | 16 | "mm/internal/elicit" |
| 17 | + "mm/internal/engine" | |
| 13 | 18 | ) |
| 14 | 19 | |
| 15 | 20 | func llmmanStub(t *testing.T) string { |
| @@ -247,3 +252,100 @@ func TestMainToStdoutAndBadAnswers(t *testing.T) { | ||
| 247 | 252 | t.Errorf("bad usage: exit %d:\n%s", code, stdout.String()) |
| 248 | 253 | } |
| 249 | 254 | } |
| 255 | + | |
| 256 | +// Ticket 214: the wizard lists the models from a local address whenever one | |
| 257 | +// answers — the default, then the same with 127.0.0.1 — and takes the | |
| 258 | +// container fallback only when none does. A provider without a fallback is | |
| 259 | +// not probed. | |
| 260 | +func TestChooseBasePrefersALocalAddress(t *testing.T) { | |
| 261 | + const base, ipv4, fallback = "http://localhost:11434/v1", "http://127.0.0.1:11434/v1", "http://host.docker.internal:11434/v1" | |
| 262 | + answering := func(urls ...string) (func(string) bool, *[]string) { | |
| 263 | + var asked []string | |
| 264 | + return func(url string) bool { | |
| 265 | + asked = append(asked, url) | |
| 266 | + for _, u := range urls { | |
| 267 | + if u == url { | |
| 268 | + return true | |
| 269 | + } | |
| 270 | + } | |
| 271 | + return false | |
| 272 | + }, &asked | |
| 273 | + } | |
| 274 | + cases := []struct { | |
| 275 | + name string | |
| 276 | + answer []string | |
| 277 | + want string | |
| 278 | + wantAsked int | |
| 279 | + }{ | |
| 280 | + {"the default answers, the fallback too (Docker Desktop on a Mac)", []string{base, fallback}, base, 1}, | |
| 281 | + {"only 127.0.0.1 answers (a server on IPv4 only)", []string{ipv4, fallback}, ipv4, 2}, | |
| 282 | + {"only the fallback answers (mm in a container)", []string{fallback}, fallback, 3}, | |
| 283 | + {"nothing answers: the default, whose error the question shows", nil, base, 3}, | |
| 284 | + } | |
| 285 | + for _, c := range cases { | |
| 286 | + lists, asked := answering(c.answer...) | |
| 287 | + if got := chooseBase(base, fallback, lists); got != c.want || len(*asked) != c.wantAsked { | |
| 288 | + t.Errorf("%s: got %s after asking %v, want %s after %d", c.name, got, *asked, c.want, c.wantAsked) | |
| 289 | + } | |
| 290 | + } | |
| 291 | + lists, asked := answering() | |
| 292 | + if got := chooseBase("https://api.openai.com/v1", "", lists); got != "https://api.openai.com/v1" || len(*asked) != 0 { | |
| 293 | + t.Errorf("no fallback: got %s, asked %v — want the default, nothing asked", got, *asked) | |
| 294 | + } | |
| 295 | +} | |
| 296 | + | |
| 297 | +func TestLocalAddresses(t *testing.T) { | |
| 298 | + for in, want := range map[string]string{ | |
| 299 | + "http://localhost:11434/v1": "http://localhost:11434/v1 http://127.0.0.1:11434/v1", | |
| 300 | + "http://localhost:12434/engines/v1": "http://localhost:12434/engines/v1 http://127.0.0.1:12434/engines/v1", | |
| 301 | + "http://127.0.0.1:17434/v1": "http://127.0.0.1:17434/v1", | |
| 302 | + } { | |
| 303 | + if got := strings.Join(localAddresses(in), " "); got != want { | |
| 304 | + t.Errorf("localAddresses(%s) = %s, want %s", in, got, want) | |
| 305 | + } | |
| 306 | + } | |
| 307 | +} | |
| 308 | + | |
| 309 | +// The address comes from the model list, not the engine's 2 s probe of | |
| 310 | +// /models: a server whose /v1/models is slow but whose list answers is kept | |
| 311 | +// — before ticket 214, the probe gave up and the fallback was taken. | |
| 312 | +func TestResolveBaseKeepsASlowLocalServer(t *testing.T) { | |
| 313 | + slow := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | |
| 314 | + switch r.URL.Path { | |
| 315 | + case "/api/tags": | |
| 316 | + _ = json.NewEncoder(w).Encode(map[string]any{"models": []any{map[string]any{"name": "qwen3.5:4b"}}}) | |
| 317 | + case "/v1/models": | |
| 318 | + time.Sleep(3 * time.Second) // longer than the engine's probe | |
| 319 | + _ = json.NewEncoder(w).Encode(map[string]any{"data": []any{}}) | |
| 320 | + default: | |
| 321 | + http.NotFound(w, r) | |
| 322 | + } | |
| 323 | + })) | |
| 324 | + t.Cleanup(slow.Close) | |
| 325 | + base := slow.URL + "/v1" | |
| 326 | + // The engine's own resolution — what the wizard used before — gives up | |
| 327 | + // on this server and takes the fallback. | |
| 328 | + fallback := "http://host.docker.internal:1/v1" | |
| 329 | + p, err := engine.Lookup("ollama") | |
| 330 | + if err != nil { | |
| 331 | + t.Fatal(err) | |
| 332 | + } | |
| 333 | + if b, err := p.Resolve(config.Config{Provider: "ollama", Model: "probe", BaseURL: base, Fallback: &fallback}); err != nil || b.BaseURL != fallback { | |
| 334 | + t.Fatalf("the engine's probe kept %s (%v): the test server is not slow enough to show ticket 214", b.BaseURL, err) | |
| 335 | + } | |
| 336 | + got := chooseBase(base, fallback, func(url string) bool { | |
| 337 | + _, err := Models(context.Background(), "ollama", url) | |
| 338 | + return err == nil | |
| 339 | + }) | |
| 340 | + if got != base { | |
| 341 | + t.Errorf("got %s, want the local server %s", got, base) | |
| 342 | + } | |
| 343 | +} | |
| 344 | + | |
| 345 | +// An address imposed by the environment is taken as is, like the engine does. | |
| 346 | +func TestResolveBaseHonoursAgentBaseURL(t *testing.T) { | |
| 347 | + t.Setenv("AGENT_BASE_URL", "http://example.invalid:9/v1") | |
| 348 | + if got := resolveBase(context.Background(), Choices{Provider: "ollama"}); got != "http://example.invalid:9/v1" { | |
| 349 | + t.Errorf("got %s", got) | |
| 350 | + } | |
| 351 | +} | |
| @@ -3,13 +3,18 @@ package agentinit | |||
| 3 | import ( | 3 | import ( |
| 4 | "bytes" | 4 | "bytes" |
| 5 | "context" | 5 | "context" |
| 6 | + "encoding/json" | ||
| 7 | + "net/http" | ||
| 8 | + "net/http/httptest" | ||
| 6 | "os" | 9 | "os" |
| 7 | "path/filepath" | 10 | "path/filepath" |
| 8 | "strings" | 11 | "strings" |
| 9 | "testing" | 12 | "testing" |
| 13 | + "time" | ||
| 10 | 14 | ||
| 11 | "mm/internal/config" | 15 | "mm/internal/config" |
| 12 | "mm/internal/elicit" | 16 | "mm/internal/elicit" |
| 17 | + "mm/internal/engine" | ||
| 13 | ) | 18 | ) |
| 14 | 19 | ||
| 15 | func llmmanStub(t *testing.T) string { | 20 | func llmmanStub(t *testing.T) string { |
| @@ -247,3 +252,100 @@ func TestMainToStdoutAndBadAnswers(t *testing.T) { | |||
| 247 | t.Errorf("bad usage: exit %d:\n%s", code, stdout.String()) | 252 | t.Errorf("bad usage: exit %d:\n%s", code, stdout.String()) |
| 248 | } | 253 | } |
| 249 | } | 254 | } |
| 255 | + | ||
| 256 | +// Ticket 214: the wizard lists the models from a local address whenever one | ||
| 257 | +// answers — the default, then the same with 127.0.0.1 — and takes the | ||
| 258 | +// container fallback only when none does. A provider without a fallback is | ||
| 259 | +// not probed. | ||
| 260 | +func TestChooseBasePrefersALocalAddress(t *testing.T) { | ||
| 261 | + const base, ipv4, fallback = "http://localhost:11434/v1", "http://127.0.0.1:11434/v1", "http://host.docker.internal:11434/v1" | ||
| 262 | + answering := func(urls ...string) (func(string) bool, *[]string) { | ||
| 263 | + var asked []string | ||
| 264 | + return func(url string) bool { | ||
| 265 | + asked = append(asked, url) | ||
| 266 | + for _, u := range urls { | ||
| 267 | + if u == url { | ||
| 268 | + return true | ||
| 269 | + } | ||
| 270 | + } | ||
| 271 | + return false | ||
| 272 | + }, &asked | ||
| 273 | + } | ||
| 274 | + cases := []struct { | ||
| 275 | + name string | ||
| 276 | + answer []string | ||
| 277 | + want string | ||
| 278 | + wantAsked int | ||
| 279 | + }{ | ||
| 280 | + {"the default answers, the fallback too (Docker Desktop on a Mac)", []string{base, fallback}, base, 1}, | ||
| 281 | + {"only 127.0.0.1 answers (a server on IPv4 only)", []string{ipv4, fallback}, ipv4, 2}, | ||
| 282 | + {"only the fallback answers (mm in a container)", []string{fallback}, fallback, 3}, | ||
| 283 | + {"nothing answers: the default, whose error the question shows", nil, base, 3}, | ||
| 284 | + } | ||
| 285 | + for _, c := range cases { | ||
| 286 | + lists, asked := answering(c.answer...) | ||
| 287 | + if got := chooseBase(base, fallback, lists); got != c.want || len(*asked) != c.wantAsked { | ||
| 288 | + t.Errorf("%s: got %s after asking %v, want %s after %d", c.name, got, *asked, c.want, c.wantAsked) | ||
| 289 | + } | ||
| 290 | + } | ||
| 291 | + lists, asked := answering() | ||
| 292 | + if got := chooseBase("https://api.openai.com/v1", "", lists); got != "https://api.openai.com/v1" || len(*asked) != 0 { | ||
| 293 | + t.Errorf("no fallback: got %s, asked %v — want the default, nothing asked", got, *asked) | ||
| 294 | + } | ||
| 295 | +} | ||
| 296 | + | ||
| 297 | +func TestLocalAddresses(t *testing.T) { | ||
| 298 | + for in, want := range map[string]string{ | ||
| 299 | + "http://localhost:11434/v1": "http://localhost:11434/v1 http://127.0.0.1:11434/v1", | ||
| 300 | + "http://localhost:12434/engines/v1": "http://localhost:12434/engines/v1 http://127.0.0.1:12434/engines/v1", | ||
| 301 | + "http://127.0.0.1:17434/v1": "http://127.0.0.1:17434/v1", | ||
| 302 | + } { | ||
| 303 | + if got := strings.Join(localAddresses(in), " "); got != want { | ||
| 304 | + t.Errorf("localAddresses(%s) = %s, want %s", in, got, want) | ||
| 305 | + } | ||
| 306 | + } | ||
| 307 | +} | ||
| 308 | + | ||
| 309 | +// The address comes from the model list, not the engine's 2 s probe of | ||
| 310 | +// /models: a server whose /v1/models is slow but whose list answers is kept | ||
| 311 | +// — before ticket 214, the probe gave up and the fallback was taken. | ||
| 312 | +func TestResolveBaseKeepsASlowLocalServer(t *testing.T) { | ||
| 313 | + slow := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||
| 314 | + switch r.URL.Path { | ||
| 315 | + case "/api/tags": | ||
| 316 | + _ = json.NewEncoder(w).Encode(map[string]any{"models": []any{map[string]any{"name": "qwen3.5:4b"}}}) | ||
| 317 | + case "/v1/models": | ||
| 318 | + time.Sleep(3 * time.Second) // longer than the engine's probe | ||
| 319 | + _ = json.NewEncoder(w).Encode(map[string]any{"data": []any{}}) | ||
| 320 | + default: | ||
| 321 | + http.NotFound(w, r) | ||
| 322 | + } | ||
| 323 | + })) | ||
| 324 | + t.Cleanup(slow.Close) | ||
| 325 | + base := slow.URL + "/v1" | ||
| 326 | + // The engine's own resolution — what the wizard used before — gives up | ||
| 327 | + // on this server and takes the fallback. | ||
| 328 | + fallback := "http://host.docker.internal:1/v1" | ||
| 329 | + p, err := engine.Lookup("ollama") | ||
| 330 | + if err != nil { | ||
| 331 | + t.Fatal(err) | ||
| 332 | + } | ||
| 333 | + if b, err := p.Resolve(config.Config{Provider: "ollama", Model: "probe", BaseURL: base, Fallback: &fallback}); err != nil || b.BaseURL != fallback { | ||
| 334 | + t.Fatalf("the engine's probe kept %s (%v): the test server is not slow enough to show ticket 214", b.BaseURL, err) | ||
| 335 | + } | ||
| 336 | + got := chooseBase(base, fallback, func(url string) bool { | ||
| 337 | + _, err := Models(context.Background(), "ollama", url) | ||
| 338 | + return err == nil | ||
| 339 | + }) | ||
| 340 | + if got != base { | ||
| 341 | + t.Errorf("got %s, want the local server %s", got, base) | ||
| 342 | + } | ||
| 343 | +} | ||
| 344 | + | ||
| 345 | +// An address imposed by the environment is taken as is, like the engine does. | ||
| 346 | +func TestResolveBaseHonoursAgentBaseURL(t *testing.T) { | ||
| 347 | + t.Setenv("AGENT_BASE_URL", "http://example.invalid:9/v1") | ||
| 348 | + if got := resolveBase(context.Background(), Choices{Provider: "ollama"}); got != "http://example.invalid:9/v1" { | ||
| 349 | + t.Errorf("got %s", got) | ||
| 350 | + } | ||
| 351 | +} | ||
modified
internal/engine/openai_compat.go +20 -1 | @@ -87,6 +87,20 @@ func DefaultURLs(provider string) (baseURL, fallback string, ok bool) { | ||
| 87 | 87 | return p.baseURL, p.fallback, true |
| 88 | 88 | } |
| 89 | 89 | |
| 90 | +// EnvBaseURL is the address the environment imposes on a provider — | |
| 91 | +// AGENT_BASE_URL, else the provider's legacy variable (DMR_BASE_URL) — or | |
| 92 | +// "" when none is set. Resolve takes it as is, without probing; so does | |
| 93 | +// `mm init` (ticket 214). | |
| 94 | +func EnvBaseURL(provider string) string { | |
| 95 | + if env := os.Getenv("AGENT_BASE_URL"); env != "" { | |
| 96 | + return env | |
| 97 | + } | |
| 98 | + if p, found := registry[provider].(*openaiCompat); found && p.legacyBaseURLEnv != "" { | |
| 99 | + return os.Getenv(p.legacyBaseURLEnv) | |
| 100 | + } | |
| 101 | + return "" | |
| 102 | +} | |
| 103 | + | |
| 90 | 104 | func init() { |
| 91 | 105 | register(&openaiCompat{ |
| 92 | 106 | name: "dmr", |
| @@ -104,11 +118,16 @@ func init() { | ||
| 104 | 118 | register(&openaiCompat{ |
| 105 | 119 | name: "llamacpp", |
| 106 | 120 | baseURL: "http://127.0.0.1:8080/v1", // llama-server's default host:port, plus the OpenAI prefix |
| 121 | + // From a container or a sandbox, like the other local servers | |
| 122 | + // (ticket 217). llama-server listens on the loopback only unless | |
| 123 | + // started with --host 0.0.0.0, which Linux and a Docker Sandbox need | |
| 124 | + // for this name to reach it (Docker Desktop reaches the loopback). | |
| 125 | + fallback: "http://host.docker.internal:8080/v1", | |
| 107 | 126 | // llama-server only checks a key when started with --api-key; most |
| 108 | 127 | // local set-ups are not, so an unset LLAMA_API_KEY is normal. |
| 109 | 128 | apiKeyEnv: "LLAMA_API_KEY", |
| 110 | 129 | dummyKey: "not-needed", |
| 111 | - startHint: "start it: llama-server -m <model.gguf> --jinja --port 8080", | |
| 130 | + startHint: "start it: llama-server -m <model.gguf> --jinja --port 8080 (add --host 0.0.0.0 when mm runs in a container or a sandbox)", | |
| 112 | 131 | notFoundHint: "llama-server serves one model; check baseUrl ends with /v1 (model: %s)", |
| 113 | 132 | probe: probeLlamaCpp, |
| 114 | 133 | progress: true, |
| @@ -87,6 +87,20 @@ func DefaultURLs(provider string) (baseURL, fallback string, ok bool) { | |||
| 87 | return p.baseURL, p.fallback, true | 87 | return p.baseURL, p.fallback, true |
| 88 | } | 88 | } |
| 89 | 89 | ||
| 90 | +// EnvBaseURL is the address the environment imposes on a provider — | ||
| 91 | +// AGENT_BASE_URL, else the provider's legacy variable (DMR_BASE_URL) — or | ||
| 92 | +// "" when none is set. Resolve takes it as is, without probing; so does | ||
| 93 | +// `mm init` (ticket 214). | ||
| 94 | +func EnvBaseURL(provider string) string { | ||
| 95 | + if env := os.Getenv("AGENT_BASE_URL"); env != "" { | ||
| 96 | + return env | ||
| 97 | + } | ||
| 98 | + if p, found := registry[provider].(*openaiCompat); found && p.legacyBaseURLEnv != "" { | ||
| 99 | + return os.Getenv(p.legacyBaseURLEnv) | ||
| 100 | + } | ||
| 101 | + return "" | ||
| 102 | +} | ||
| 103 | + | ||
| 90 | func init() { | 104 | func init() { |
| 91 | register(&openaiCompat{ | 105 | register(&openaiCompat{ |
| 92 | name: "dmr", | 106 | name: "dmr", |
| @@ -104,11 +118,16 @@ func init() { | |||
| 104 | register(&openaiCompat{ | 118 | register(&openaiCompat{ |
| 105 | name: "llamacpp", | 119 | name: "llamacpp", |
| 106 | baseURL: "http://127.0.0.1:8080/v1", // llama-server's default host:port, plus the OpenAI prefix | 120 | baseURL: "http://127.0.0.1:8080/v1", // llama-server's default host:port, plus the OpenAI prefix |
| 121 | + // From a container or a sandbox, like the other local servers | ||
| 122 | + // (ticket 217). llama-server listens on the loopback only unless | ||
| 123 | + // started with --host 0.0.0.0, which Linux and a Docker Sandbox need | ||
| 124 | + // for this name to reach it (Docker Desktop reaches the loopback). | ||
| 125 | + fallback: "http://host.docker.internal:8080/v1", | ||
| 107 | // llama-server only checks a key when started with --api-key; most | 126 | // llama-server only checks a key when started with --api-key; most |
| 108 | // local set-ups are not, so an unset LLAMA_API_KEY is normal. | 127 | // local set-ups are not, so an unset LLAMA_API_KEY is normal. |
| 109 | apiKeyEnv: "LLAMA_API_KEY", | 128 | apiKeyEnv: "LLAMA_API_KEY", |
| 110 | dummyKey: "not-needed", | 129 | dummyKey: "not-needed", |
| 111 | - startHint: "start it: llama-server -m <model.gguf> --jinja --port 8080", | 130 | + startHint: "start it: llama-server -m <model.gguf> --jinja --port 8080 (add --host 0.0.0.0 when mm runs in a container or a sandbox)", |
| 112 | notFoundHint: "llama-server serves one model; check baseUrl ends with /v1 (model: %s)", | 131 | notFoundHint: "llama-server serves one model; check baseUrl ends with /v1 (model: %s)", |
| 113 | probe: probeLlamaCpp, | 132 | probe: probeLlamaCpp, |
| 114 | progress: true, | 133 | progress: true, |
modified
internal/engine/provider_test.go +11 -6 | @@ -108,10 +108,13 @@ func TestResolveURLPrecedence(t *testing.T) { | ||
| 108 | 108 | {"an explicit empty fallback disables it", "dmr", config.Config{BaseURL: down, Fallback: ptr("")}, nil, down, "not-needed"}, |
| 109 | 109 | {"AGENT_BASE_URL wins without probing", "dmr", config.Config{BaseURL: up.URL, Fallback: ptr("")}, map[string]string{"AGENT_BASE_URL": down}, down, "not-needed"}, |
| 110 | 110 | {"DMR_BASE_URL still works for dmr", "dmr", config.Config{BaseURL: up.URL, Fallback: ptr("")}, map[string]string{"DMR_BASE_URL": down}, down, "not-needed"}, |
| 111 | - {"llamacpp default is llama-server's port", "llamacpp", config.Config{}, nil, "http://127.0.0.1:8080/v1", "not-needed"}, | |
| 112 | - {"llamacpp ignores DMR_BASE_URL", "llamacpp", config.Config{}, map[string]string{"DMR_BASE_URL": down}, "http://127.0.0.1:8080/v1", "not-needed"}, | |
| 113 | - {"llamacpp reads LLAMA_API_KEY when set", "llamacpp", config.Config{}, map[string]string{"LLAMA_API_KEY": "secret"}, "http://127.0.0.1:8080/v1", "secret"}, | |
| 114 | - {"apiKeyEnv names another variable", "llamacpp", config.Config{APIKeyEnv: "MY_KEY"}, map[string]string{"MY_KEY": "k2"}, "http://127.0.0.1:8080/v1", "k2"}, | |
| 111 | + // llamacpp falls back on the host like the other local servers | |
| 112 | + // since ticket 217 (its default address: TestDefaultURLs). | |
| 113 | + {"llamacpp falls back to the host's llama-server", "llamacpp", config.Config{BaseURL: down}, nil, "http://host.docker.internal:8080/v1", "not-needed"}, | |
| 114 | + {"llamacpp keeps a reachable baseUrl", "llamacpp", config.Config{BaseURL: up.URL}, nil, up.URL, "not-needed"}, | |
| 115 | + {"llamacpp ignores DMR_BASE_URL", "llamacpp", config.Config{BaseURL: up.URL}, map[string]string{"DMR_BASE_URL": down}, up.URL, "not-needed"}, | |
| 116 | + {"llamacpp reads LLAMA_API_KEY when set", "llamacpp", config.Config{BaseURL: up.URL}, map[string]string{"LLAMA_API_KEY": "secret"}, up.URL, "secret"}, | |
| 117 | + {"apiKeyEnv names another variable", "llamacpp", config.Config{BaseURL: up.URL, APIKeyEnv: "MY_KEY"}, map[string]string{"MY_KEY": "k2"}, up.URL, "k2"}, | |
| 115 | 118 | {"llmman falls back to the host's daemon", "llmman", config.Config{BaseURL: down}, nil, "http://host.docker.internal:17434/v1", "not-needed"}, |
| 116 | 119 | {"llmman keeps a reachable baseUrl", "llmman", config.Config{BaseURL: up.URL}, nil, up.URL, "not-needed"}, |
| 117 | 120 | {"llmman reads LLMMAN_API_KEY when set", "llmman", config.Config{BaseURL: up.URL}, map[string]string{"LLMMAN_API_KEY": "k3", "LLAMA_API_KEY": "secret"}, up.URL, "k3"}, |
| @@ -445,7 +448,9 @@ func TestConfigCompat(t *testing.T) { | ||
| 445 | 448 | } |
| 446 | 449 | |
| 447 | 450 | config.Cfg = saved |
| 448 | - llama := write("llama.yaml", "provider: llamacpp\nmodel: qwen2.5-coder\ncontextWindow: 16384\n") | |
| 451 | + // fallback: "" keeps the default address whether llama-server runs or | |
| 452 | + // not (it has a fallback since ticket 217). | |
| 453 | + llama := write("llama.yaml", "provider: llamacpp\nmodel: qwen2.5-coder\ncontextWindow: 16384\nfallback: \"\"\n") | |
| 449 | 454 | if _, err := config.Load(llama); err != nil { |
| 450 | 455 | t.Fatalf("Load(llamacpp config): %v", err) |
| 451 | 456 | } |
| @@ -559,7 +564,7 @@ func TestDefaultURLs(t *testing.T) { | ||
| 559 | 564 | {"ollama", "http://localhost:11434/v1", "http://host.docker.internal:11434/v1"}, |
| 560 | 565 | {"kronk", "http://127.0.0.1:11435/v1", "http://host.docker.internal:11435/v1"}, |
| 561 | 566 | {"dmr", "http://localhost:12434/engines/v1", "http://host.docker.internal:12434/engines/v1"}, |
| 562 | - {"llamacpp", "http://127.0.0.1:8080/v1", ""}, | |
| 567 | + {"llamacpp", "http://127.0.0.1:8080/v1", "http://host.docker.internal:8080/v1"}, | |
| 563 | 568 | {"openai", "https://api.openai.com/v1", ""}, |
| 564 | 569 | } |
| 565 | 570 | for _, c := range cases { |
| @@ -108,10 +108,13 @@ func TestResolveURLPrecedence(t *testing.T) { | |||
| 108 | {"an explicit empty fallback disables it", "dmr", config.Config{BaseURL: down, Fallback: ptr("")}, nil, down, "not-needed"}, | 108 | {"an explicit empty fallback disables it", "dmr", config.Config{BaseURL: down, Fallback: ptr("")}, nil, down, "not-needed"}, |
| 109 | {"AGENT_BASE_URL wins without probing", "dmr", config.Config{BaseURL: up.URL, Fallback: ptr("")}, map[string]string{"AGENT_BASE_URL": down}, down, "not-needed"}, | 109 | {"AGENT_BASE_URL wins without probing", "dmr", config.Config{BaseURL: up.URL, Fallback: ptr("")}, map[string]string{"AGENT_BASE_URL": down}, down, "not-needed"}, |
| 110 | {"DMR_BASE_URL still works for dmr", "dmr", config.Config{BaseURL: up.URL, Fallback: ptr("")}, map[string]string{"DMR_BASE_URL": down}, down, "not-needed"}, | 110 | {"DMR_BASE_URL still works for dmr", "dmr", config.Config{BaseURL: up.URL, Fallback: ptr("")}, map[string]string{"DMR_BASE_URL": down}, down, "not-needed"}, |
| 111 | - {"llamacpp default is llama-server's port", "llamacpp", config.Config{}, nil, "http://127.0.0.1:8080/v1", "not-needed"}, | 111 | + // llamacpp falls back on the host like the other local servers |
| 112 | - {"llamacpp ignores DMR_BASE_URL", "llamacpp", config.Config{}, map[string]string{"DMR_BASE_URL": down}, "http://127.0.0.1:8080/v1", "not-needed"}, | 112 | + // since ticket 217 (its default address: TestDefaultURLs). |
| 113 | - {"llamacpp reads LLAMA_API_KEY when set", "llamacpp", config.Config{}, map[string]string{"LLAMA_API_KEY": "secret"}, "http://127.0.0.1:8080/v1", "secret"}, | 113 | + {"llamacpp falls back to the host's llama-server", "llamacpp", config.Config{BaseURL: down}, nil, "http://host.docker.internal:8080/v1", "not-needed"}, |
| 114 | - {"apiKeyEnv names another variable", "llamacpp", config.Config{APIKeyEnv: "MY_KEY"}, map[string]string{"MY_KEY": "k2"}, "http://127.0.0.1:8080/v1", "k2"}, | 114 | + {"llamacpp keeps a reachable baseUrl", "llamacpp", config.Config{BaseURL: up.URL}, nil, up.URL, "not-needed"}, |
| 115 | + {"llamacpp ignores DMR_BASE_URL", "llamacpp", config.Config{BaseURL: up.URL}, map[string]string{"DMR_BASE_URL": down}, up.URL, "not-needed"}, | ||
| 116 | + {"llamacpp reads LLAMA_API_KEY when set", "llamacpp", config.Config{BaseURL: up.URL}, map[string]string{"LLAMA_API_KEY": "secret"}, up.URL, "secret"}, | ||
| 117 | + {"apiKeyEnv names another variable", "llamacpp", config.Config{BaseURL: up.URL, APIKeyEnv: "MY_KEY"}, map[string]string{"MY_KEY": "k2"}, up.URL, "k2"}, | ||
| 115 | {"llmman falls back to the host's daemon", "llmman", config.Config{BaseURL: down}, nil, "http://host.docker.internal:17434/v1", "not-needed"}, | 118 | {"llmman falls back to the host's daemon", "llmman", config.Config{BaseURL: down}, nil, "http://host.docker.internal:17434/v1", "not-needed"}, |
| 116 | {"llmman keeps a reachable baseUrl", "llmman", config.Config{BaseURL: up.URL}, nil, up.URL, "not-needed"}, | 119 | {"llmman keeps a reachable baseUrl", "llmman", config.Config{BaseURL: up.URL}, nil, up.URL, "not-needed"}, |
| 117 | {"llmman reads LLMMAN_API_KEY when set", "llmman", config.Config{BaseURL: up.URL}, map[string]string{"LLMMAN_API_KEY": "k3", "LLAMA_API_KEY": "secret"}, up.URL, "k3"}, | 120 | {"llmman reads LLMMAN_API_KEY when set", "llmman", config.Config{BaseURL: up.URL}, map[string]string{"LLMMAN_API_KEY": "k3", "LLAMA_API_KEY": "secret"}, up.URL, "k3"}, |
| @@ -445,7 +448,9 @@ func TestConfigCompat(t *testing.T) { | |||
| 445 | } | 448 | } |
| 446 | 449 | ||
| 447 | config.Cfg = saved | 450 | config.Cfg = saved |
| 448 | - llama := write("llama.yaml", "provider: llamacpp\nmodel: qwen2.5-coder\ncontextWindow: 16384\n") | 451 | + // fallback: "" keeps the default address whether llama-server runs or |
| 452 | + // not (it has a fallback since ticket 217). | ||
| 453 | + llama := write("llama.yaml", "provider: llamacpp\nmodel: qwen2.5-coder\ncontextWindow: 16384\nfallback: \"\"\n") | ||
| 449 | if _, err := config.Load(llama); err != nil { | 454 | if _, err := config.Load(llama); err != nil { |
| 450 | t.Fatalf("Load(llamacpp config): %v", err) | 455 | t.Fatalf("Load(llamacpp config): %v", err) |
| 451 | } | 456 | } |
| @@ -559,7 +564,7 @@ func TestDefaultURLs(t *testing.T) { | |||
| 559 | {"ollama", "http://localhost:11434/v1", "http://host.docker.internal:11434/v1"}, | 564 | {"ollama", "http://localhost:11434/v1", "http://host.docker.internal:11434/v1"}, |
| 560 | {"kronk", "http://127.0.0.1:11435/v1", "http://host.docker.internal:11435/v1"}, | 565 | {"kronk", "http://127.0.0.1:11435/v1", "http://host.docker.internal:11435/v1"}, |
| 561 | {"dmr", "http://localhost:12434/engines/v1", "http://host.docker.internal:12434/engines/v1"}, | 566 | {"dmr", "http://localhost:12434/engines/v1", "http://host.docker.internal:12434/engines/v1"}, |
| 562 | - {"llamacpp", "http://127.0.0.1:8080/v1", ""}, | 567 | + {"llamacpp", "http://127.0.0.1:8080/v1", "http://host.docker.internal:8080/v1"}, |
| 563 | {"openai", "https://api.openai.com/v1", ""}, | 568 | {"openai", "https://api.openai.com/v1", ""}, |
| 564 | } | 569 | } |
| 565 | for _, c := range cases { | 570 | for _, c := range cases { |