Skip to content

feat: add LLMTR as a model provider - #213

Open
knowhycodata wants to merge 2 commits into
CopilotKit:mainfrom
knowhycodata:add-llmtr-provider
Open

knowhycodata wants to merge 2 commits into
CopilotKit:mainfrom
knowhycodata:add-llmtr-provider

Conversation

@knowhycodata

Copy link
Copy Markdown

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> 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.

Verification

  • pnpm lint, pnpm typecheck, pnpm --dir apps/worker typecheck, pnpm build:server: pass
  • pnpm test: 524 passed
  • 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.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 29, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ⚠️ Failed 2026-10-29T08:04:08.214185Z
We couldn’t complete this review. Comment @codex review to try again.
206c104 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@caspianchan31

Copy link
Copy Markdown

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:

  1. 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.
  2. 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] Add LLMTR as a model provider

2 participants