coderouter-cli 2.6.0__tar.gz → 2.6.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (215) hide show
  1. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/.gitignore +1 -0
  2. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/CHANGELOG.md +45 -0
  3. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/PKG-INFO +32 -1
  4. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/README.en.md +31 -0
  5. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/README.md +31 -0
  6. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/ingress/dashboard_routes.py +23 -0
  7. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/metrics/collector.py +60 -0
  8. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/docs/README.md +38 -1
  9. coderouter_cli-2.6.1/docs/backends/claude-code-llamacpp-vllm.md +172 -0
  10. coderouter_cli-2.6.1/docs/guides/language-tax.en.md +138 -0
  11. coderouter_cli-2.6.1/docs/guides/language-tax.md +139 -0
  12. coderouter_cli-2.6.1/examples/README.md +68 -0
  13. coderouter_cli-2.6.1/examples/providers-multiagent.yaml +188 -0
  14. coderouter_cli-2.6.0/examples/providers.v2-context-budget.yaml → coderouter_cli-2.6.1/examples/providers.context-budget-test.yaml +2 -1
  15. coderouter_cli-2.6.0/examples/providers.llama-cpp-vllm.yaml → coderouter_cli-2.6.1/examples/providers.llamacpp-vllm.yaml +19 -9
  16. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/examples/providers.nvidia-nim.yaml +1 -0
  17. coderouter_cli-2.6.0/examples/providers.auto-custom.yaml → coderouter_cli-2.6.1/examples/providers.ollama-auto-custom.yaml +6 -5
  18. coderouter_cli-2.6.0/examples/providers.auto.yaml → coderouter_cli-2.6.1/examples/providers.ollama-auto.yaml +2 -1
  19. coderouter_cli-2.6.0/examples/providers.note-2026.yaml → coderouter_cli-2.6.1/examples/providers.ollama-free-chain.yaml +3 -2
  20. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/examples/providers.raspberrypi.yaml +1 -0
  21. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/examples/providers.yaml +1 -0
  22. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/pyproject.toml +1 -1
  23. coderouter_cli-2.6.1/tests/test_tokens_saved_metric.py +87 -0
  24. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/LICENSE +0 -0
  25. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/__init__.py +0 -0
  26. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/__main__.py +0 -0
  27. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/adapters/__init__.py +0 -0
  28. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/adapters/anthropic_native.py +0 -0
  29. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/adapters/base.py +0 -0
  30. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/adapters/openai_compat.py +0 -0
  31. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/adapters/registry.py +0 -0
  32. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/cli.py +0 -0
  33. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/cli_stats.py +0 -0
  34. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/config/__init__.py +0 -0
  35. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/config/capability_registry.py +0 -0
  36. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/config/env_file.py +0 -0
  37. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/config/loader.py +0 -0
  38. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/config/schemas.py +0 -0
  39. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/cost.py +0 -0
  40. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/data/__init__.py +0 -0
  41. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/data/model-capabilities.yaml +0 -0
  42. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/doctor.py +0 -0
  43. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/doctor_apply.py +0 -0
  44. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/env_security.py +0 -0
  45. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/errors.py +0 -0
  46. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/gguf_introspect.py +0 -0
  47. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/guards/__init__.py +0 -0
  48. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/guards/_fingerprint.py +0 -0
  49. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/guards/backend_health.py +0 -0
  50. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/guards/context_budget.py +0 -0
  51. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/guards/continuous_probe.py +0 -0
  52. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/guards/drift_actions.py +0 -0
  53. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/guards/drift_detection.py +0 -0
  54. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/guards/memory_budget.py +0 -0
  55. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/guards/memory_pressure.py +0 -0
  56. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/guards/self_healing.py +0 -0
  57. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/guards/tool_loop.py +0 -0
  58. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/hardware.py +0 -0
  59. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/ingress/__init__.py +0 -0
  60. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/ingress/anthropic_routes.py +0 -0
  61. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/ingress/app.py +0 -0
  62. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/ingress/launcher_routes.py +0 -0
  63. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/ingress/metrics_routes.py +0 -0
  64. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/ingress/openai_routes.py +0 -0
  65. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/language_tax.py +0 -0
  66. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/logging.py +0 -0
  67. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/metrics/__init__.py +0 -0
  68. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/metrics/prometheus.py +0 -0
  69. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/output_filters.py +0 -0
  70. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/plugins/__init__.py +0 -0
  71. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/plugins/base.py +0 -0
  72. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/plugins/loader.py +0 -0
  73. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/plugins/registry.py +0 -0
  74. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/routing/__init__.py +0 -0
  75. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/routing/adaptive.py +0 -0
  76. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/routing/auto_router.py +0 -0
  77. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/routing/budget.py +0 -0
  78. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/routing/capability.py +0 -0
  79. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/routing/fallback.py +0 -0
  80. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/state/__init__.py +0 -0
  81. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/state/audit_log.py +0 -0
  82. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/state/replay.py +0 -0
  83. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/state/request_log.py +0 -0
  84. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/state/store.py +0 -0
  85. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/state/suggest_rules.py +0 -0
  86. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/token_estimation.py +0 -0
  87. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/token_estimation_accurate.py +0 -0
  88. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/translation/__init__.py +0 -0
  89. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/translation/anthropic.py +0 -0
  90. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/translation/convert.py +0 -0
  91. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/coderouter/translation/tool_repair.py +0 -0
  92. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/docs/assets/dashboard-demo.png +0 -0
  93. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/docs/backends/gguf_dl.md +0 -0
  94. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/docs/backends/hf-ollama-models.md +0 -0
  95. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/docs/backends/install-backends.en.md +0 -0
  96. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/docs/backends/install-backends.md +0 -0
  97. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/docs/backends/launcher-quickstart.md +0 -0
  98. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/docs/backends/launcher.md +0 -0
  99. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/docs/backends/llamacpp-direct.en.md +0 -0
  100. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/docs/backends/llamacpp-direct.md +0 -0
  101. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/docs/backends/lmstudio-direct.en.md +0 -0
  102. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/docs/backends/lmstudio-direct.md +0 -0
  103. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/docs/backends/verify-ollama-0.23.1.md +0 -0
  104. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/docs/concepts/architecture.md +0 -0
  105. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/docs/concepts/context-budget.md +0 -0
  106. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/docs/concepts/continuous-probing.md +0 -0
  107. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/docs/concepts/drift-detection.md +0 -0
  108. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/docs/concepts/partial-stitch.md +0 -0
  109. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/docs/designs/v1.5-dashboard-mockup.html +0 -0
  110. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/docs/designs/v1.6-auto-router-verification.md +0 -0
  111. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/docs/designs/v1.6-auto-router.md +0 -0
  112. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/docs/guides/free-tier-guide.en.md +0 -0
  113. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/docs/guides/free-tier-guide.md +0 -0
  114. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/docs/guides/security.en.md +0 -0
  115. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/docs/guides/security.md +0 -0
  116. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/docs/guides/troubleshooting.en.md +0 -0
  117. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/docs/guides/troubleshooting.md +0 -0
  118. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/docs/guides/usage-guide.en.md +0 -0
  119. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/docs/guides/usage-guide.md +0 -0
  120. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/docs/low-memory-integration.md +0 -0
  121. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/docs/openrouter-roster/CHANGES.md +0 -0
  122. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/docs/openrouter-roster/README.md +0 -0
  123. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/docs/openrouter-roster/latest.json +0 -0
  124. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/docs/retrospectives/v0.4.md +0 -0
  125. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/docs/retrospectives/v0.5-verify.md +0 -0
  126. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/docs/retrospectives/v0.5.md +0 -0
  127. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/docs/retrospectives/v0.6.md +0 -0
  128. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/docs/retrospectives/v0.7.md +0 -0
  129. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/docs/retrospectives/v1.0-verify.md +0 -0
  130. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/docs/retrospectives/v1.0.md +0 -0
  131. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/docs/start/quickstart.en.md +0 -0
  132. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/docs/start/quickstart.md +0 -0
  133. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/docs/start/when-do-i-need-coderouter.en.md +0 -0
  134. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/docs/start/when-do-i-need-coderouter.md +0 -0
  135. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/examples/.env.example +0 -0
  136. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/scripts/demo_traffic.sh +0 -0
  137. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/scripts/openrouter_roster_diff.py +0 -0
  138. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/scripts/smoke_v2_2.sh +0 -0
  139. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/scripts/verify-providers.yaml +0 -0
  140. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/scripts/verify_ollama_0_23.py +0 -0
  141. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/scripts/verify_v0_5.sh +0 -0
  142. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/scripts/verify_v1_0.sh +0 -0
  143. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/__init__.py +0 -0
  144. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/conftest.py +0 -0
  145. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_adapter_anthropic.py +0 -0
  146. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_audit_log.py +0 -0
  147. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_auto_router.py +0 -0
  148. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_auto_router_cjk.py +0 -0
  149. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_backend_health.py +0 -0
  150. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_budget.py +0 -0
  151. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_capability.py +0 -0
  152. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_capability_degraded_payload.py +0 -0
  153. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_capability_registry.py +0 -0
  154. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_capability_registry_cache_control.py +0 -0
  155. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_claude_code_suitability.py +0 -0
  156. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_cli.py +0 -0
  157. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_cli_stats.py +0 -0
  158. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_config.py +0 -0
  159. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_context_budget.py +0 -0
  160. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_continuous_probe.py +0 -0
  161. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_dashboard_endpoint.py +0 -0
  162. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_doctor.py +0 -0
  163. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_doctor_apply.py +0 -0
  164. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_doctor_cache_probe.py +0 -0
  165. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_drift_actions.py +0 -0
  166. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_drift_detection.py +0 -0
  167. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_drift_detection_integration.py +0 -0
  168. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_env_file.py +0 -0
  169. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_env_security.py +0 -0
  170. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_errors.py +0 -0
  171. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_examples_yaml.py +0 -0
  172. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_fallback.py +0 -0
  173. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_fallback_anthropic.py +0 -0
  174. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_fallback_cache_control.py +0 -0
  175. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_fallback_cache_observed.py +0 -0
  176. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_fallback_misconfig_warn.py +0 -0
  177. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_fallback_paid_gate.py +0 -0
  178. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_fallback_thinking.py +0 -0
  179. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_gguf_introspect.py +0 -0
  180. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_guards_tool_loop.py +0 -0
  181. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_hardware.py +0 -0
  182. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_ingress_anthropic.py +0 -0
  183. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_ingress_profile.py +0 -0
  184. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_language_tax.py +0 -0
  185. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_language_tax_integration.py +0 -0
  186. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_memory_budget.py +0 -0
  187. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_memory_pressure.py +0 -0
  188. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_metrics_cache.py +0 -0
  189. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_metrics_collector.py +0 -0
  190. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_metrics_cost.py +0 -0
  191. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_metrics_endpoint.py +0 -0
  192. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_metrics_jsonl.py +0 -0
  193. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_metrics_prometheus.py +0 -0
  194. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_metrics_prometheus_cache.py +0 -0
  195. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_openai_compat.py +0 -0
  196. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_openrouter_roster_diff.py +0 -0
  197. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_output_filters.py +0 -0
  198. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_output_filters_adapters.py +0 -0
  199. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_partial_stitch.py +0 -0
  200. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_plugins_integration.py +0 -0
  201. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_plugins_loader.py +0 -0
  202. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_plugins_registry.py +0 -0
  203. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_reasoning_strip.py +0 -0
  204. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_repair_byte_fallback.py +0 -0
  205. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_request_log.py +0 -0
  206. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_role_normalization.py +0 -0
  207. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_routing_adaptive.py +0 -0
  208. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_self_healing.py +0 -0
  209. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_setup_sh.py +0 -0
  210. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_state_store.py +0 -0
  211. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_token_estimation.py +0 -0
  212. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_token_estimation_accurate.py +0 -0
  213. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_tool_repair.py +0 -0
  214. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_translation_anthropic.py +0 -0
  215. {coderouter_cli-2.6.0 → coderouter_cli-2.6.1}/tests/test_translation_reverse.py +0 -0
@@ -36,6 +36,7 @@ ENV/
36
36
  # _OUTPUTS
37
37
  # ============================================================
38
38
  _OUTPUTS/
39
+ _run/
39
40
 
40
41
  # uv
41
42
  # Note: uv.lock SHOULD be committed (per plan.md §5.4)
@@ -6,6 +6,51 @@ versioning follows [SemVer](https://semver.org/).
6
6
 
7
7
  ---
8
8
 
9
+ ## [v2.6.1] — 2026-06-28 (Token-savings accounting)
10
+
11
+ Patch release: surfaces **token-savings accounting** in the metrics layer
12
+ and dashboard. The figure is owned by core, so it appears even when no
13
+ plugin is installed (trim savings from the context-budget guard), and the
14
+ optional `compress` plugin adds to the same total via a neutral
15
+ `tokens-saved` log event. **No new core dependency**, **no behavioral
16
+ change** to existing paths, and **fully backward compatible** — existing
17
+ counters and events are untouched; the new buckets are additive.
18
+
19
+ ### Added
20
+
21
+ - **Token-savings buckets in `MetricsCollector`**
22
+ (`coderouter/metrics/collector.py`). `tokens_saved_total` plus a
23
+ per-mechanism breakdown (`tokens_saved_by_mechanism`). Two feeds
24
+ aggregate under one schema: `trim` (derived from the existing
25
+ `context-budget-trimmed` event's before/after token estimate) and
26
+ `compress` (the neutral `tokens-saved` event emitted by the compress
27
+ plugin — no core import). Wired through `snapshot()`, `save_state()`,
28
+ `load_state()`, and `reset()`.
29
+ - **Dashboard Token Savings tiles**
30
+ (`coderouter/ingress/dashboard_routes.py`). Three tiles — trim /
31
+ compress / total — in the "Cost & Language Tax" panel, zero-filled so a
32
+ fresh or local-only deployment renders cleanly.
33
+
34
+ ### Docs / examples
35
+
36
+ - Reorganized provider samples under `examples/` with a category index.
37
+ - Added the language-tax guide (JA/EN) and a Claude Code +
38
+ llama.cpp/vllm backend guide.
39
+
40
+ ### Tests
41
+
42
+ - `tests/test_tokens_saved_metric.py` — trim/compress accounting,
43
+ negative-delta clamping, combined aggregate, persistence round-trip,
44
+ and reset. Full suite: **1263 passed, 1 skipped**.
45
+
46
+ ### Companion
47
+
48
+ - `coderouter-plugin-compress` emits the `tokens-saved` event (plugin
49
+ branch `feat/tokens-saved-emit`, v0.2.0). CodeRouter core works
50
+ standalone — trim savings show without the plugin.
51
+
52
+ ---
53
+
9
54
  ## [v2.6.0] — 2026-06-20 (Language Tax: measure, route, visualize)
10
55
 
11
56
  Minor release: makes the CJK **"language tax"** — cloud tokenizers bill
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: coderouter-cli
3
- Version: 2.6.0
3
+ Version: 2.6.1
4
4
  Summary: Local-first, free-first, fallback-built-in LLM router. Claude Code / OpenAI compatible.
5
5
  Project-URL: Homepage, https://github.com/zephel01/CodeRouter
6
6
  Project-URL: Repository, https://github.com/zephel01/CodeRouter
@@ -161,6 +161,36 @@ ANTHROPIC_BASE_URL=http://localhost:8088 ANTHROPIC_AUTH_TOKEN=dummy claude
161
161
  | **`coderouter replay`** | provider 切替の効果を統計比較 (A/B 分析) / `--suggest-rules` でルール最適化提案 |
162
162
  | **Continuous Probe** | idle 時も定期的に backend を監視 |
163
163
 
164
+ ### 言語税トラッキング — v2.6.0
165
+
166
+ 日本語などの CJK テキストは、クラウドのトークナイザだと「同じ意味の英語」より多くのトークンを消費します(**実測: GPT-4o 系 o200k で平均 1.6 倍、GPT-4 系 cl100k で平均 2.0 倍**)。ローカル LLM は課金されないので、この「言語税」はクラウド利用時だけ効いてきます。CodeRouter v2.6.0 はこれを **計測・ルーティング回避・可視化** します。
167
+
168
+ | 機能 | 何をしてくれるか |
169
+ |---|---|
170
+ | **言語税の計測** | プロバイダに `tokenizer_path`(ローカルの `tokenizer.json`)を指定すると、char/4 ヒューリスティック比の実トークン倍率と割増 USD を算出(ネットワーク不要・未設定なら無効) |
171
+ | **`cjk_ratio_min` ルーティング** | CJK 比率が高いリクエストを自動でローカル LLM(課金ゼロ)へ。コードや英語はクラウドへ |
172
+ | **ダッシュボード可視化** | `/dashboard` の「Cost & Language Tax」パネルで総支出・キャッシュ節約・言語税をリアルタイム表示 |
173
+
174
+ ```yaml
175
+ # providers.yaml — CJK 多めのターンはローカルへ自動回避
176
+ auto_router:
177
+ rules:
178
+ - match: { cjk_ratio_min: 0.3 } # 日本語が3割以上 → ローカル
179
+ profile: local
180
+ - match: { has_tools: true } # ツール使用 → クラウド
181
+ profile: cloud
182
+ default_rule_profile: cloud
183
+
184
+ providers:
185
+ - name: cloud-sonnet
186
+ kind: anthropic
187
+ base_url: https://api.anthropic.com
188
+ model: claude-sonnet-4-6
189
+ tokenizer_path: ~/.coderouter/tokenizers/sonnet.json # 言語税の正確計測(任意)
190
+ ```
191
+
192
+ 詳細 → [言語税ガイド](./docs/guides/language-tax.md)
193
+
164
194
  ### Launcher — llama.cpp / vllm 起動 UI
165
195
 
166
196
  `http://localhost:8088/launcher` で開けるブラウザ UI。llama.cpp や vllm を GUI で起動・管理できます。
@@ -229,6 +259,7 @@ providers:
229
259
  | 使いこなす | [利用ガイド](./docs/guides/usage-guide.md) |
230
260
  | 無料で回す | [無料枠ガイド](./docs/guides/free-tier-guide.md) |
231
261
  | llama.cpp / vllm を GUI で起動 | [Launcher ガイド](./docs/backends/launcher.md) |
262
+ | 言語税を計測・回避する | [言語税ガイド](./docs/guides/language-tax.md) |
232
263
  | 詰まった | [トラブルシューティング](./docs/guides/troubleshooting.md) |
233
264
  | 設計を知りたい | [アーキテクチャ詳細](./docs/concepts/architecture.md) |
234
265
  | 全リリース履歴 | [CHANGELOG](./CHANGELOG.md) |
@@ -116,6 +116,36 @@ Full decision matrix → [Do I need CodeRouter?](./docs/start/when-do-i-need-cod
116
116
  | **`coderouter replay`** | Compare providers statistically (A/B analysis) / `--suggest-rules` for automated rule suggestions |
117
117
  | **Continuous Probe** | Background health monitoring even during idle |
118
118
 
119
+ ### Language Tax tracking — v2.6.0
120
+
121
+ CJK text (Japanese / Chinese / Korean) costs more tokens on cloud tokenizers than the same meaning in English (**measured: ~1.6× on average with GPT-4o-era o200k, ~2.0× with GPT-4-era cl100k**). Local models bill nothing per token, so this "language tax" only bites on the cloud leg. CodeRouter v2.6.0 makes it **measurable, routable, and visible**.
122
+
123
+ | Feature | What it does |
124
+ |---|---|
125
+ | **Language-tax measurement** | Set a provider's `tokenizer_path` (a local `tokenizer.json`) to compute the real token multiplier vs the char/4 heuristic and the extra USD. No network; inert when unset. |
126
+ | **`cjk_ratio_min` routing** | Auto-route CJK-heavy turns to a local (tax-free) model; code/English falls through to the cloud chain. |
127
+ | **Dashboard panel** | The `/dashboard` "Cost & Language Tax" panel shows total spend, cache savings, and language-tax spend live. |
128
+
129
+ ```yaml
130
+ # providers.yaml — steer CJK-heavy turns to local
131
+ auto_router:
132
+ rules:
133
+ - match: { cjk_ratio_min: 0.3 } # >=30% CJK chars -> local
134
+ profile: local
135
+ - match: { has_tools: true } # tool use -> cloud
136
+ profile: cloud
137
+ default_rule_profile: cloud
138
+
139
+ providers:
140
+ - name: cloud-sonnet
141
+ kind: anthropic
142
+ base_url: https://api.anthropic.com
143
+ model: claude-sonnet-4-6
144
+ tokenizer_path: ~/.coderouter/tokenizers/sonnet.json # accurate language-tax (optional)
145
+ ```
146
+
147
+ Details → [Language Tax guide](./docs/guides/language-tax.en.md)
148
+
119
149
  ### Launcher — llama.cpp / vllm GUI
120
150
 
121
151
  Browser UI at `http://localhost:8088/launcher` for starting and managing local inference backends.
@@ -184,6 +214,7 @@ More detail → [Usage guide](./docs/guides/usage-guide.en.md) · [Architecture]
184
214
  | Use it well | [Usage guide](./docs/guides/usage-guide.en.md) |
185
215
  | Run for free | [Free-tier guide](./docs/guides/free-tier-guide.en.md) |
186
216
  | Launch llama.cpp / vllm via GUI | [Launcher guide](./docs/backends/launcher.md) |
217
+ | Measure & avoid the language tax | [Language Tax guide](./docs/guides/language-tax.en.md) |
187
218
  | Stuck? | [Troubleshooting](./docs/guides/troubleshooting.en.md) |
188
219
  | Understand the design | [Architecture](./docs/concepts/architecture.md) |
189
220
  | Full release history | [CHANGELOG](./CHANGELOG.md) |
@@ -116,6 +116,36 @@ ANTHROPIC_BASE_URL=http://localhost:8088 ANTHROPIC_AUTH_TOKEN=dummy claude
116
116
  | **`coderouter replay`** | provider 切替の効果を統計比較 (A/B 分析) / `--suggest-rules` でルール最適化提案 |
117
117
  | **Continuous Probe** | idle 時も定期的に backend を監視 |
118
118
 
119
+ ### 言語税トラッキング — v2.6.0
120
+
121
+ 日本語などの CJK テキストは、クラウドのトークナイザだと「同じ意味の英語」より多くのトークンを消費します(**実測: GPT-4o 系 o200k で平均 1.6 倍、GPT-4 系 cl100k で平均 2.0 倍**)。ローカル LLM は課金されないので、この「言語税」はクラウド利用時だけ効いてきます。CodeRouter v2.6.0 はこれを **計測・ルーティング回避・可視化** します。
122
+
123
+ | 機能 | 何をしてくれるか |
124
+ |---|---|
125
+ | **言語税の計測** | プロバイダに `tokenizer_path`(ローカルの `tokenizer.json`)を指定すると、char/4 ヒューリスティック比の実トークン倍率と割増 USD を算出(ネットワーク不要・未設定なら無効) |
126
+ | **`cjk_ratio_min` ルーティング** | CJK 比率が高いリクエストを自動でローカル LLM(課金ゼロ)へ。コードや英語はクラウドへ |
127
+ | **ダッシュボード可視化** | `/dashboard` の「Cost & Language Tax」パネルで総支出・キャッシュ節約・言語税をリアルタイム表示 |
128
+
129
+ ```yaml
130
+ # providers.yaml — CJK 多めのターンはローカルへ自動回避
131
+ auto_router:
132
+ rules:
133
+ - match: { cjk_ratio_min: 0.3 } # 日本語が3割以上 → ローカル
134
+ profile: local
135
+ - match: { has_tools: true } # ツール使用 → クラウド
136
+ profile: cloud
137
+ default_rule_profile: cloud
138
+
139
+ providers:
140
+ - name: cloud-sonnet
141
+ kind: anthropic
142
+ base_url: https://api.anthropic.com
143
+ model: claude-sonnet-4-6
144
+ tokenizer_path: ~/.coderouter/tokenizers/sonnet.json # 言語税の正確計測(任意)
145
+ ```
146
+
147
+ 詳細 → [言語税ガイド](./docs/guides/language-tax.md)
148
+
119
149
  ### Launcher — llama.cpp / vllm 起動 UI
120
150
 
121
151
  `http://localhost:8088/launcher` で開けるブラウザ UI。llama.cpp や vllm を GUI で起動・管理できます。
@@ -184,6 +214,7 @@ providers:
184
214
  | 使いこなす | [利用ガイド](./docs/guides/usage-guide.md) |
185
215
  | 無料で回す | [無料枠ガイド](./docs/guides/free-tier-guide.md) |
186
216
  | llama.cpp / vllm を GUI で起動 | [Launcher ガイド](./docs/backends/launcher.md) |
217
+ | 言語税を計測・回避する | [言語税ガイド](./docs/guides/language-tax.md) |
187
218
  | 詰まった | [トラブルシューティング](./docs/guides/troubleshooting.md) |
188
219
  | 設計を知りたい | [アーキテクチャ詳細](./docs/concepts/architecture.md) |
189
220
  | 全リリース履歴 | [CHANGELOG](./CHANGELOG.md) |
@@ -184,6 +184,21 @@ _DASHBOARD_HTML = r"""<!doctype html>
184
184
  </div>
185
185
  </div>
186
186
  <div id="language-tax-by-provider" class="text-xs text-slate-400 tabnum mt-3"></div>
187
+ <!-- Token Savings: trim (core budget guard) + compress (plugin) -->
188
+ <div class="grid grid-cols-3 gap-3 mt-3">
189
+ <div class="rounded-md bg-slate-800/50 p-3">
190
+ <div class="text-xs text-slate-400">Tokens saved &middot; trim</div>
191
+ <div class="text-2xl font-semibold tabnum text-sky-400" data-bind="tokens_saved_trim">0</div>
192
+ </div>
193
+ <div class="rounded-md bg-slate-800/50 p-3">
194
+ <div class="text-xs text-slate-400">Tokens saved &middot; compress</div>
195
+ <div class="text-2xl font-semibold tabnum text-sky-400" data-bind="tokens_saved_compress">0</div>
196
+ </div>
197
+ <div class="rounded-md bg-slate-800/50 p-3">
198
+ <div class="text-xs text-slate-400">Tokens saved &middot; total</div>
199
+ <div class="text-2xl font-semibold tabnum text-green-400" data-bind="tokens_saved_total">0</div>
200
+ </div>
201
+ </div>
187
202
  </section>
188
203
  <section class="bg-slate-900/60 border border-slate-800 rounded-lg p-4">
189
204
  <h2 class="text-sm font-semibold uppercase tracking-wider text-slate-400 mb-3">Usage Mix</h2>
@@ -474,6 +489,14 @@ _DASHBOARD_HTML = r"""<!doctype html>
474
489
  rows.map(([n, v]) =>
475
490
  '<span class="mr-4"><span class="text-slate-500">' + escapeHTML(n) +
476
491
  '</span> ' + usd(v) + '</span>').join("");
492
+ // token-savings tiles. trim comes from the core budget guard;
493
+ // compress from the optional plugin. Collector zero-fills, so an
494
+ // install with neither still renders "0" cleanly.
495
+ const ts = c.tokens_saved_by_mechanism || {};
496
+ const intfmt = (x) => (Number(x) || 0).toLocaleString();
497
+ setBind("tokens_saved_trim", intfmt(ts.trim));
498
+ setBind("tokens_saved_compress", intfmt(ts.compress));
499
+ setBind("tokens_saved_total", intfmt(c.tokens_saved_total));
477
500
  };
478
501
 
479
502
  const renderSnapshot = (snap) => {
@@ -197,6 +197,16 @@ class MetricsCollector(logging.Handler):
197
197
  self._language_tax_usd: dict[str, float] = {}
198
198
  self._language_tax_usd_aggregate: float = 0.0
199
199
 
200
+ # token-savings accounting. Tokens that never reached the backend
201
+ # because a reduction mechanism shrank or dropped them. Two
202
+ # mechanisms feed this: ``trim`` (core context-budget guard, derived
203
+ # from the existing ``context-budget-trimmed`` event) and
204
+ # ``compress`` (the optional compress plugin, via the neutral
205
+ # ``tokens-saved`` event). Owned by core so the figure exists even
206
+ # when no plugin is installed.
207
+ self._tokens_saved_total: int = 0
208
+ self._tokens_saved_by_mechanism: Counter[str] = Counter()
209
+
200
210
  # v2.0-F (L1): context budget guard counters. Per-profile counts
201
211
  # of warnings (over warn threshold) and trims (messages removed).
202
212
  # The ``latest_usage_ratio`` dict records the most recent ratio
@@ -425,6 +435,41 @@ class MetricsCollector(logging.Handler):
425
435
  profile = _str(extras.get("profile"))
426
436
  self._context_budget_trims_total += 1
427
437
  self._context_budget_trims_by_profile[profile] += 1
438
+ # token-savings: the trim already carries the estimated
439
+ # before/after token counts, so fold the delta into the
440
+ # shared savings buckets (mechanism="trim").
441
+ before = extras.get("estimated_tokens_before")
442
+ after = extras.get("estimated_tokens_after")
443
+ if isinstance(before, int | float) and isinstance(
444
+ after, int | float
445
+ ):
446
+ saved = max(0, int(before) - int(after))
447
+ if saved:
448
+ self._tokens_saved_total += saved
449
+ self._tokens_saved_by_mechanism["trim"] += saved
450
+ elif event == "tokens-saved":
451
+ # Neutral token-savings event emitted by non-core reduction
452
+ # mechanisms (e.g. the compress plugin). Carries a
453
+ # ``mechanism`` label plus either a precomputed
454
+ # ``tokens_saved`` or a ``tokens_before`` / ``tokens_after``
455
+ # pair. Negative deltas clamp to zero. No core import needed
456
+ # by the emitter — it just logs this record name.
457
+ mechanism = _str(extras.get("mechanism")) or "unknown"
458
+ saved_raw = extras.get("tokens_saved")
459
+ before = extras.get("tokens_before")
460
+ after = extras.get("tokens_after")
461
+ if isinstance(saved_raw, int | float):
462
+ saved = max(0, int(saved_raw))
463
+ elif isinstance(before, int | float) and isinstance(
464
+ after, int | float
465
+ ):
466
+ saved = max(0, int(before) - int(after))
467
+ else:
468
+ saved = 0
469
+ if saved:
470
+ self._tokens_saved_total += saved
471
+ self._tokens_saved_by_mechanism[mechanism] += saved
472
+ self._push_recent(event, extras, record)
428
473
  elif event == "drift-detected":
429
474
  # v2.0-G (L4): drift detection fired.
430
475
  provider = _str(extras.get("provider"))
@@ -624,6 +669,11 @@ class MetricsCollector(logging.Handler):
624
669
  "language_tax_usd_aggregate": round(
625
670
  self._language_tax_usd_aggregate, 6
626
671
  ),
672
+ # token-savings: total + per-mechanism (trim / compress).
673
+ "tokens_saved_total": self._tokens_saved_total,
674
+ "tokens_saved_by_mechanism": dict(
675
+ self._tokens_saved_by_mechanism
676
+ ),
627
677
  # v2.0-F (L1): context budget guard aggregate counters.
628
678
  "context_budget_warnings_total": self._context_budget_warnings_total,
629
679
  "context_budget_trims_total": self._context_budget_trims_total,
@@ -684,6 +734,10 @@ class MetricsCollector(logging.Handler):
684
734
  "chain_budget_exceeded_total": self._chain_budget_exceeded_total,
685
735
  "chain_memory_pressure_blocked_total": self._chain_memory_pressure_blocked_total,
686
736
  "chain_uniform_auth_failure_total": self._chain_uniform_auth_failure_total,
737
+ "tokens_saved_total": self._tokens_saved_total,
738
+ "tokens_saved_by_mechanism": dict(
739
+ self._tokens_saved_by_mechanism
740
+ ),
687
741
  "probe_rounds_total": self._probe_rounds_total,
688
742
  }
689
743
 
@@ -724,6 +778,9 @@ class MetricsCollector(logging.Handler):
724
778
  self._language_tax_usd_aggregate += float(
725
779
  state.get("language_tax_usd_aggregate", 0.0)
726
780
  )
781
+ self._tokens_saved_total += int(state.get("tokens_saved_total", 0))
782
+ for k, v in (state.get("tokens_saved_by_mechanism") or {}).items():
783
+ self._tokens_saved_by_mechanism[k] += int(v)
727
784
  self._chain_paid_gate_blocked_total += int(
728
785
  state.get("chain_paid_gate_blocked_total", 0)
729
786
  )
@@ -782,6 +839,9 @@ class MetricsCollector(logging.Handler):
782
839
  # v2.6
783
840
  self._language_tax_usd.clear()
784
841
  self._language_tax_usd_aggregate = 0.0
842
+ # token-savings
843
+ self._tokens_saved_total = 0
844
+ self._tokens_saved_by_mechanism.clear()
785
845
  # v2.0-H (L6)
786
846
  self._partial_stitch_surfaced_total = 0
787
847
  # v2.0-I
@@ -16,10 +16,12 @@ Index of CodeRouter's public documentation — find the right page by what you w
16
16
  | 自分に必要か知りたい / Is it for me? | [start/when-do-i-need-coderouter](start/when-do-i-need-coderouter.md) |
17
17
  | 無料で運用したい / Run for free | [guides/free-tier-guide](guides/free-tier-guide.md) |
18
18
  | 機能を一通り知りたい / Learn the features | [guides/usage-guide](guides/usage-guide.md) |
19
+ | 言語税を計測・回避したい / Measure & avoid the language tax | [guides/language-tax](guides/language-tax.md) |
19
20
  | エラーで詰まった / Something broke | [guides/troubleshooting](guides/troubleshooting.md) |
20
21
  | ローカル LLM を起動したい / Launch a local LLM | [backends/launcher-quickstart](backends/launcher-quickstart.md) |
21
22
  | APIキー・機密の扱い / Secrets & security | [guides/security](guides/security.md) |
22
23
  | 仕組みを理解したい / Understand the design | [concepts/architecture](concepts/architecture.md) |
24
+ | プラグインで拡張したい / Extend with plugins | [対応プラグイン / Plugins](#対応プラグイン--plugins) |
23
25
 
24
26
  ---
25
27
 
@@ -55,6 +57,7 @@ Many documents have a Japanese version (`.md`) and an English version (`.en.md`)
55
57
  日常的に使いこなすためのガイド。 / Day-to-day usage.
56
58
 
57
59
  - **usage-guide** — 機能を一通り使いこなす / Full feature guide · [日本語](guides/usage-guide.md) · [English](guides/usage-guide.en.md)
60
+ - **language-tax** — 日本語の言語税を計測・ルーティング回避・可視化 / Measure, route around, and visualize the CJK language tax · [日本語](guides/language-tax.md) · [English](guides/language-tax.en.md)
58
61
  - **free-tier-guide** — NVIDIA NIM × OpenRouter Free でコストゼロ運用 / Zero-cost operation · [日本語](guides/free-tier-guide.md) · [English](guides/free-tier-guide.en.md)
59
62
  - **troubleshooting** — つまずいたときの解決集 / Fixing problems · [日本語](guides/troubleshooting.md) · [English](guides/troubleshooting.en.md)
60
63
  - **security** — シークレット管理とセキュリティ方針 / Secrets handling & security posture · [日本語](guides/security.md) · [English](guides/security.en.md)
@@ -91,4 +94,38 @@ CodeRouter の仕組みと信頼性機構。 / How CodeRouter works and its reli
91
94
 
92
95
  ---
93
96
 
94
- 最終更新 / Last updated: 2026-05-22
97
+ ## 対応プラグイン / Plugins
98
+
99
+ CodeRouter は v2.3.0 で入った **Plugin SDK** により、別パッケージのプラグインを *opt-in* で読み込めます。`plugins.enabled` に名前を明示したときだけ作動する(サプライチェーン防御)ため、インストールしただけでは何も起きません。各プラグインは独立した PyPI パッケージなので、**コアの依存は一切増えません**。
100
+
101
+ CodeRouter's **Plugin SDK** (since v2.3.0) loads out-of-tree plugins *opt-in*: a plugin runs only when its name is listed in `plugins.enabled` (supply-chain defense), so installing one does nothing by itself. Each plugin ships as a separate PyPI package, so **the core's dependencies never grow**.
102
+
103
+ | プラグイン / Plugin | 何をするか / What it does | インストール / Install | リポジトリ / Repo |
104
+ |---|---|---|---|
105
+ | **compress** | ツール出力(JSON / ログ)を LLM に届く前に圧縮してトークンを削減。原文はローカル保持で可逆(CCR)。`cache-align` で Anthropic プロンプトキャッシュも整列。<br>Compresses tool output (JSON / logs) before it reaches the LLM to cut tokens; originals kept locally and reversible (CCR). `cache-align` also aligns Anthropic prompt caching. | `pip install coderouter-plugin-compress` | [coderouter-plugin-compress](https://github.com/zephel01/coderouter-plugin-compress) |
106
+ | **memory** | 応答から key facts を抽出して `facts.jsonl` に蓄積し、次セッションの system prompt へ自動注入。「毎回同じ説明」を wire 層で解消。<br>Extracts key facts from responses into `facts.jsonl` and auto-injects them into the next session's system prompt — solving "explain it every time" at the wire layer. | `pip install coderouter-plugin-memory` | [coderouter-plugin-memory](https://github.com/zephel01/coderouter-plugin-memory) |
107
+
108
+ 有効化は `providers.yaml` に追記するだけ。起動ログに `plugin-loaded` が出れば有効です。
109
+ Enable by adding to `providers.yaml`; a `plugin-loaded` line in the startup log confirms activation.
110
+
111
+ ```yaml
112
+ plugins:
113
+ enabled:
114
+ - compress # ツール出力を圧縮 / compress tool output
115
+ - compress-stats # 圧縮率を coderouter stats に出力 / report compression ratio
116
+ - cache-align # プロンプトキャッシュのブレークポイント整列 / align prompt-cache breakpoints
117
+ - memory # セッション横断メモリ / cross-session memory
118
+ config:
119
+ compress:
120
+ mode: safe # off | safe | aggressive
121
+ ccr: true # 圧縮の可逆復元(既定 on)/ reversible re-expansion (default on)
122
+ memory:
123
+ consolidate_model: qwen3:1.7b
124
+ ```
125
+
126
+ 各プラグインの詳細・設定は上記リポジトリの README を参照してください。
127
+ See each plugin's repo README for full configuration.
128
+
129
+ ---
130
+
131
+ 最終更新 / Last updated: 2026-06-24
@@ -0,0 +1,172 @@
1
+ # Claude Code × ローカル LLM(llama.cpp / vLLM)接続ガイド — Ollama なしの設定とトラブルシュート
2
+
3
+ Ollama を使わず、**ダウンロード済みの `.gguf` を llama.cpp で**、または **vLLM で** 動かし、CodeRouter 経由で Claude Code に繋ぐための実践ガイドです。
4
+ 構成の作り方と、実際に踏みやすいエラー(400 / 接続拒否 / 502 / コネクタ無効化 / `n_ctx=4096` のまま)の直し方をまとめています。
5
+
6
+ > 関連: [Launcher ガイド](./launcher.md) / [バックエンド インストール手順書](./install-backends.md) / [examples/README](../../examples/README.md)
7
+
8
+ ---
9
+
10
+ ## 全体構成
11
+
12
+ ```
13
+ Claude Code ──(ANTHROPIC_BASE_URL)──► CodeRouter (:8088) ──► ① llama.cpp (:8080)
14
+ ├─► ② vLLM (:8000)
15
+ └─► ③ 無料クラウド (fallback)
16
+ ```
17
+
18
+ CodeRouter が求めるのは「OpenAI 互換 API を話すバックエンド」だけです。Ollama はその選択肢の 1 つにすぎず、llama.cpp / vLLM でも等価に使えます。
19
+
20
+ ---
21
+
22
+ ## セットアップ手順
23
+
24
+ ### 1. バックエンドを起動する(Ollama なし)
25
+
26
+ **llama.cpp(ダウンロード済み GGUF を使う)**
27
+
28
+ ```bash
29
+ brew install llama.cpp # macOS / Linux(Windows: winget install ggml.llamacpp)
30
+
31
+ llama-server -m ~/models/<model>.gguf --host 127.0.0.1 --port 8080 \
32
+ -ngl 99 --ctx-size 32768
33
+ # 起動ログの「n_ctx = 32768」を必ず確認する
34
+ ```
35
+
36
+ **vLLM(NVIDIA GPU)**
37
+
38
+ ```bash
39
+ uv venv ~/.coderouter/backends/vllm
40
+ ~/.coderouter/backends/vllm/bin/python -m pip install vllm
41
+ ~/.coderouter/backends/vllm/bin/python -m vllm.entrypoints.openai.api_server \
42
+ --model Qwen/Qwen2.5-Coder-7B-Instruct --port 8000 --max-model-len 32768
43
+ ```
44
+
45
+ > 起動を GUI に任せたい場合は [Launcher](./launcher.md)。ただし Launcher が面倒を見るのは**起動まで**で、下記の provider 登録は別作業です。
46
+
47
+ ### 2. CodeRouter に provider として登録する(`~/.coderouter/providers.yaml`)
48
+
49
+ ```yaml
50
+ allow_paid: false
51
+ default_profile: default
52
+
53
+ providers:
54
+ - name: llama-cpp-local
55
+ kind: openai_compat
56
+ base_url: http://localhost:8080/v1 # ← 起動したポートと一致させる
57
+ model: "" # llama-server は model 名を問わない
58
+ timeout_s: 120
59
+
60
+ - name: vllm-local
61
+ kind: openai_compat
62
+ base_url: http://localhost:8000/v1 # ← vLLM の既定は 8000
63
+ model: Qwen/Qwen2.5-Coder-7B-Instruct
64
+ timeout_s: 120
65
+
66
+ - name: openrouter-free # 逃げ先(任意だが推奨)
67
+ kind: openai_compat
68
+ base_url: https://openrouter.ai/api/v1
69
+ model: qwen/qwen3-coder:free
70
+ api_key_env: OPENROUTER_API_KEY
71
+
72
+ profiles:
73
+ - name: default
74
+ providers: [llama-cpp-local, vllm-local, openrouter-free]
75
+ ```
76
+
77
+ `examples/providers.llamacpp-vllm.yaml` をコピーして始めると速いです。
78
+
79
+ ### 3. CodeRouter を起動して Claude Code を繋ぐ
80
+
81
+ ```bash
82
+ # ターミナル1
83
+ coderouter serve --port 8088
84
+
85
+ # ターミナル2(このシェルだけに env を効かせる。グローバルに置かない)
86
+ ANTHROPIC_BASE_URL=http://localhost:8088 ANTHROPIC_AUTH_TOKEN=dummy claude
87
+ ```
88
+
89
+ `ANTHROPIC_AUTH_TOKEN` はダミーで可(CodeRouter は検証しない)。実 API キーは `providers.yaml` 側で管理します。
90
+
91
+ ---
92
+
93
+ ## 設定の 4 つの要点
94
+
95
+ ### ① ポートを一致させる
96
+
97
+ `base_url` のポートは起動した推論サーバーと一字一句一致させること。ズレると `transport error: All connection attempts failed`(接続拒否)になります。
98
+
99
+ | バックエンド | 既定ポート | 確認 |
100
+ |---|---|---|
101
+ | llama.cpp | `8080` | `curl localhost:8080/health` |
102
+ | vLLM | `8000` | `curl localhost:8000/v1/models` |
103
+ | Ollama | `11434` | `curl localhost:11434/api/version` |
104
+
105
+ ### ② context size を Claude Code 用に上げる
106
+
107
+ Claude Code は毎ターン **15〜35K tokens** を送ります。`--ctx-size` / `--max-model-len` が小さいと
108
+ `exceed_context_size_error (400)` になります。**32768 以上**を既定に。
109
+ モデルの学習時 context を超える場合は YaRN 等の rope 拡張を使います。
110
+
111
+ ```bash
112
+ llama-server -m <model>.gguf --port 8080 -ngl 99 \
113
+ --ctx-size 65536 --rope-scaling yarn --yarn-orig-ctx 32768
114
+ ```
115
+
116
+ 大きい ctx で OOM する場合は、ctx を下げる / KV 量子化(`--cache-type-k q8_0 --cache-type-v q8_0`)/ 小さいモデルへ。
117
+
118
+ ### ③ チェーン末尾に「効くフォールバック」を置く
119
+
120
+ `providers:` がローカルだけだと、落ちた瞬間に逃げ先が無く **502** になります。末尾に無料クラウドを 1 本足すと、ローカルが落ちても・context が載らなくても Claude Code が止まりません。有料は `ALLOW_PAID=true` を立てない限り呼ばれません(既定 `allow_paid: false`)。
121
+
122
+ ### ④ 編集の反映は 3 ステップ
123
+
124
+ 動いているプロセスには即時反映されません。
125
+
126
+ 1. 設定を **`~/.coderouter/providers.yaml`** に置く(`examples/` を直すだけでは効かない)
127
+ 2. **`coderouter serve` を再起動**(`launcher:` / プロファイルは起動時に読まれる)
128
+ 3. **バックエンドを起動し直す**(`--ctx-size` 等は再起動して初めて効く)
129
+
130
+ ---
131
+
132
+ ## トラブルシュート早見表
133
+
134
+ | 症状 / ログ | 原因 | 対処 |
135
+ |---|---|---|
136
+ | `400 exceed_context_size_error` `n_ctx:4096` | ctx-size が小さく Claude Code の prompt が入らない | `--ctx-size 32768` 以上で**起動し直す**。学習 ctx 超は YaRN |
137
+ | `transport error: All connection attempts failed` (status: null) | バックエンドが落ちている / **ポート不一致** | サーバを起動 + `base_url` のポートを実ポートに合わせる |
138
+ | すべて `provider-failed` → **502 Bad Gateway** | チェーンの逃げ先が全滅 | バックエンドを 1 つ復旧 + 末尾に無料クラウド fallback |
139
+ | 起動し直しても `n_ctx=4096` のまま | 旧プロセスが残存 / 設定が `~/.coderouter` に未反映 / serve 未再起動 | `ps aux \| grep llama-server` で実コマンド確認 → 反映3ステップ |
140
+ | OOM でバックエンドが即落ち | ctx を上げすぎ | ctx を下げる / KV 量子化 / 小さいモデル |
141
+ | `capability-degraded: cache_control` | OpenAI 形式へ翻訳時に Anthropic prompt-cache マーカーを落とすだけ | **無害**。対処不要 |
142
+ | `claude.ai connectors are disabled …` | env の `ANTHROPIC_AUTH_TOKEN`/`API_KEY` が claude.ai ログインより優先 | CodeRouter 用 env はそのシェル/フォルダ限定に(`direnv`)。普段使いシェルでは `unset` |
143
+ | `/mcp` に `✘ failed` が残る | 不要な MCP サーバ登録 | `claude mcp remove <name> -s user` |
144
+
145
+ ### 切り分けコマンド
146
+
147
+ ```bash
148
+ # バックエンドが生きているか
149
+ curl -s localhost:8080/health ; echo # llama.cpp
150
+ curl -s localhost:8000/v1/models ; echo # vLLM
151
+ ps aux | grep -E '[l]lama-server|[v]llm'
152
+
153
+ # CodeRouter 側の状態
154
+ open http://localhost:8088/dashboard # 誰が落ちているか色で分かる
155
+ coderouter doctor --check-model llama-cpp-local # provider を 6 プローブで診断
156
+ ```
157
+
158
+ ---
159
+
160
+ ## 3 つのバックエンド早見
161
+
162
+ | | 何が要るか | モデル形式 | 起動の単位 |
163
+ |---|---|---|---|
164
+ | Ollama | `ollama pull` | Ollama 管理 | デーモン 1 つが on-demand |
165
+ | **llama.cpp** | `.gguf` + `llama-server` | `.gguf`(手元のファイル) | **1 起動 = 1 モデル = 1 ポート** |
166
+ | **vLLM** | NVIDIA GPU + venv | HF ID / ローカルパス | 1 起動 = 1 モデル = 1 ポート |
167
+
168
+ llama.cpp / vLLM は「起動したモデルだけ」が使えます(Ollama のように 1 つの口で複数モデルを出し分けることはしません)。複数使うならポートを分けてそれぞれ provider 登録します。
169
+
170
+ ---
171
+
172
+ 最終更新: 2026-06-24