{"slug": "wiring-a-model-into-soloncode-dialects-the-apiurl-rules-and-the-timeouts-nobody", "title": "Wiring a Model into SolonCode: Dialects, the apiUrl Rules, and the Timeouts Nobody Warns You About", "summary": "SolonCode, a coding assistant built on Solon AI, ships without a bundled model, requiring users to wire one up manually. The project supports seven chat dialects—including OpenAI, Ollama, Gemini, and Anthropic—detected via the 'standard' field or the shape of the apiUrl, with OpenAI-compatible endpoints recommended for fastest setup. Key configuration fields include apiUrl, apiKey, model, timeout, and contextLength, with a 60-second default timeout that often needs adjustment for long tool-calling sessions.", "body_md": "SolonCode ships with no model. That is a deliberate product choice, not an omission: no bundled provider, no default key, no telemetry-backed endpoint you did not ask for. The upside is you can point it at DeepSeek, a local Ollama box, or an air-gapped corporate gateway with equal ease. The downside is that installing the binary does not give you a working assistant. You have to wire a model up first, and that is where most first-time users stall.\n\nThis is the follow-up to getting SolonCode installed. Here we get one model connected and *stable* — meaning it survives long tool-calling sessions, weak networks, and multi-file refactors without mysterious mid-task failures.\n\nYou can hand-edit `settings.json`\n\n. You should not, at least not on day one. The settings page validates your input and gives you a **Test connection** button, which is the single most useful debugging affordance in the whole product.\n\n```\nsoloncode web        # default port 4808\nsoloncode web 0      # pick any free port\nsoloncode web 1212   # explicit port\n```\n\nThen go to **Settings → LLM**, add a model, and hit test. Do not skip the test. A green test is the boundary between \"config problem\" and \"everything else.\"\n\nIf the port is taken, `soloncode web 0`\n\nsidesteps it. That is the official answer too.\n\nThis is the part that saves the most time. SolonCode sits on Solon AI, and Solon AI does not have a list of supported *vendors*. It has a list of supported **chat dialects** — request/response shapes. Any service that speaks one of those shapes works.\n\nThe built-in dialects and how they are detected:\n\n| Dialect | Detected by |\n|---|---|\n`openai` |\ndefault, or `apiUrl` ending in `.../chat/completions`\n|\n`openai-responses` |\n`standard=openai-responses` , or `apiUrl` ending in `.../v1/responses`\n|\n`ollama` |\n`standard=ollama` |\n`gemini` |\n`standard=gemini` , or `apiUrl` matching `.../v1beta/models/*` (usable since v3.8.1) |\n`gemini-interactions` |\n`standard=gemini-interactions` , or `.../v1beta/interactions/*` (usable since v4.0.3) |\n`anthropic` |\n`standard=anthropic` , or `apiUrl` ending in `.../v1/messages` (usable since v3.9.1) |\n`dashscope` |\n`standard=dashscope` , or `apiUrl` matching `.../v1/services/*`\n|\n\n`ChatConfig`\n\npicks the dialect from either `standard`\n\nor the shape of `apiUrl`\n\n. So the question is never \"does SolonCode support vendor X\" — it is \"which of these seven shapes does vendor X's endpoint speak.\"\n\nTwo useful notes straight from the docs: Claude also offers an OpenAI-compatible mode, so you can run it through the `openai`\n\ndialect instead of `anthropic`\n\n. Alibaba's Bailian exposes both its native DashScope protocol and an OpenAI-compatible one. When a provider gives you both, **the OpenAI-compatible endpoint is almost always the faster path to a green test.**\n\n`apiUrl`\n\nUnderneath, a model entry maps to Solon AI's `ChatConfig`\n\n:\n\n| Field | Required | Notes |\n|---|---|---|\n`apiUrl` |\nyes | the endpoint address |\n`apiKey` |\ndepends | token; may be empty for unauthenticated local services |\n`model` |\nyes | the API model id, not the console display name |\n`standard` |\nno | interface spec; defaults to `openai`\n|\n`timeout` |\nno |\n`Duration` , defaults to 60s\n|\n`headers` |\nno | extra headers — other options are all passed as headers |\n`proxy` |\nno | network proxy |\n`contextLength` |\nno | model context length; the docs flag this one as important |\n`defaultAutoToolCall` |\nno | defaults to `true` , since v3.8.4 |\n\nThere is also `provider`\n\n, which served the role of `standard`\n\nbefore v4.0. If you are reading an old config, that is what it is.\n\nNow the `apiUrl`\n\nrules, which are where the real failures live:\n\n`/chat/completions`\n\nor `/api/chat`\n\n) and the dialect is inferred from the tail.`standard`\n\n`#`\n\n`#`\n\nonward is stripped.One honest wrinkle: the `ChatConfig`\n\nreference describes `apiUrl`\n\nas \"the full address, not a baseUrl,\" while the dialect page explicitly supports baseUrl + `standard`\n\n. Both statements are in the official docs. My practical read: **paste the full address.** It removes a whole class of ambiguity, and the `#`\n\nrule exists precisely for the cases where appending would break you.\n\nField shapes are stable. Hostnames and model ids are not — providers rename models and retire old ones. Always confirm the current id in the vendor console, and never put a real key in a doc, a screenshot, or a commit.\n\n**A cloud provider over an OpenAI-compatible endpoint** — the common case, and the one to start with:\n\n```\napiUrl: \"https://api.example.com/v1/chat/completions\"\napiKey: \"sk-xxxxxx\"\nmodel: \"<copy the exact id from the console>\"\ntimeout: \"180s\"\n```\n\nFind the \"OpenAI compatible\" base URL in your provider's console, leave `standard`\n\nat its default, and copy the model id rather than typing it from memory. The console's display name is frequently not the API id.\n\n**A local Ollama instance**, from the official example:\n\n```\nChatModel chatModel = ChatModel.of(\"http://127.0.0.1:11434/api/chat\")\n        .standard(\"ollama\")\n        .model(\"llama3.2\")\n        .build();\n```\n\nThe `model`\n\nvalue is whatever you pulled — if you ran `ollama run deepseek-r1:7b`\n\n, you write `deepseek-r1:7b`\n\n. Note that the dialect table lists only `standard=ollama`\n\nas the detection rule; the `/api/chat`\n\ntail-matching behavior appears in the dialect's source, not the table. Declaring `standard`\n\nexplicitly is the safe move.\n\nAlso worth setting expectations: a small local model that connects fine may still be unreliable at multi-file refactors and long tool chains. That is a capability ceiling, not a config bug.\n\n**A corporate gateway.** Fill `apiUrl`\n\nper the gateway's own docs, put tenant or custom auth headers in `headers`\n\n, use the model names from the gateway's allow-list rather than the public cloud names, and if the gateway path is unusual, apply the `#`\n\nsuffix. Keep this one in the **workspace** scope so a client-specific gateway does not leak into every other project on your machine.\n\nSettings persist to `settings.json`\n\nin one of two places:\n\n| Scope | Path | Good for |\n|---|---|---|\n| user | `~/.soloncode/settings.json` |\nmodels, skill pool, and MCP servers shared across projects |\n| workspace | `.soloncode/settings.json` |\nmodels, APIs, LSP, and mounts for this project only |\n\nThe merge order is documented plainly: the user-level file is read first, then the workspace file, and **workspace config overrides or supplements user config**. Saving from the settings page tries to write into the running engine, so a restart is often unnecessary — the docs say \"not necessarily,\" so if your model list does not refresh, restarting the web process is the cheap fix.\n\nPractical split: your personal default model goes global; anything client- or gateway-specific goes workspace.\n\nIf `.soloncode/settings.json`\n\nholds a real key, it does not belong in version control:\n\n```\n.soloncode/settings.json\n.soloncode/logs/\n```\n\nShip a `settings.example.json`\n\nwith placeholder values instead, and let people copy it locally.\n\nOne exposure path deserves explicit attention: **if you bind the web UI to anything beyond localhost, set webAuthUser and webAuthPass.** Leave them blank and authentication is off. An unauthenticated SolonCode web endpoint on your LAN hands over your conversations, your tool permissions, and — since the keys live in the settings file it manages — effectively your API credentials. Sandboxing (\n\n`sandboxMode`\n\n, `sandboxAllowUserHome`\n\n, both default `true`\n\n) and human-in-the-loop review are a separate line of defense. Getting a model connected is not a reason to switch either of them off.A coding agent makes many round trips per task, each carrying context and tool descriptions. So connectivity is necessary but not sufficient. The general settings that govern stability, with their documented defaults:\n\n| Setting | Default | What it controls |\n|---|---|---|\n`apiRetries` |\n3 | API retry count |\n`modelRetries` |\n3 | model retry count |\n`mcpRetries` |\n3 | MCP retry count |\n`maxTurns` |\n20 | max rounds in a single task |\n`autoRethink` |\ntrue | allow self-reflection retries |\n`logLevel` |\nINFO | TRACE / DEBUG / INFO / WARN / ERROR |\n`logMaxHistory` |\n7 | days of log archives kept |\n\nRetries help with flaky networks and nothing else. A 401 or a wrong model id will fail identically three times and just triple your log volume.\n\nThat 60-second `timeout`\n\ndefault deserves a second look. For plain chat it is fine. For a reasoning model chewing on a long context behind a slow proxy, it is easy to hit. Raising it is reasonable; raising it to effectively-infinite is not, because an invisible hang is harder to diagnose than a fast failure.\n\nLong tasks accumulate conversation turns and tool results. Compression summarizes older content to relieve context pressure. Two settings and a naming caveat:\n\n`compressionThresholdPercent`\n\ndefaults to **75** — compression triggers when 75% of the context window is used. Both doc pages agree on this one.\n\nThe message-count trigger defaults to **100**, but appears under two different names in the docs: the settings reference calls it `summaryWindowSize`\n\n, while the compression guide calls it `compressionThresholdMessages`\n\n. Similarly, `sessionWindowSize`\n\n(how many recent messages a new instruction carries) is documented as **8** on one page and **12** on the other. I am not going to guess which is authoritative — check what your settings page actually shows and treat that as truth for your version.\n\nThe official tuning ranges, by model context window:\n\n| Context | Message threshold | Percent threshold | Rationale |\n|---|---|---|---|\n| 128k | 30–50 | 65–70 | balanced, fits most coding tasks |\n| 256k | 60–100 | 70–75 | keeps more tool chain, suits complex refactors |\n| 1m | 100–200 | 75–80 | compress less; watch cost and latency |\n\nAnd the symptom-to-knob mapping, which is the genuinely useful part:\n\n| Symptom | Adjustment |\n|---|---|\n| agent keeps re-reading a file it just read | raise the message threshold |\n| model reports context overflow | lower the percent threshold |\n| summarization is slow or expensive | raise both thresholds |\n| small model flaky on complex tasks | lower `sessionWindowSize`\n|\n\nIf a task consistently gets cut off mid-way, `maxTurns`\n\nmay be too low. But if the model is spinning in circles, tighten the task description instead. More turns will not fix an underspecified request.\n\nThe official checklist is short: verify `apiUrl`\n\n, `apiKey`\n\n, the model name, and your network proxy. Expanded into something you can actually run through:\n\n`apiUrl`\n\nthe chat endpoint, not the vendor's homepage? Did you drop the `/v1`\n\nor `/chat/completions`\n\nsegment?`standard=ollama`\n\nset, or the full `/api/chat`\n\naddress used?`#`\n\nsuffix.Still stuck? Set `logLevel`\n\nto DEBUG or TRACE, reproduce the failure once, and read `.soloncode/logs/`\n\n. Grep for `timeout`\n\n, `401`\n\n, `403`\n\n, `dialect`\n\n, `model`\n\n. On dialect mismatch specifically, the docs name two causes: a wrong `standard`\n\n, or a missing dependency package.\n\nThere is one more failure mode worth naming, because it looks like a config problem and is not: **the connection tests green but the coding output is poor.** Check whether you launched from the project root (wrong working directory means no project context), whether the project has an `AGENTS.md`\n\ndescribing build and test commands, and whether the session is simply too polluted — a fresh session often fixes it. If none of that helps, you are looking at a model capability limit, and the fix is a different model, not a different config value.\n\nRun these in your project root before trusting the setup with real work:\n\n| Step | Input | Pass condition |\n|---|---|---|\n| 1 | `hello` |\nclean response, no auth error |\n| 2 | \"list the top-level files in this workspace, change nothing\" | output matches `ls`\n|\n| 3 | same question on a second model, if configured | both answer |\n| 4 | temporarily break the key, hit Test connection | it fails — proving the button is honest |\n| 5 | restore the key, test again | green |\n\nStep 4 is the one people skip and the one that matters most. A test button you have never seen fail is a test button you cannot trust.\n\nOnce all five pass, add a second model and split your traffic: a cheap fast model as the default for reading code and small fixes, a stronger one you switch to deliberately for cross-module refactors and hard bugs. Running every task on your most expensive model is the fastest way to a surprising invoice, and it is rarely the difference between success and failure. Task description quality usually matters more than model tier.\n\n| Topic | Link |\n|---|---|\n| SolonCode |\n|\n\nDefaults and field names shift between versions, and the two documentation pages disagree on a couple of them today. When in doubt, the settings page in your installed build is the authority. Model ids and endpoint paths belong to your provider — re-check those in the console before you file a bug against the config.", "url": "https://wpnews.pro/news/wiring-a-model-into-soloncode-dialects-the-apiurl-rules-and-the-timeouts-nobody", "canonical_source": "https://dev.to/solonjava/wiring-a-model-into-soloncode-dialects-the-apiurl-rules-and-the-timeouts-nobody-warns-you-about-14ke", "published_at": "2026-08-03 22:29:49+00:00", "updated_at": "2026-08-03 22:40:01.565633+00:00", "lang": "en", "topics": ["developer-tools", "large-language-models", "ai-tools"], "entities": ["SolonCode", "Solon AI", "DeepSeek", "Ollama", "OpenAI", "Gemini", "Anthropic", "Alibaba Bailian"], "alternates": {"html": "https://wpnews.pro/news/wiring-a-model-into-soloncode-dialects-the-apiurl-rules-and-the-timeouts-nobody", "markdown": "https://wpnews.pro/news/wiring-a-model-into-soloncode-dialects-the-apiurl-rules-and-the-timeouts-nobody.md", "text": "https://wpnews.pro/news/wiring-a-model-into-soloncode-dialects-the-apiurl-rules-and-the-timeouts-nobody.txt", "jsonld": "https://wpnews.pro/news/wiring-a-model-into-soloncode-dialects-the-apiurl-rules-and-the-timeouts-nobody.jsonld"}}