You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
LLMTR is an OpenAI-compatible gateway (I maintain it). With this change OpenMuse can use it next to OpenAI, Anthropic and Google: MODEL=llmtr/<catalog id> plus LLMTR_API_KEY selects it, and the base URL defaults to https://llmtr.com/v1 (LLMTR_BASE_URL overrides it). Traffic goes through chat completions, following the same path as the OpenAI-compatible gateways in #80.
A hosted id such as llmtr/qwen3-8-27b keeps its llmtr/ prefix; a routed id such as qwen/qwen3.8-27b-free is sent unchanged. reasoning is not sent.
Touched: apps/server/src/engine/tanstack-agent.ts, apps/server/src/agent.ts, .env.example, README.md, new tests/llmtr-provider.test.ts, and an update to tests/model-provider.test.ts.
Live run from a fresh clone (pnpm install --frozen-lockfile, .env from .env.example with AGENT_BACKEND=model, MODEL=llmtr/qwen/qwen3.8-27b-free, LLMTR_API_KEY, WEB_SEARCH_ENABLED=false):
GET /api/health returned {"ok":true,"mode":"sample","agentConfigured":true}
POST /api/agent/tasks asking it to save a note artifact titled "Smoke" and then call finish_task reached succeeded in under 5 s. Both tool calls worked: the artifact was saved and finish_task returned pong.
A plain "Reply with the single word pong." task got the reply pong in about 2 s; it stopped at waiting_input because the model answered in text instead of calling finish_task, which is model behaviour rather than a transport issue.
Integration limits
Needs an llmtr- key; the run above used the free qwen/qwen3.8-27b-free.
Responses-only models (e.g. llmtr/leyla) and embedding models are not routed.
Server-only change; web, iOS and Android builds were not rebuilt.
Checked the id parsing against current tanstack-agent.ts before anything else: the three-segment specs are sound. The split ^([^/:]*)[/:](.*)$ puts everything after the first slash in the model, so MODEL=llmtr/qwen/qwen3.8-27b-free reaches the case as provider llmtr + model qwen/qwen3.8-27b-free, and the new tests pin both the hosted (llmtr/...) and routed (vendor/model) shapes. Reusing the existing openaiCompatibleText keeps this to chat completions, which matches the "Responses tool loop not supported" constraint, and the dedicated LLMTR_API_KEY gate lines up with agentConfigured.
Two things worth settling:
Versus the path that already exists — MODEL=openai/... + OPENAI_BASE_URL + OPENAI_CHAT_COMPLETIONS=true — the increment here is a default base URL, a separate key, chat-completions-by-default, and id normalisation. All reasonable, but it is the Nth OpenAI-compatible gateway to earn its own switch case, its own env var, and a hard-coded commercial host. A declarative compatible-gateway config (id prefix → base URL, key env, wire format) would let the next gateway in with zero changes to this switch. I track this closely because I maintain a downstream self-hosted fork and re-merge this provider block on every upstream bump.
llmtrModelId infers hosted vs routed from whether the id contains a /. That is only safe if the catalog guarantees every routed id is vendor/model; a routed id without a vendor segment would silently get an llmtr/ prefix and be misrouted. Worth stating that guarantee, or taking an explicit marker instead of the heuristic.
This branch has not been deployed
No deployments
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #212
What changed
LLMTR is an OpenAI-compatible gateway (I maintain it). With this change OpenMuse can use it next to OpenAI, Anthropic and Google:
MODEL=llmtr/<catalog id>plusLLMTR_API_KEYselects it, and the base URL defaults tohttps://llmtr.com/v1(LLMTR_BASE_URLoverrides it). Traffic goes through chat completions, following the same path as the OpenAI-compatible gateways in #80.A hosted id such as
llmtr/qwen3-8-27bkeeps itsllmtr/prefix; a routed id such asqwen/qwen3.8-27b-freeis sent unchanged.reasoningis not sent.Touched:
apps/server/src/engine/tanstack-agent.ts,apps/server/src/agent.ts,.env.example,README.md, newtests/llmtr-provider.test.ts, and an update totests/model-provider.test.ts.Verification
pnpm lint,pnpm typecheck,pnpm --dir apps/worker typecheck,pnpm build:server: passpnpm test: 524 passedpnpm install --frozen-lockfile,.envfrom.env.examplewithAGENT_BACKEND=model,MODEL=llmtr/qwen/qwen3.8-27b-free,LLMTR_API_KEY,WEB_SEARCH_ENABLED=false):GET /api/healthreturned{"ok":true,"mode":"sample","agentConfigured":true}POST /api/agent/tasksasking it to save a note artifact titled "Smoke" and then callfinish_taskreachedsucceededin under 5 s. Both tool calls worked: the artifact was saved andfinish_taskreturnedpong.pongin about 2 s; it stopped atwaiting_inputbecause the model answered in text instead of callingfinish_task, which is model behaviour rather than a transport issue.Integration limits
llmtr-key; the run above used the freeqwen/qwen3.8-27b-free.llmtr/leyla) and embedding models are not routed.