Local-first, free-first, fallback-built-in LLM router. Claude Code / OpenAI compatible.
Project description
CodeRouter
Claude Code でローカル LLM を使うと tool calling が壊れる問題、
ルーター側で直します。
qwen2.5-coder:7B、phi-4、mistral-nemo など小型・量子化モデルがしばしばやる
「{"name":..., "arguments":...} を plain text として吐いてしまう」現象を、
CodeRouter の tool-call 修復パスが Claude Code に届く前に
有効な tool_use ブロックへ復元します。
「ローカル LLM にしたら agentic coding ができない」と諦めていた人へ。
これで本気で使える local-first agent が組めます。
English · 日本語 · 利用ガイド · Security
10 分で動かす → Quickstart | 詳しく → 利用ガイド | 無料で回す → 無料枠ガイド | 要るか判定 → 要否判定
CodeRouter が他に何をやってくれるか
coderouter doctor --check-model <provider>でそのモデルが tool call / streaming / thinking に対応しているかを実プローブで即診断し、足りない宣言をコピペ可能な YAML パッチで教えてくれる- reasoning leak(
<think>...</think>タグや<|turn|>など 6 種の stop マーカー漏れ)を SSE チャンク境界を跨いで自動スクラブ - ローカル → 無料クラウド(OpenRouter free / NVIDIA NIM 40 req/min 無料枠)→ 有料 API の自動フォールバック。既定で
ALLOW_PAID=falseなので課金はオプトイン制 - v1.9.0 から Anthropic prompt cache の hit/miss を全リクエストで記録、
/dashboardで hit_rate / saved tokens / USD コストが見える(cache savings は別計算) - v1.9.0 から adaptive routing で「いま遅い provider」を自動降格(profile に
adaptive: trueを付けるだけ)、tool-loop guard で stuck loop を検出(warn/inject/breakの 3 段階 policy) - ランタイム依存 5 個(
fastapi/uvicorn/httpx/pydantic/pyyaml)— 純 Python、MIT、テスト 830 本緑
→ Claude Code / gemini-cli / codex + Ollama / llama.cpp / NVIDIA NIM で、破綻しない local-first agent が組める
ドキュメント
| 目的 | ドキュメント | 内容 |
|---|---|---|
| 動かす | Quickstart | Claude Code / codex を local Ollama で 10〜15 分で動かす最短手順 |
| 使いこなす | 利用ガイド | HW 別モデル選定・チューニング既定値・OS ごとの起動フロー・doctor / verify の読み方 |
| 無料で回す | 無料枠ガイド | NVIDIA NIM 40 req/min × OpenRouter 無料枠の使い分け・live 検証済みモデル表・地雷 5 点 |
| 要るか判断する | 要否判定ガイド | エージェント × モデルの詳細マトリクスで「そもそも自分に必要か」を決める |
| 詰まったとき | トラブルシューティング | doctor の使い方、.env の export 必須、Ollama サイレント失敗 5 症状、Claude Code 連携の罠 |
| llama.cpp 直叩き | llama.cpp 直叩きガイド | Qwen3.6 を Ollama 詰みから救出する経路。llama.cpp build → Unsloth GGUF → llama-server → CodeRouter 接続を 7 step で(v1.8.3 実機検証済) |
| LM Studio 直接 | LM Studio 直接ガイド | qwen35 / qwen35moe を救う第 2 経路。LM Studio 0.4.12+ Local Server 経由で OpenAI 互換 + Anthropic 互換 (/v1/messages) 両対応、prompt caching 透過(v1.8.4 実機検証済) |
| 安全に使う | セキュリティ方針 | 脅威モデル・秘密情報の扱い・脆弱性報告経路 |
| 履歴 | CHANGELOG | 全リリース履歴(最新: v1.9.0 — Cache observability (A) + Cross-backend cache passthrough (B) + Adaptive routing (C) + Cost-aware dashboard (D) + Tool-loop guard (E) を 1 minor で出荷) |
| 設計を追う | plan.md | 設計不変項・マイルストーン・今後のロードマップ |
English versions: Quickstart · Usage guide · Free-tier guide · When you need it · Troubleshooting · llama.cpp direct · LM Studio direct · Security
CodeRouter で何が楽になるか
CodeRouter は、コーディングエージェント(Claude Code / gemini-cli / codex / 素の OpenAI SDK)と、その裏の LLM の間に挟まる小さなルーターです。ツールの向き先を 1 本のエンドポイントにまとめておけば、CodeRouter がプロバイダを順に選びます — まずローカル Ollama / llama.cpp、次に無料クラウド (OpenRouter free)、有料 API は明示的に opt-in したときだけ。
初心者が普通に使うとぶつかる「地雷」を、CodeRouter がまとめて面倒見てくれます:
- API キー無し・Anthropic 課金無しのまま Claude Code を回せる。 ローカルモデル(または OpenRouter 無料枠)が答えます。有料プロバイダは
ALLOW_PAID=trueを明示したときだけ呼ばれます。 - 返答が途中で消えない。 1 プロバイダが途中で落ちてもクライアントには綺麗な
event: errorが 1 本届くだけ — 2 モデルを継ぎ接ぎしたフランケン応答にはなりません。 - うっかり課金しない。
ALLOW_PAID=falseが既定。有料プロバイダをチェーンから外したときは理由を 1 行ログに出すので、なぜ使われなかったかが後で grep できます。 - ローカル Ollama の上で Claude Code / gemini-cli / codex が動く。 Claude Code は Anthropic のワイアフォーマット、Ollama / llama.cpp / LM Studio は OpenAI。CodeRouter が双方向に変換し、小さいローカルモデルがテキストで吐いてしまう
{"name":..., "arguments":...}を tool_use ブロックへ復元してからエージェントに渡します。 - 「なぜか動かない」の原因を教えてくれる。
coderouter doctor --check-model <provider>が 6 種類の典型的な失敗モード(コンテキスト切り詰め / ストリーム早期終了 / ツール呼び出し欠落 / reasoning フィールド漏れ / 認証 / Anthropicthinking)を実地プローブし、コピペ可能な YAML パッチを出します。 - 監査しやすい。 ランタイム依存 5 個(LiteLLM は 100+)。Pure Python、MIT、テスト 710 本緑。
クライアント (Claude Code / OpenAI SDK / gemini-cli / codex / curl)
│
▼
CodeRouter ──► ① ローカルモデル (Ollama / llama.cpp — 無料・最優先)
② 無料クラウド (OpenRouter qwen3-coder:free, gpt-oss-120b:free, …)
③ 有料クラウド (Claude / GPT — ALLOW_PAID=true のときだけ)
ライブダッシュボード
coderouter dashboard は、障害調査中に実際に知りたい「いま何が起きているか」に、ログを grep せずに即答するための画面です:
- どのプロバイダが生きていて、いま応答しているのは誰か
- フォールバックは直近で発火したか、発火したなら何が理由か
- 有料ゲートは閉じたままか(= まだ無料経路で走っているか)
- 直近数分のリクエスト流量はどうか
- ついさっき何が起きたか — 直近 N 件のイベントが時系列で
上のスクリーンショットは scripts/demo_traffic.sh で混合トラフィック(normal / stream / burst / fallback / paid-gate)をローカルのモックに流している最中のものです。左上から: プロバイダ状態、フォールバック & ゲート状態、requests/min スパークライン、直近イベント(新しい順)、usage mix。
CodeRouter は自分に必要か?
CodeRouter は wire 翻訳 + 絆創膏の層です。エージェントが既に OpenAI を喋り、モデルがお行儀良く動くなら、多くの場合不要です。下の 2 つの表が短縮版で、フルの判断ガイドは docs/when-do-i-need-coderouter.md にあります。
エージェント別 — Ollama に直接向けられるか:
| エージェント | wire | Ollama 直続き | CodeRouter 必要? |
|---|---|---|---|
| Claude Code | Anthropic | ✕ | 必須 — wire 翻訳 |
| Codex CLI / 素の OpenAI SDK | OpenAI | ◯(OPENAI_BASE_URL) |
オプション |
| gemini-cli | Gemini | ✕ | 必要(アダプタ) |
| GitHub Copilot CLI | GitHub 独自 | ✕(バックエンド固定) | 無力 — 差し替え不可 |
モデル別 — 直続きで崩れるか:
| モデル | 出力綺麗? | 効く CodeRouter フィルタ |
|---|---|---|
llama3.1 / mistral-nemo / phi-4 / qwen2.5(-coder でない) |
◯ | — |
qwen2.5-coder |
✕ — <think> 漏れ |
strip_thinking |
gpt-oss / deepseek-r1 / qwq |
✕ — 推論過程漏れ | strip_thinking |
| 小さい量子化(Q2 / Q3)、テンプレ不整合 Modelfile | ✕ — tool JSON 壊れ / stop marker 漏れ | repair_tool_call / strip_stop_markers |
OpenAI 互換エージェント + お行儀の良いモデル + フォールバック不要、の構成なら OPENAI_BASE_URL=http://localhost:11434/v1 の一行で済みます。それ以外 — 特に Claude Code、reasoning 系モデル、mid-stream ガード付きの多段フォールバック — が CodeRouter の仕事どころです。
直接つなげばいいのでは?
- Ollama / llama.cpp / LM Studio を直接叩く。 確かに速くて無料ですが、Claude Code(および
/v1/messagesを前提にした多くのエージェント)は Anthropic 形式で話します — 上記サーバは OpenAI 形式だけ。結果、"unsupported endpoint" で弾かれるか、モデルが tool 呼び出しを素のテキストで吐いて tool-use が静かに壊れるかのどちらかです。CodeRouter は双方向に変換し、エージェントに渡る前に JSON を修復します。 - LiteLLM。 良いプロダクトですが依存が重く(推移的依存 100+)、
/v1/messagesをネイティブに出しません。 - OpenRouter 単独。 無料枠はレート制限があり、たまに落ちます。有料オンリーは新規ユーザーや CI には敷居が高い。
設計不変項と今後のロードマップは plan.md を参照。初心者向けに「同じローカルモデルでも、なぜ人によって動く/動かないが分かれるのか」を解説する記事は Zenn / Note で別途公開しています。
クイックスタート(3 コマンド)
v1.7.0 で PyPI 公開、v1.8.0 で用途別 4 プロファイル + Z.AI/GLM 連携、v1.8.2 で doctor probe を thinking モデル対応、v1.9.0 で Cache observability / Adaptive routing / Cost-aware dashboard / Tool-loop guard を pillar 化しました。uvx 一発で動きます (Python 3.12 以上必須):
# 1. サンプル設定を置く
mkdir -p ~/.coderouter
curl -fsSL https://raw.githubusercontent.com/zephel01/CodeRouter/main/examples/providers.yaml \
> ~/.coderouter/providers.yaml
# 2. uvx で起動 (インストール + 起動が 1 行)
# PyPI 配布名 (coderouter-cli) と console script 名 (coderouter) が異なるため、
# uv 0.11+ では --from 形式が必須 (旧 uv でも動く canonical 形式)
uvx --from coderouter-cli coderouter serve --port 8088
恒久的にインストールしておきたい場合:
uv tool install coderouter-cli
coderouter serve --port 8088
git clone して開発にも参加したい場合 (中級者向け):
git clone https://github.com/zephel01/CodeRouter.git
cd CodeRouter
uv sync
uv run coderouter serve --port 8088
注: PyPI 上のパッケージ名は
coderouter-cliですが、コマンド名と Python import 名はcoderouterのままです。詳しくは CHANGELOG[v1.7.0]参照。
--apply自動化を使う場合 (v1.8.0+):ruamel.yamlを optional dep として一緒に入れます (pip install 'coderouter-cli[doctor]'またはuv pip install ruamel.yaml)。基本機能には不要です。
あとは任意の OpenAI クライアントを http://127.0.0.1:8088 に向けるだけです:
curl http://127.0.0.1:8088/v1/chat/completions \
-H 'Content-Type: application/json' \
-d '{
"model": "ignored",
"messages": [{"role": "user", "content": "Hello"}]
}'
model フィールドは現状プレースホルダです — ルーティングは profile フィールド(providers.yaml の default がデフォルト)で決まります。
はじめての方は 利用ガイド を参照してください。ハードウェア別のモデル選定、チューニング既定値、OS ごとの起動フロー、OpenRouter 無料枠とのペア方針を一通り解説しています。(English: usage guide)
NVIDIA NIM 無料枠(40 req/min)と OpenRouter 無料枠をどう重ねるかは 無料枠ガイド にまとめてあります。live 検証済みのモデル一覧、claude-code-nim プロファイルの設計意図、よくあるハマり所 5 点 込み。(English: free-tier guide)
API キーの管理が気になる方 (1Password / direnv + sops / OS Keychain 連携 + .env の安全運用) は v1.6.3 で coderouter serve --env-file と coderouter doctor --check-env を入れています。詳細は トラブルシューティング §5。
OS 対応
CodeRouter 自体は純 Python 3.12+ で、実質的な OS 対応範囲は min(coderouter, ollama, claude-code) です。
| OS | サーバー | ローカル推論 | メモ |
|---|---|---|---|
| macOS — Apple Silicon (M1–M5) | ✅ | ✅ Metal ネイティブ | 主要開発ターゲット |
| macOS — Intel | ✅ | ⚠️ CPU のみ | 実用はクラウドフォールバックのみ |
| Linux — x86_64 (Ubuntu / Debian / Fedora) | ✅ | ✅ CUDA または CPU | フル対応 |
| Linux — ARM64 (Pi 5 / Graviton) | ✅ | ⚠️ Pi では CPU | クラウド中継プロキシとして使える |
| Windows — WSL2 (Ubuntu) | ✅ | ✅ | Windows ではこの経路を推奨 |
| Windows — native | ⚠️ 一部 | ✅ CUDA | scripts/verify_*.sh は bash 必須 (Git Bash/WSL2) |
注意点や「ローカル GPU なし」向けレシピを含むフル版マトリクス: 利用ガイド §1
ステータス — v1.0 安定版 (2026-04)
テスト 710 本通過。ランタイム依存 5 個。macOS / Linux / Windows WSL2 で動作。 ルーターは日常的な Claude Code 用途で安定しています。v1.0 の総まとめは docs/retrospectives/v1.0.md。
今日の CodeRouter が届ける価値:
- どのクライアントもどのプロバイダに橋渡し。 OpenAI 互換クライアントからのリクエストと Claude Code(
/v1/messages経由)両方を受け入れ、ストリーミング/非ストリーミングを問わず、ローカル Ollama / OpenRouter 無料 / Anthropic / それらの混在にルーティングします。 - 部分レスポンスを垂れ流さず安全にフォールバック。 最初のバイト前にプロバイダが失敗したら次を試す。最初のバイト以降に失敗したら、クライアントには綺麗な
event: errorが 1 本届くだけ — 2 つのプロバイダを継ぎ接ぎしたフランケン応答は起きません。 - 明示的にオプトインしたときだけ課金。
ALLOW_PAID=false(既定)がチェーンから有料プロバイダを外し、ブロック時は 1 行の明確なログを出します。 - 小さいローカルモデルが壊すものを修復。 Qwen / DeepSeek 系がテキストとして吐いた
{"name":..., "arguments":...}は、Claude Code に届く前に有効なtool_useブロックへ復元されます。 - 何がおかしいかを教えてくれる。
coderouter doctor --check-model <provider>が 6 プローブ(認証 / コンテキスト切り詰め / ストリーム中断 / ツール呼び出し能力 / reasoning フィールド漏れ / Anthropicthinking対応)を回し、宣言と実挙動が食い違えばコピペ可能な YAML パッチを出します。 - reasoning 漏れをスクラブ。 プロバイダに
output_filters: [strip_thinking, strip_stop_markers]を付ければ<think>…</think>と 6 種の stop マーカー variants が SSE チャンク境界を跨いでも安定して剥がれます。 - Anthropic ネイティブ機能は Anthropic に届いたら保持。
cache_control/thinking/anthropic-betaヘッダでゲートされる body フィールドはkind: anthropicプロバイダでそのまま通り、OpenAI 形状へ落ちる場合のロッシー変換は(沈黙ではなく)ログで可視化されます。
リリース単位の詳細が欲しい? v0.x と v1.0-A/B/C の各スライス — 何が入り、何本のテストが増え、なぜ必要だったのか — は CHANGELOG.md に揃っています。設計の不変項と今後のロードマップは plan.md。
次の予定(v1.0 は plan.md §10、v1.0+ は §18): v1.5 ✅ メトリクス / /dashboard / coderouter stats TUI / scripts/demo_traffic.sh、v1.6 ✅ auto_router (task-aware routing) + NVIDIA NIM 無料枠 + トラブルシュートドキュメント分離 + --env-file / doctor --check-env、v1.7 ✅ PyPI 公開 (uvx --from coderouter-cli coderouter)、v1.8 ✅ 用途別 4 プロファイル (multi/coding/general/reasoning) + Gemma 4 / Qwen3.6 / Z.AI (GLM) 登録 + setup.sh onboarding ウィザード + coderouter doctor --check-model --apply (非破壊 YAML 書き戻し) + claude_code_suitability startup チェック + Trusted Publishing 自動化。残り (v1.9 候補) は coderouter doctor --network (CI 用) / launcher スクリプト / 起動時アップデートチェック (opt-in)。
Claude Code と一緒に使う
# ターミナル 1: Claude Code 向けにチューニングしたプロファイルで CodeRouter を起動
uv run coderouter serve --port 8088
# ターミナル 2: Claude Code を CodeRouter に向け、ヘッダでチューニング済みプロファイルを選ぶ
ANTHROPIC_BASE_URL=http://localhost:8088 \
ANTHROPIC_AUTH_TOKEN=dummy \
claude
examples/providers.yaml の claude-code プロファイル(7b を先頭、14b を品質フォールバック、14b のタイムアウトを 300s に拡大)を使うには、設定で既定にします:
# ~/.coderouter/providers.yaml
default_profile: claude-code
もしくは起動時に --mode フラグで選択 (v0.6-A):
uv run coderouter serve --port 8088 --mode claude-code
# 同等: CODEROUTER_MODE=claude-code uv run coderouter serve --port 8088
--mode はこのプロセス限定で YAML の default_profile を上書きします。リクエスト単位の上書き (X-CodeRouter-Profile ヘッダ、または body の profile フィールド) は依然勝つので、--mode は「設定ファイルを編集せずに別のチェーンを試したい」ときのつまみです。未知のプロファイル名は初回リクエストではなく起動時 fast-fail です。
examples/providers.yaml 側のプロファイルはこのような形です — そのままコピーし、各 providers: エントリの base_url / model をあなたのローカルスタックに合わせて書き換えてください:
# ANTHROPIC_BASE_URL=http://localhost:8088 claude 用にチューニング。
# Claude Code は毎ターン全ツール (Bash/Glob/Read/Write/...) を宣言するので、
# ルーターは常に v0.3-D の tool-downgrade 経路を使う。ユーザー体感レイテンシ
# ≒ 上流のトータル応答時間。先頭に最速の tool 対応モデル、2 番手に 14b を品質
# フォールバックに、レート制限脱出に無料クラウド 2 種、最後の砦に Claude。
profiles:
- name: claude-code
providers:
- ollama-qwen-coder-7b # M 系で ~30–60s/ターン、tool 対応
- ollama-qwen-coder-14b # 品質フォールバック (timeout_s: 300)
- openrouter-free # qwen/qwen3-coder:free (262K コンテキスト)
- openrouter-gpt-oss-free # openai/gpt-oss-120b:free (別ベンダー = レート制限脱出)
- openrouter-claude # 有料、ALLOW_PAID=true が必要
有料ティアを Anthropic のネイティブ API にしたい場合(Anthropic ingress 経由での cache_control / thinking ブロック生存が目的なら)、openrouter-claude を anthropic-direct に差し替えます — examples/providers.yaml の claude-code-direct プロファイルがまさにそれです。
プロファイル単位のパラメータ上書き (v0.6-B)
プロファイルはチェーン中の全試行に対し 2 つのパラメータを上書き可能で、同じプロバイダ一覧を別プロファイルで違った挙動にしたいとき(例: 長文 /no_think モード vs 短文チャットモード)に便利です:
profiles:
- name: claude-code-long
timeout_s: 600 # このプロファイルでは ProviderConfig.timeout_s を置換
append_system_prompt: "" # 空文字 = プロバイダ指示を明示的にクリア
providers:
- ollama-qwen-coder-14b
- openrouter-free
セマンティクス: プロファイル値は設定されていればプロバイダ値を置き換えます(append ではない)。timeout_s のようなスカラでの素直な挙動と一致。append_system_prompt: "" はこのプロファイル限定でプロバイダ指示を明示消去します(「未設定」= プロバイダ既定にフォールバック、と区別)。未設定フィールドはプロバイダ既定をそのまま残します。retry_max はアダプタレイヤのリトライが未実装のため後続マイナーに持ち越し — 現状はフォールバックチェーン自体がリトライ機構です。
Mode エイリアス — X-CodeRouter-Mode (v0.6-D)
具体プロファイル名ではなく意図を表現したいクライアントは X-CodeRouter-Mode ヘッダを送れます。CodeRouter は YAML mode_aliases: ブロックで解決します:
# providers.yaml
mode_aliases:
coding: claude-code # クライアントが Mode: coding → プロファイル claude-code
long: claude-code-long
fast: ollama-only
curl http://localhost:8088/v1/chat/completions \
-H 'Content-Type: application/json' \
-H 'X-CodeRouter-Mode: coding' \
-d '{ "messages": [{"role":"user","content":"hi"}] }'
優先度(先着勝ち): body profile > X-CodeRouter-Profile ヘッダ > X-CodeRouter-Mode ヘッダ > default_profile。Mode が Profile より下なのは Profile は実装、Mode は意図 であるため — 呼び出し側が具体プロファイルを指定したときはそのまま尊重します。CodeRouter の前段プロキシが Mode を自動付与する構成でも、呼び出し側の明示 body/ヘッダ profile が勝つ、これが大事な理由です。
ガードレール: 壊れたエイリアス対象は起動時 fast-fail(default_profile バリデーションと同じ哲学)、未知 Mode は宣言済エイリアス一覧付き 400、解決ごとに mode-alias-resolved INFO を出すので運用者はマッピングを後で grep できます。
モデルケイパビリティレジストリ — model-capabilities.yaml (v0.7-A)
「どの Anthropic ファミリが thinking: {type: enabled} を受け付けるか」の知識は、以前は coderouter/routing/capability.py 内の正規表現リテラルでした。v0.7-A からは coderouter/data/model-capabilities.yaml(パッケージ同梱)に移行し、任意で ~/.coderouter/model-capabilities.yaml によるユーザー上書きが可能です。Anthropic が新ファミリを出したら YAML 1 行で追加 — コード変更もリリースサイクルも不要。
# ~/.coderouter/model-capabilities.yaml — 任意のユーザー上書き
version: 1
rules:
# 仮に Anthropic が新ファミリを出し、CodeRouter の同梱既定更新前に使いたい場合。
- match: "claude-sonnet-5-*"
kind: anthropic
capabilities:
thinking: true
# このタグのローカル Ollama では確実にツール呼び出しできるので宣言。
# v0.7-B doctor の判定と合わせ、将来の glob 消費者からも
# 方針のある既定として参照されるようにする。
- match: "qwen3-coder:*"
kind: openai_compat
capabilities:
tools: true
スキーマ: 各ルールは match (provider.model に対する fnmatch glob、大小区別)、任意の kind フィルタ ("anthropic" / "openai_compat" / "any"、既定 "any")、capabilities: マップ(thinking / reasoning_passthrough / tools / max_context_tokens を宣言可能)。ルールは上から順に評価され、各フラグごとに最初に宣言したルールが勝ちます。ルールは 1 つのケイパビリティだけ上書きし、他はフォールスルーさせる使い方も可能。
レイヤ間の優先度は providers.yaml capabilities.*(プロバイダ単位の明示 opt-in)> ユーザー model-capabilities.yaml > 同梱 model-capabilities.yaml > 未設定(False 扱い)。ユーザーは常に上書き権限を失いません — providers.yaml のプロバイダで明示的に capabilities.thinking: true を付ければレジストリに勝つ点は v0.5-A から変わりません。
タイポはロード時に検出: 未知のトップレベルフィールド、未知のフラグ名、不正な kind はいずれも ValidationError を上げてサーバーがトラフィックを受け付ける前に停止します。default_profile / mode_aliases バリデーションと同じ fast-fail 姿勢です。
Doctor — coderouter doctor --check-model <provider> (v0.7-B)
「Ollama を立ててルーターを向けたけど、どうも何かがおかしい」は最多の onboarding 失敗です。v0.7-B の doctor サブコマンドはこれを一行診断に変えます:
coderouter doctor --check-model ollama-qwen-coder-14b
フォールバックチェーン全体ではなく、指定したプロバイダ単体に対し小さな 4 プローブ(各 ≤100 トークン)を走らせ、観測挙動が providers.yaml + model-capabilities.yaml の現宣言と食い違えば判定表とコピペ可能な YAML パッチを出力します:
provider: ollama-qwen-coder-14b (kind=openai_compat, model=qwen2.5-coder:14b)
probe verdict detail
auth+basic-chat OK 200 in 1.4s, 18 tokens in / 6 tokens out
tool_calls NEEDS_TUNING model emitted a tool_use block but registry says tools=false
thinking N/A kind=openai_compat; thinking probe is anthropic-only
reasoning-leak OK no stray `reasoning` field on choice.message
suggested patch for ~/.coderouter/providers.yaml:
providers:
- name: ollama-qwen-coder-14b
capabilities:
tools: true # observed: model returned a well-formed tool_use block
4 プローブとその存在意義:
- auth+basic-chat — 些細な 1 ターン。「API キー未設定」「
base_url違い」「プロバイダ到達不能」のクラスを先に捕まえる。失敗した場合、残り 3 プローブはSKIPとなり症状追いで時間(とトークン)を浪費しない。 - tool_calls — ダミー
echo(text: string)ツール仕様と、それを発火させるはずのプロンプトを送る。意図的に非破壊(上流への副作用なし)。モデルが有効なtool_useを吐いたがレジストリがtools: falseと言っている(あるいは逆)ときNEEDS_TUNING。 - thinking — Anthropic 限定。
thinking: {type: enabled, budget_tokens: 16}をネイティブ送出(OpenAI 形状アダプタをバイパス)し、上流がフィールドを受け付けるか確認。ファミリがmodel-capabilities.yamlに未登録ならレジストリパッチ(providers.yamlパッチではない)を出す。 - reasoning-leak — chat ターンを発行し、v0.5-C strip が走る前の上流生ボディを検査。「モデルが
reasoningを返した」と「アダプタが既に除去済」を区別できる。OpenRouter 無料モデル(openai/gpt-oss-120b:freeなど)で意味がある。
終了コード(CI 投入想定で設計):
| コード | 意味 |
|---|---|
0 |
全プローブが宣言ケイパビリティと一致、パッチ不要 |
2 |
1 つ以上の NEEDS_TUNING、YAML パッチは出力内 |
1 |
プローブ実行不能 — auth 失敗、プロバイダ到達不能、または未知プロバイダ名。前提条件を直して再実行 |
複数シグナル同時発火時の優先度は 1(ブロッカ)> 2(チューニング)> 0(クリーン)。Unix lint 規約(2 = 自動修復可、1 = 諦め)と揃えています。1 プローブの失敗で他が抑制されることはなく、auth 短絡時でもスキップされたプローブは SKIP: upstream auth failed と明記して透明性を維持します。
このサブコマンドはプロバイダ 1 つを対象とする設計です: doctor のプローブが、同ファミリを共有する他プロバイダに波及するレジストリ glob 変更を提案すべきではないからです。チェーン内の各プロバイダについて --check-model を変えて再実行してください。
体感の目安
- 初バイトレイテンシ: Claude Code は毎ターン全ツール (Bash/Glob/Read/Write/…) を宣言するので、CodeRouter は常に v0.3-D の tool-downgrade 経路(内部非ストリーミング + SSE リプレイ)を使います。体感レイテンシ ≒ 上流のトータル応答時間。
- M 系 macOS では qwen2.5-coder:7b が ~30–60s/ターン、14b が ~2 分。主因は Claude Code が毎ターン送る 15–20K トークンのシステムプロンプト prefill で、CodeRouter のオーバーヘッドではありません。
- ツール選択の品質はモデル側の限界で、ワイア層の問題ではありません。CodeRouter はワイア(テキスト JSON →
tool_useブロック)を修復しますが、モデルが正しいツールを選んだかは別問題。qwen2.5-coder:14b はBashが正解の場面でGlobを選ぶことがあり — 対策はより強いローカルモデル、あるいはALLOW_PAID=trueで Claude にフォールスルーさせることです。 - ミッドストリーム失敗(Ollama が最初のチャンク後に落ちる等)は単発の
event: errorとしてクライアントに届き、リトライはありません — 部分レスポンスは保持され、ストリームはクリーンに閉じます。
予定(v1.0 は plan.md §10、v1.0+ は §18):
- v1.0 ✅ — 14 ケースのリグレッションスイート、Code Mode (スリム版 Claude Code ハーネス); 出力クリーニングは v1.0-A で
output_filtersチェーンとして完了 - v1.5 ✅ — メトリクスダッシュボード(出荷済み) —
MetricsCollector+GET /metrics.json+GET /metrics(Prometheus) +GET /dashboard(HTML 1 ページ) +coderouter statscurses TUI +scripts/demo_traffic.shトラフィックジェネレータ +display_timezone設定 - v1.6 ✅ —
auto_router(task-aware routing、default_profile: autoで画像/コード濃度/その他を自動振り分け) + NVIDIA NIM 無料枠 8 段チェーン + ドキュメント言語スワップ (JA primary) + トラブルシュート独立ドキュメント +--env-file/doctor --check-env - v1.7 ✅ — PyPI 公開 (
uvx --from coderouter-cli coderouterで 1 行起動) + Trusted Publishing 経路 (release.yml で自動 publish) - v1.8 ✅ — 用途別 4 プロファイル + GLM/Gemma 4/Qwen3.6 公式化 + apply 自動化:
multi(default) /coding/general/reasoningの 4 プロファイル + 全プロファイルにappend_system_promptで Claude 風応答 nudge +mode_aliases(default/fast/vision/think/cheap)、Ollama 公式 tag 化されたgemma4:e4b/26b/31b/qwen3.6:27b/35bを active stanza に格上げ、Z.AI を OpenAI-compat で 2 base_url 提供 (Coding Plan / General API)、coderouter doctor --check-model --applyで YAML パッチを非破壊書き戻し (ruamel.yamlround-trip でコメント・key 順序保持、冪等)、setup.shonboarding ウィザード、claude_code_suitabilitystartup チェック (Llama-3.3-70B 系をclaude-code-*profile で WARN)。残り (v1.9 以降):coderouter doctor --network(CI 用)、launcher スクリプト (.command/.sh/.bat)、opt-in 起動時アップデートチェック
kind: openai_compat と kind: anthropic の選び方
providers.yaml の各プロバイダに kind があります。2 択です。どちらを選ぶかでホップを超えて生存するワイアレベル機能と、到達可能なクライアントが変わります。
| 観点 | kind: openai_compat |
kind: anthropic |
|---|---|---|
/v1/chat/completions から到達 |
✅ 変換不要 | ✅ v0.4-A 逆変換経由 |
/v1/messages から到達 |
✅ 変換 + tool-call 修復経由 | ✅ ネイティブパススルー |
| 対象 | llama.cpp, Ollama, OpenRouter, LM Studio, Together, Groq, ... | api.anthropic.com、Bedrock の Anthropic シム、Messages ワイアを話す任意サーバー |
cache_control ブロック |
❌ ロスト(OpenAI 側に等価物なし) | ✅ /v1/messages 経由で end-to-end 保持 |
thinking ブロック |
❌ ロスト | ✅ /v1/messages 経由で保持 |
構造化 tool_use SSE イベント |
修復から合成 (v0.3-D downgrade) | 上流からパススルー |
tool-call 修復 (素テキスト JSON → tool_use) |
✅ 壊れた JSON を吐くローカルモデル向けに必要 | n/a (Anthropic は壊れた JSON を出さない) |
anthropic-beta ヘッダ転送 (v0.4-D) |
n/a | ✅ そのまま |
判断の目安:
- ローカルモデルまたは OpenRouter 無料枠 →
kind: openai_compat。逆経路は存在しますが、OpenAI ワイアをネイティブに話すプロバイダに対し変換コストを払う理由はありません。 - 公式 API 経由の Claude で、
cache_control/thinkingを効かせたい →kind: anthropic、/v1/messages経由(= Claude Code からANTHROPIC_BASE_URL=http://localhost:8088)。examples/providers.yamlのclaude-code-directプロファイルがこのケース用に事前配線されています。 - OpenAI クライアントから Claude に到達(
openaiSDK / curl →/v1/chat/completions)→kind: anthropicは引き続き動きます — 基本 chat / tools / vision は v0.4-A 逆経路で生き残ります。ただし OpenAI に等価形状が無いためcache_control/thinkingは送れません。 - 混在チェーン(ローカル先頭、Claude を有料最終砦に)→ 同プロファイルに両
kindを並べます。エンジンの多態ディスパッチが各境界のホップを扱います。
トラブルシューティング
詳細は独立ドキュメント
docs/troubleshooting.md(v1.6.2 で分離) を参照してください。 本節は 30 秒で済む早見表。
まず第一に: 失敗中のプロバイダに対して coderouter doctor --check-model <provider> を走らせてください。6 probe を回し、宣言と観測の不一致があればコピペ YAML パッチを出します。
症状別の入口 (詳細はリンク先):
- 起動して上流に 401:
Header of type authorization was missing→ §1 起動・設定の罠 (.envのexport必須、coderouter serve --mode <profile>の正しい使い方) - ログに
provider-failed/capability-degraded/chain-uniform-auth-failure→ §2 ログの読み方 - Ollama に向けたら無音 /
<think>タグ漏れ / 「ファイルが読めません」 → §3 Ollama 5 症状 - Claude Code 上で挨拶がツール呼び出しに化ける /
UserPromptSubmit hook error→ §4 Claude Code 連携の罠
ダッシュボード http://localhost:8088/dashboard を別タブで開いておくと、ほとんどの罠が目で見て 10 秒で特定できます。
ミッドストリーム失敗は SSE ストリーム内で単発の event: error / type: api_error として出ます (ヘッダは既送出なので 5xx HTTP ステータスは返らない)。これは「どのプロバイダも開始できなかった」 (type: overloaded_error) とは区別されます。
Ollama 初心者 — サイレント失敗 5 症状
詳細は docs/troubleshooting.md §3 に移動しました。
- 症状 1: 200 が返るのに返信が空/意味不明 →
num_ctx既定 2048 に切り詰められた - 症状 2: 「ファイルが読めません」を繰り返す → 小さなモデルが tools 仕様を扱えていない (
tools: false宣言) - 症状 3:
<think>...</think>が漏れる →output_filters: [strip_thinking] - 症状 4: 初回リクエストが毎回失敗 →
ollama pull <tag>忘れ /model:タイポ - 症状 5: 全プロバイダが一様に失敗 → クラウド API キー未 export (§1-2 / §1-3)
各症状の coderouter doctor 出力例とコピペ可能 YAML パッチは docs/troubleshooting.md に。HF-on-Ollama 構成 / lunacode との関係も同じドキュメントに集約。
依存ポリシー
厳密 — plan.md §5.4 参照。ランタイム依存:
| パッケージ | 目的 |
|---|---|
fastapi |
HTTP ingress |
uvicorn |
ASGI サーバー |
httpx |
アウトバウンド HTTP(あえて Anthropic/OpenAI SDK を使わない) |
pydantic |
スキーマ検証 |
pyyaml |
設定パース |
以上。litellm なし、langchain なし、openai/anthropic SDK なし。
プログラムから例外をキャッチする (v1.0.1)
CodeRouter を組み込んで使う場合 (engine を直接呼ぶ / coderouter serve を harness でラップする等)、CodeRouter が内部で raise する全例外は CodeRouterError を継承しています。1 つの except で全部拾えます:
from coderouter import CodeRouterError
try:
response = await engine.generate(chat_request)
except CodeRouterError as exc:
# AdapterError / NoProvidersAvailableError / MidStreamError の全てに該当
logger.error("coderouter-failed", extra={"reason": str(exc)})
leaf 例外は従来の場所 (AdapterError は coderouter.adapters.base、NoProvidersAvailableError と MidStreamError は coderouter.routing.fallback) に残っているので、既存の except AdapterError: のような catch はそのまま動きます。root class は downstream が leaf を個別 import して enumerate しなくて済むよう public API surface を固定するためだけに存在し、今後 leaf が増えても呼び出し側のコードを触る必要がありません。
Security
シークレットは設定ファイルではなく環境変数に置きます。CI はシークレット
スキャン (gitleaks)、多重ソースの依存 CVE 監査 (pip-audit +
OSV-Scanner)、lockfile 固定インストールを強制します —
docs/security.md に完全な方針と
報告手順があります。
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file coderouter_cli-1.9.0.tar.gz.
File metadata
- Download URL: coderouter_cli-1.9.0.tar.gz
- Upload date:
- Size: 829.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f0c589a587ec9a5c30fa81780356147f6a22e08d7cb81af8843c2904451efb51
|
|
| MD5 |
87ac52b11444cb21ba5d7a285516c145
|
|
| BLAKE2b-256 |
35de5b0381171bb2cdef076d4a64962362e3df068fed40014eae9ff4da911e81
|
Provenance
The following attestation bundles were made for coderouter_cli-1.9.0.tar.gz:
Publisher:
release.yml on zephel01/CodeRouter
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
coderouter_cli-1.9.0.tar.gz -
Subject digest:
f0c589a587ec9a5c30fa81780356147f6a22e08d7cb81af8843c2904451efb51 - Sigstore transparency entry: 1399486219
- Sigstore integration time:
-
Permalink:
zephel01/CodeRouter@740be49e97ade9af2d8d52720662ba4f58c8371e -
Branch / Tag:
refs/tags/v1.9.0 - Owner: https://github.com/zephel01
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@740be49e97ade9af2d8d52720662ba4f58c8371e -
Trigger Event:
push
-
Statement type:
File details
Details for the file coderouter_cli-1.9.0-py3-none-any.whl.
File metadata
- Download URL: coderouter_cli-1.9.0-py3-none-any.whl
- Upload date:
- Size: 216.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
41baab99a043e3be8e62eea50b6460f00c02e539252ebfd315a27c9a83528252
|
|
| MD5 |
aad45d0cd908895f3d3d992c78d48103
|
|
| BLAKE2b-256 |
aed59d626d82018e5cfc85291d01df28c8c7a7118c34c2c52ff4b29c35720bc0
|
Provenance
The following attestation bundles were made for coderouter_cli-1.9.0-py3-none-any.whl:
Publisher:
release.yml on zephel01/CodeRouter
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
coderouter_cli-1.9.0-py3-none-any.whl -
Subject digest:
41baab99a043e3be8e62eea50b6460f00c02e539252ebfd315a27c9a83528252 - Sigstore transparency entry: 1399486245
- Sigstore integration time:
-
Permalink:
zephel01/CodeRouter@740be49e97ade9af2d8d52720662ba4f58c8371e -
Branch / Tag:
refs/tags/v1.9.0 - Owner: https://github.com/zephel01
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@740be49e97ade9af2d8d52720662ba4f58c8371e -
Trigger Event:
push
-
Statement type: