cyberine
Providers

OpenRouter API

  • Kind: OpenAI-compatible aggregator (300+ models, 50+ providers, one key)
  • Official docs: https://openrouter.ai/docs
  • Cyberine adapter: LoopAgentAdapter (ids loop-deepseek-openrouter, build worker loop-openrouter-build)
  • Fallback for the model-level DeepSeek worker when no DEEPSEEK_API_KEY is set.
  • Researched/verified: 2026-06-07 — confidence high.
  • DeepSeek section re-verified 2026-08-24 (T686) against the live catalog — see DeepSeek ids (V4) and Pricing below.

Base URL & auth

Base URLhttps://openrouter.ai/api/v1
Auth headerAuthorization: Bearer <OPENROUTER_API_KEY>
Keyshttps://openrouter.ai/settings/keys
Optional headersHTTP-Referer: <site>, X-Title: <name> — attribution only (affect public rankings), not required for server use

No per-provider auth — OpenRouter wraps every provider under one key.

Endpoints

Method + pathPurpose
POST /chat/completionsOpenAI-compatible chat completions + OpenRouter extensions (provider routing, reasoning).
GET /modelsCatalog with pricing, context_length, supported_parameters; add auth for per_request_limits.
GET /generation?id=<id>Usage/metadata for a past generation.
GET /keyCredit balance, usage, limit_remaining.
GET /openapi.{yaml,json}Full OpenAPI spec.

Models

Model ids use vendor/model form. Enumerate live via GET /api/v1/models — the catalog changes.

Model idNotes
deepseek/deepseek-v4-pro-0813Cyberine default (OPENROUTER_MODEL) since T691. Dated current V4 Pro GA — see DeepSeek ids (V4) below for why the date suffix is mandatory here.
deepseek/deepseek-r1671B/37B, 164K ctx, $0.70/$2.50, MIT, open reasoning tokens.
anthropic/claude-sonnet-4.61M ctx, $3/$15. Note the dot, not hyphen (see gotcha).
google/gemini-2.5-flash1M ctx, $0.30/$2.50, built-in thinking.
moonshotai/kimi-k2-09051T/32B, 262K ctx, $0.60/$2.50. (Repo's kimi-k2.6 is not an OpenRouter slug — see gotcha.)
openrouter/autoAuto-router picks the best model.
~vendor/model-latestTilde-prefixed dynamic aliases → newest version.

DeepSeek ids (V4) — re-verified live 2026-08-25 (T691)

Enumerated via curl https://openrouter.ai/api/v1/models (raw JSON — a summarizing fetch drops exactly the id/pricing precision this table needs):

Model idModalitiesNotes
deepseek/deepseek-v4-flash-vision-exp["text","image"]The only OpenRouter DeepSeek id that accepts images (new 2026-08-21).
deepseek/deepseek-v4-flash-0731["text"]Current V4 Flash GA, dated id. CYBERINE_JUDGE_MODEL_WEAK's default and the flash variant of loop-openrouter-build since T691. 29 upstream vendors.
deepseek/deepseek-v4-pro-0813["text"]Current V4 Pro GA, dated id. OPENROUTER_MODEL's default since T691. canonical_slug: deepseek/deepseek-v4-pro-20260813, created 2026-08-12, 15 upstream vendors.
~deepseek/deepseek-v4-flash-latest["text"]Floating alias; currently targets flash-0731.
deepseek/deepseek-v4-pro["text"]Legacy undated alias — resolves to canonical_slug: deepseek/deepseek-v4-pro-20260423, an OLDER GA than the dated -0813 id above. Was OPENROUTER_MODEL's default until T691 repointed it; still valid to pin, but DeepSeek themselves no longer serve it (see below).
deepseek/deepseek-v4-flash["text"]Same pattern — legacy undated alias, canonical_slug dated 0423. Was CYBERINE_JUDGE_MODEL_WEAK's default until T691.

Dated-vs-stable id trap: DeepSeek's own direct API exposes stable, undated ids (deepseek-v4-flash, deepseek-v4-pro) that always point at the current GA — see deepseek.md. OpenRouter inverts this: its DATED ids (-0731, -0813) are the ones that track a specific GA release, while its UNDATED ids (deepseek/deepseek-v4-pro, deepseek/deepseek-v4-flash) are legacy aliases frozen on an older release. Copying an id between the two routes on the assumption "no date suffix = latest" silently pins the OLDER model on OpenRouter.

How to tell them apart — read the ENDPOINTS listing, not the model page (the page and the catalog's top-level pricing field both disagree with it; see Pricing below):

curl https://openrouter.ai/api/v1/models/deepseek/deepseek-v4-pro/endpoints        # 17 vendors
curl https://openrouter.ai/api/v1/models/deepseek/deepseek-v4-pro-0813/endpoints   # 15 vendors

Live 2026-08-25 the differing vendor counts and price ceilings are what separate them, but the decisive field is provider_name: the undated aliases have no "DeepSeek" endpoint at all (17 third-party re-hosts topping out at Azure $1.91/$3.83 for pro-0423, and 17 topping out at $0.44/$1.32 for flash-0423), while each dated current-GA id does (pro-0813 at $0.66/$1.98, flash-0731 at $0.22/$0.66 — matching DeepSeek-direct's own off-peak rates to the cent). DeepSeek has walked away from serving its own frozen 0423 weights here.

T691 decision: the Cyberine defaults are DATED, and the re-pointing burden is accepted

Cyberine repointed rather than freeze. OPENROUTER_MODEL, JUDGE_MODEL, CYBERINE_JUDGE_MODEL_STRONG, CYBERINE_JUDGE_MODEL_WEAK, and loop-openrouter-build's model + reasoning/flash variants now default to the dated current GAs. Before T691 every dispatch through loop-deepseek-openrouter / loop-openrouter-build silently ran the 2026-04-23 GA while the code and docs read as current. "Leave it undated and document the staleness as deliberate" was rejected for one reason above all: no upstream party stands behind the alias any more — see the provider_name finding above.

The burden this creates, stated plainly: a dated id goes stale by construction. When DeepSeek ships the next V4 GA, OpenRouter mints a new -MMDD id and Cyberine's defaults keep running the previous one until someone bumps them. Three things bound it:

BoundWhat it is
One edit sitesrc/core/openrouterModelIds.ts holds the two constants; config.ts, workerProfiles.ts, and selectJudgeModel.ts's customized-weak sentinel all read them. Add a modelPricing.ts row for the new id too, or cost estimation silently drops to the coarse provider-level fallback.
A scheduled ownerRecurring chore R02 (the CHANGELOG-WATCH sweep, every 7d) already treats "new model id" as a material upstream change; its OpenRouter row now names this check explicitly.
An operator escape hatchOPENROUTER_MODEL overrides the default with no code change, so a stale constant is a wrong default, never a wall.
A regression guardnpm run selftest:openrouter-model-default (offline) asserts both directions: every OpenRouter-routed default is dated, every DeepSeek-direct / dual-route id stays undated, the DeepSeek-direct judge sentinel still yields a bare id, each dated default has a modelPricing.ts row, and no src/ file re-hardcodes an undated alias as an OpenRouter default.

2026-09-10 (kq2ne, R02 sweep): deepseek/deepseek-v4.1-flash appeared; NOT adopted, and this route just became more important, not less. DeepSeek shipped V4.1-Flash on 2026-09-10 and the new line is live here: 1M context, $0.15/$0.60 per 1M, canonical_slug: null, and 4 endpoints — against 29-30 for the dated deepseek/deepseek-v4-flash-0731. Not adopted, for the reason this section already settles: it is UNDATED, so pinning it reproduces exactly the drift T691 removed, and 4 endpoints is thin routing next to the dated line's 30. The adoptable form is a dated -MMDD V4.1 id; re-check for one each sweep. Both existing constants are still the newest dated ids, so nothing is stale today.

The asymmetry worth recording: from 2026-09-14 this route is the only one that still reaches a real V4-Pro. DeepSeek-direct routes deepseek-v4-pro to V4.1 Flash on that date (k9tvx), while OpenRouter dispatches DATED snapshots — deepseek/deepseek-v4-pro-0813 keeps resolving to the 2026-08-13 Pro build. The dated-id burden this section accepted as a cost is what makes the OpenRouter path immune to an upstream re-route, which is the strongest argument yet for keeping it.

Re-confirmed 2026-09-04 (km6mp), with a fifth and decisive reason: the alias serves NOTHING. GET /api/v1/models/~deepseek/deepseek-v4-flash-latest/endpoints returns 0 endpoints and a canonical_slug of null, against 30 endpoints for deepseek/deepseek-v4-flash-0731 on the same call minutes apart. So the floating alias is listed in the catalogue but no provider serves it: adopting it would not merely cost reproducibility, it would make every loop-openrouter-build dispatch fail with no route. The four T691 reasons below stand unchanged and this one supersedes the need to weigh them. Also re-verified the same day: the two dated constants in src/core/openrouterModelIds.ts are still the newest dated ids (no newer -MMDD upstream), and there is still no ~deepseek/deepseek-v4-pro-latest at all. Two ids new to the route since the last sweep are recorded as available and NOT adopted: deepseek/deepseek-v4-flash-vision-exp (canonical ...-20260821, DeepSeek's own experimental vision model) and :batch variants of both dated ids.

~...-latest was considered and rejected. A real floating alias exists for flash (~deepseek/deepseek-v4-flash-latest) but not for pro — verified against the full 417-model catalog 2026-08-25. Adopting it for flash alone would make one tier self-maintaining while the other still needs a manual bump; a moving pointer cannot carry a stable modelPricing.ts row (its catalog price already differs from flash-0731: $0.040/$0.080 vs $0.066/$0.132); a run's recorded model id would stop identifying which weights actually ran, breaking .local/runs/<id>/run.json reproducibility; and zsh performs filename expansion on the right-hand side of assignments, so OPENROUTER_MODEL=~deepseek/... is a live tilde-expansion footgun in this repo's own shell.

Two ids deliberately stay undated. DEEPSEEK_MODEL / OPENCODE_MODEL / CYBERINE_OPENCODE_DEEPSEEK_MODEL reach DeepSeek directly (OpenCode's deepseek/ namespace authenticates with DEEPSEEK_API_KEY, not an OpenRouter key), where undated is the current pointer and a dated id is rejected with HTTP 400. And CYBERINE_ROUTER_MODEL is a dual-route id: router.ts strips the deepseek/ prefix and sends it to DeepSeek-direct when no OpenRouter key is configured, so only the undated form resolves on both branches — it keeps running the frozen 0423 alias on the OpenRouter branch, accepted for one cheap classification call.

Key request params

  • Standard OpenAI fields: model, messages, max_tokens / max_completion_tokens, temperature, top_p, top_k, stream, response_format, tools / tool_choice, seed, stop, penalties, logprobs, parallel_tool_calls
  • reasoning — thinking control; reasoning_effort: xhigh|high|medium|low|minimal|none
  • provider — provider-routing object (only, sort, zdr, BYOK …)
  • structured_outputs, web_search_options
  • Suffix shortcuts on a slug: :nitro (sort by throughput), :floor (sort by price), :free

Notable features

  • OpenAI drop-in (works with openai SDK by setting baseURL).
  • Provider routing + auto schema translation for non-OpenAI providers.
  • Streaming over SSE; post-stream errors arrive as SSE events with HTTP 200.
  • GET /models with auth returns per_request_limits scoped to your balance.
  • BYOK, ZDR routing (provider.zdr:true), free tier (:free ids).
  • Unsupported params are silently ignored (schema normalized across providers).

Gotchas

  • Credit reservation: OpenRouter reserves the full max_tokens against your balance up front. On a credit-limited key this returns HTTP 402 immediately even if real usage would be tiny → keep max_tokens conservative. (This is why Cyberine keeps LOOP_MAX_TOKENS low on OpenRouter fallback.)
  • 402 = insufficient credits; a negative balance also 402s free models.
  • 503 = no provider meets routing constraints (e.g. provider.only/zdr) — config issue, not transient.
  • Model id format is vendor/model — verify slugs via GET /models; wrong separator → model-not-found.
  • Repo's kimi-k2.6 is unconfirmed on OpenRouter (only moonshotai/kimi-k2-0905 confirmed). Cyberine reaches Kimi via Moonshot-direct / OpenCode, not OpenRouter, so this is informational.
  • Repo's claude-sonnet-4-6 (hyphen) vs OpenRouter's anthropic/claude-sonnet-4.6 (dot).

Pricing

No markup in principle — each listing shows an upstream provider's own rate. The Jun 2026 example here (deepseek/deepseek-v4-pro $0.435/$0.87) was a promo rate that expired 2026-05-31; it is stale and has been removed rather than replaced with a new point figure, because live 2026-08-24 measurement (below) shows OpenRouter's own numbers for a single model id are NOT one stable price.

Unresolved discrepancy, recorded rather than picked: for deepseek/deepseek-v4-pro-0813, GET /api/v1/models reports "prompt":"0.000001122","completion":"0.000003366" ($1.122/$3.366 per 1M) at the catalog's top level, while the model's own human-readable page (openrouter.ai/deepseek/deepseek-v4-pro-0813) advertises a lower "$0.66 per million input tokens, $1.98 per million output tokens" for the SAME id — both re-confirmed live 2026-08-24 via raw curl (JSON field and page HTML respectively), cause unexplained. Drilling into GET /api/v1/models/deepseek/deepseek-v4-pro-20260813/endpoints shows why a single number is misleading: OpenRouter multiplexes this one model id across (at last count) 15 upstream compute vendors, each billed at its own independently-set rate — DeepSeek's own endpoint is cheapest at $0.66/$1.98 (matching the page), others run up to Phala at $1.45/$4.36 per 1M — and which vendor actually serves a given request depends on OpenRouter's live routing/availability, not a fixed catalog price. Do not treat either the page price or the /models price as authoritative; Cyberine's own conservative fallback for this route (src/store/creditLedger.ts) is set from this per-endpoint spread rather than either single figure — see that file's openrouter row for the exact reasoning. Other rows remain approximate: anthropic/claude-sonnet-4.6 $3/$15; google/gemini-2.5-flash $0.30/$2.50. Catalog: https://openrouter.ai/pricing

Cyberine integration notes

  • Registered as loop-deepseek-openrouter only when DEEPSEEK_API_KEY is absent and OPENROUTER_API_KEY is set; build variant is loop-openrouter-build.
  • LOOP_MAX_TOKENS matters more here than on DeepSeek-direct because of the credit-reservation behavior above.

Sources