coderouter-cli 2.17.0__tar.gz → 2.19.0__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 (330) hide show
  1. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/CHANGELOG.md +104 -0
  2. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/PKG-INFO +3 -5
  3. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/README.en.md +2 -3
  4. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/README.md +2 -4
  5. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/adapters/anthropic_native.py +4 -0
  6. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/adapters/base.py +3 -0
  7. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/adapters/openai_compat.py +6 -0
  8. coderouter_cli-2.19.0/coderouter/adapters/slot_affinity.py +54 -0
  9. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/cli.py +2 -1
  10. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/config/schemas.py +36 -1
  11. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/doctor_claude_code.py +12 -0
  12. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/ingress/anthropic_routes.py +8 -2
  13. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/ingress/app.py +3 -0
  14. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/ingress/openai_routes.py +7 -2
  15. coderouter_cli-2.19.0/coderouter/ingress/responses_routes.py +269 -0
  16. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/routing/auto_router.py +46 -2
  17. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/routing/capability.py +4 -1
  18. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/translation/anthropic.py +3 -0
  19. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/translation/convert.py +4 -0
  20. coderouter_cli-2.19.0/coderouter/translation/responses.py +686 -0
  21. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/vscode_init.py +10 -1
  22. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/backends/llamacpp-direct.en.md +21 -0
  23. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/backends/llamacpp-direct.md +21 -0
  24. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/guides/subagent-routing.en.md +19 -2
  25. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/guides/subagent-routing.md +22 -2
  26. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/start/quickstart.en.md +27 -16
  27. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/start/quickstart.md +27 -16
  28. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/start/when-do-i-need-coderouter.en.md +1 -1
  29. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/start/when-do-i-need-coderouter.md +1 -1
  30. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/pyproject.toml +1 -1
  31. coderouter_cli-2.19.0/tests/test_auto_router_hints.py +99 -0
  32. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_context_budget.py +30 -16
  33. coderouter_cli-2.19.0/tests/test_responses_api.py +398 -0
  34. coderouter_cli-2.19.0/tests/test_slot_affinity.py +147 -0
  35. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/.gitignore +0 -0
  36. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/LICENSE +0 -0
  37. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/__init__.py +0 -0
  38. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/__main__.py +0 -0
  39. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/adapters/__init__.py +0 -0
  40. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/adapters/registry.py +0 -0
  41. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/cli_stats.py +0 -0
  42. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/config/__init__.py +0 -0
  43. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/config/capability_registry.py +0 -0
  44. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/config/env_file.py +0 -0
  45. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/config/loader.py +0 -0
  46. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/cost.py +0 -0
  47. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/credentials.py +0 -0
  48. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/data/__init__.py +0 -0
  49. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/data/model-capabilities.yaml +0 -0
  50. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/doctor.py +0 -0
  51. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/doctor_apply.py +0 -0
  52. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/env_security.py +0 -0
  53. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/errors.py +0 -0
  54. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/gguf_introspect.py +0 -0
  55. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/guards/__init__.py +0 -0
  56. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/guards/_fingerprint.py +0 -0
  57. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/guards/backend_health.py +0 -0
  58. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/guards/context_budget.py +0 -0
  59. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/guards/continuous_probe.py +0 -0
  60. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/guards/drift_actions.py +0 -0
  61. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/guards/drift_detection.py +0 -0
  62. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/guards/memory_budget.py +0 -0
  63. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/guards/memory_pressure.py +0 -0
  64. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/guards/self_healing.py +0 -0
  65. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/guards/tool_loop.py +0 -0
  66. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/hardware.py +0 -0
  67. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/ingress/__init__.py +0 -0
  68. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/ingress/anthropic_errors.py +0 -0
  69. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/ingress/dashboard_routes.py +0 -0
  70. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/ingress/launcher_routes.py +0 -0
  71. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/ingress/metrics_routes.py +0 -0
  72. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/ingress/tool_search.py +0 -0
  73. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/ingress/ui_auth.py +0 -0
  74. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/language_tax.py +0 -0
  75. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/launcher_devices.py +0 -0
  76. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/launcher_speculative.py +0 -0
  77. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/launcher_swap.py +0 -0
  78. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/logging.py +0 -0
  79. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/metrics/__init__.py +0 -0
  80. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/metrics/collector.py +0 -0
  81. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/metrics/prometheus.py +0 -0
  82. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/output_filters.py +0 -0
  83. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/plugins/__init__.py +0 -0
  84. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/plugins/base.py +0 -0
  85. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/plugins/loader.py +0 -0
  86. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/plugins/registry.py +0 -0
  87. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/py.typed +0 -0
  88. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/rollback.py +0 -0
  89. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/routing/__init__.py +0 -0
  90. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/routing/adaptive.py +0 -0
  91. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/routing/budget.py +0 -0
  92. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/routing/fallback.py +0 -0
  93. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/routing/fallback_trace.py +0 -0
  94. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/secret_redaction.py +0 -0
  95. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/state/__init__.py +0 -0
  96. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/state/audit_log.py +0 -0
  97. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/state/replay.py +0 -0
  98. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/state/request_log.py +0 -0
  99. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/state/store.py +0 -0
  100. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/state/suggest_rules.py +0 -0
  101. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/token_estimation.py +0 -0
  102. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/token_estimation_accurate.py +0 -0
  103. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/translation/__init__.py +0 -0
  104. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/coderouter/translation/tool_repair.py +0 -0
  105. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/README.en.md +0 -0
  106. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/README.md +0 -0
  107. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/assets/dashboard-demo.png +0 -0
  108. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/backends/claude-code-llamacpp-vllm.en.md +0 -0
  109. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/backends/claude-code-llamacpp-vllm.md +0 -0
  110. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/backends/external-agents.en.md +0 -0
  111. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/backends/external-agents.md +0 -0
  112. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/backends/gguf_dl.en.md +0 -0
  113. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/backends/gguf_dl.md +0 -0
  114. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/backends/hf-ollama-models.en.md +0 -0
  115. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/backends/hf-ollama-models.md +0 -0
  116. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/backends/install-backends.en.md +0 -0
  117. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/backends/install-backends.md +0 -0
  118. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/backends/launcher-quickstart.en.md +0 -0
  119. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/backends/launcher-quickstart.md +0 -0
  120. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/backends/launcher.en.md +0 -0
  121. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/backends/launcher.md +0 -0
  122. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/backends/lmstudio-direct.en.md +0 -0
  123. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/backends/lmstudio-direct.md +0 -0
  124. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/backends/verify-ollama-0.23.1.md +0 -0
  125. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/concepts/architecture.en.md +0 -0
  126. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/concepts/architecture.md +0 -0
  127. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/concepts/commit-point.en.md +0 -0
  128. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/concepts/commit-point.md +0 -0
  129. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/concepts/context-budget.en.md +0 -0
  130. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/concepts/context-budget.md +0 -0
  131. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/concepts/continuous-probing.en.md +0 -0
  132. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/concepts/continuous-probing.md +0 -0
  133. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/concepts/drift-detection.en.md +0 -0
  134. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/concepts/drift-detection.md +0 -0
  135. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/concepts/partial-stitch.en.md +0 -0
  136. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/concepts/partial-stitch.md +0 -0
  137. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/concepts/stream-truncation.en.md +0 -0
  138. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/concepts/stream-truncation.md +0 -0
  139. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/designs/agent-cli-plugin-extraction.md +0 -0
  140. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/designs/external-agents-adapter.md +0 -0
  141. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/designs/launcher-model-swap.md +0 -0
  142. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/designs/launcher-multi-build.md +0 -0
  143. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/designs/orchestration-companion.md +0 -0
  144. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/designs/v1.5-dashboard-mockup.html +0 -0
  145. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/designs/v1.6-auto-router-verification.md +0 -0
  146. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/designs/v1.6-auto-router.md +0 -0
  147. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/guides/free-tier-guide.en.md +0 -0
  148. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/guides/free-tier-guide.md +0 -0
  149. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/guides/language-tax.en.md +0 -0
  150. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/guides/language-tax.md +0 -0
  151. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/guides/remote-access.en.md +0 -0
  152. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/guides/remote-access.md +0 -0
  153. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/guides/security.en.md +0 -0
  154. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/guides/security.md +0 -0
  155. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/guides/troubleshooting.en.md +0 -0
  156. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/guides/troubleshooting.md +0 -0
  157. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/guides/usage-guide.en.md +0 -0
  158. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/guides/usage-guide.md +0 -0
  159. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/guides/vscode.md +0 -0
  160. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/low-memory-integration.en.md +0 -0
  161. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/low-memory-integration.md +0 -0
  162. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/openrouter-roster/CHANGES.md +0 -0
  163. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/openrouter-roster/README.md +0 -0
  164. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/openrouter-roster/latest.json +0 -0
  165. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/retrospectives/v0.4.md +0 -0
  166. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/retrospectives/v0.5-verify.md +0 -0
  167. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/retrospectives/v0.5.md +0 -0
  168. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/retrospectives/v0.6.md +0 -0
  169. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/retrospectives/v0.7.md +0 -0
  170. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/retrospectives/v1.0-verify.md +0 -0
  171. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/docs/retrospectives/v1.0.md +0 -0
  172. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/examples/.env.example +0 -0
  173. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/examples/README.md +0 -0
  174. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/examples/providers-agent-cli.yaml +0 -0
  175. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/examples/providers-multiagent.yaml +0 -0
  176. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/examples/providers.cli-session.yaml +0 -0
  177. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/examples/providers.context-budget-test.yaml +0 -0
  178. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/examples/providers.llamacpp-vllm.yaml +0 -0
  179. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/examples/providers.nvidia-nim.yaml +0 -0
  180. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/examples/providers.ollama-auto-custom.yaml +0 -0
  181. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/examples/providers.ollama-auto.yaml +0 -0
  182. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/examples/providers.ollama-free-chain.yaml +0 -0
  183. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/examples/providers.opusplan.yaml +0 -0
  184. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/examples/providers.raspberrypi.yaml +0 -0
  185. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/examples/providers.swap.yaml +0 -0
  186. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/examples/providers.yaml +0 -0
  187. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/scripts/demo_traffic.sh +0 -0
  188. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/scripts/openrouter_roster_diff.py +0 -0
  189. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/scripts/smoke_v2_2.sh +0 -0
  190. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/scripts/verify-providers.yaml +0 -0
  191. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/scripts/verify_ollama_0_23.py +0 -0
  192. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/scripts/verify_v0_5.sh +0 -0
  193. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/scripts/verify_v1_0.sh +0 -0
  194. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/__init__.py +0 -0
  195. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/conftest.py +0 -0
  196. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_adapter_anthropic.py +0 -0
  197. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_agent_cli.py +0 -0
  198. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_anthropic_errors.py +0 -0
  199. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_audit_log.py +0 -0
  200. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_auto_router.py +0 -0
  201. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_auto_router_cjk.py +0 -0
  202. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_backend_health.py +0 -0
  203. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_budget.py +0 -0
  204. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_capability.py +0 -0
  205. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_capability_degraded_payload.py +0 -0
  206. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_capability_registry.py +0 -0
  207. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_capability_registry_cache_control.py +0 -0
  208. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_capability_tool_choice.py +0 -0
  209. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_claude_code_suitability.py +0 -0
  210. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_cli.py +0 -0
  211. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_cli_bind_warning.py +0 -0
  212. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_cli_stats.py +0 -0
  213. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_config.py +0 -0
  214. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_config_cwd_warning.py +0 -0
  215. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_config_shim_actions.py +0 -0
  216. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_continuous_probe.py +0 -0
  217. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_credentials.py +0 -0
  218. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_dashboard_endpoint.py +0 -0
  219. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_doctor.py +0 -0
  220. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_doctor_apply.py +0 -0
  221. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_doctor_cache_probe.py +0 -0
  222. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_doctor_claude_code.py +0 -0
  223. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_drift_actions.py +0 -0
  224. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_drift_detection.py +0 -0
  225. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_drift_detection_integration.py +0 -0
  226. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_env_file.py +0 -0
  227. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_env_security.py +0 -0
  228. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_errors.py +0 -0
  229. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_examples_yaml.py +0 -0
  230. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_examples_yaml_roundtrip.py +0 -0
  231. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_fallback.py +0 -0
  232. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_fallback_anthropic.py +0 -0
  233. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_fallback_cache_control.py +0 -0
  234. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_fallback_cache_observed.py +0 -0
  235. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_fallback_cache_strip.py +0 -0
  236. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_fallback_empty_response.py +0 -0
  237. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_fallback_misconfig_warn.py +0 -0
  238. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_fallback_paid_gate.py +0 -0
  239. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_fallback_reason.py +0 -0
  240. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_fallback_thinking.py +0 -0
  241. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_fallback_tool_choice_emulate.py +0 -0
  242. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_fallback_tool_integrity.py +0 -0
  243. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_fix_h1_prometheus_drift.py +0 -0
  244. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_fix_h2_h6_translation.py +0 -0
  245. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_fix_h3_client_reuse.py +0 -0
  246. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_fix_h4_h5_guards.py +0 -0
  247. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_fix_h7_probe_restore.py +0 -0
  248. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_fix_h8_launcher_auth.py +0 -0
  249. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_fix_mA_routing.py +0 -0
  250. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_fix_mB_adapters.py +0 -0
  251. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_fix_mC_convert.py +0 -0
  252. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_fix_mD_logging_metrics.py +0 -0
  253. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_fix_mE_config_validation.py +0 -0
  254. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_fix_mF_ingress.py +0 -0
  255. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_fix_v213_launcher_hardening.py +0 -0
  256. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_gguf_introspect.py +0 -0
  257. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_guards_tool_loop.py +0 -0
  258. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_hardware.py +0 -0
  259. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_import_hygiene.py +0 -0
  260. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_ingress_anthropic.py +0 -0
  261. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_ingress_count_tokens.py +0 -0
  262. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_ingress_profile.py +0 -0
  263. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_language_tax.py +0 -0
  264. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_language_tax_integration.py +0 -0
  265. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_launcher_backend_variants.py +0 -0
  266. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_launcher_config_bench.py +0 -0
  267. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_launcher_devices.py +0 -0
  268. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_launcher_devices_detect.py +0 -0
  269. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_launcher_devices_routes.py +0 -0
  270. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_launcher_gui_devices.py +0 -0
  271. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_launcher_gui_events.py +0 -0
  272. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_launcher_gui_readiness.py +0 -0
  273. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_launcher_gui_sweep_close.py +0 -0
  274. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_launcher_mtp.py +0 -0
  275. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_launcher_mtp_fallback.py +0 -0
  276. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_launcher_provider_sync.py +0 -0
  277. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_launcher_readiness_restart.py +0 -0
  278. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_launcher_swap.py +0 -0
  279. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_launcher_swap_review.py +0 -0
  280. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_launcher_variant_config.py +0 -0
  281. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_launcher_variant_gui.py +0 -0
  282. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_launcher_variant_routes.py +0 -0
  283. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_launcher_variant_sweep.py +0 -0
  284. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_memory_budget.py +0 -0
  285. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_memory_pressure.py +0 -0
  286. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_metrics_cache.py +0 -0
  287. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_metrics_collector.py +0 -0
  288. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_metrics_cost.py +0 -0
  289. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_metrics_endpoint.py +0 -0
  290. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_metrics_jsonl.py +0 -0
  291. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_metrics_prometheus.py +0 -0
  292. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_metrics_prometheus_cache.py +0 -0
  293. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_models_passthrough.py +0 -0
  294. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_openai_compat.py +0 -0
  295. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_openrouter_roster_diff.py +0 -0
  296. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_output_filters.py +0 -0
  297. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_output_filters_adapters.py +0 -0
  298. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_packaging.py +0 -0
  299. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_partial_stitch.py +0 -0
  300. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_plugin_adapter.py +0 -0
  301. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_plugins_integration.py +0 -0
  302. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_plugins_loader.py +0 -0
  303. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_plugins_registry.py +0 -0
  304. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_reasoning_strip.py +0 -0
  305. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_repair_byte_fallback.py +0 -0
  306. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_request_log.py +0 -0
  307. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_role_normalization.py +0 -0
  308. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_rollback.py +0 -0
  309. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_routing_adaptive.py +0 -0
  310. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_secret_redaction.py +0 -0
  311. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_self_healing.py +0 -0
  312. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_setup_sh.py +0 -0
  313. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_state_store.py +0 -0
  314. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_stop_reason_forward_compat.py +0 -0
  315. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_stream_truncation.py +0 -0
  316. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_token_estimation.py +0 -0
  317. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_token_estimation_accurate.py +0 -0
  318. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_tokens_saved_metric.py +0 -0
  319. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_tool_repair.py +0 -0
  320. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_tool_repair_differential.py +0 -0
  321. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_tool_repair_lenient.py +0 -0
  322. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_tool_repair_r4.py +0 -0
  323. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_tool_repair_scanners.py +0 -0
  324. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_tool_search.py +0 -0
  325. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_toolrepair_bench.py +0 -0
  326. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_translation_anthropic.py +0 -0
  327. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_translation_reverse.py +0 -0
  328. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_ttft_timeout.py +0 -0
  329. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_ui_auth.py +0 -0
  330. {coderouter_cli-2.17.0 → coderouter_cli-2.19.0}/tests/test_vscode_init.py +0 -0
@@ -9,6 +9,110 @@ are kept verbatim where the Japanese text itself is the subject).
9
9
 
10
10
  ---
11
11
 
12
+ ## [v2.19.0] — 2026-10-24 (OpenAI Responses API for the Codex CLI)
13
+
14
+ ### Added
15
+
16
+ - **`POST /v1/responses`** — the OpenAI Responses API, so the current Codex
17
+ CLI (Responses-only since 2026-02) can use CodeRouter as a custom
18
+ provider (`wire_api = "responses"`, `base_url = http://127.0.0.1:8088/v1`;
19
+ see `docs/start/quickstart.md` Pattern B). The request is translated to an
20
+ Anthropic Messages request and runs through the same fallback engine as
21
+ `/v1/messages`, so fallback, tool-call repair, the guards, the TTFT
22
+ cut-off and the chain-failure error mapping all apply; the result is
23
+ translated back (`coderouter/translation/responses.py`). Built against
24
+ the wire contract in openai/codex `970111f` (2026-10-23):
25
+ - `developer` / `system` messages (Codex sends its system prompt as the
26
+ first `developer` input item, not `instructions`) become Anthropic
27
+ `system` text; `instructions` is honoured for other clients.
28
+ - Tools: `function` → `function_call` with a JSON-string `arguments`;
29
+ `custom` grammar tools such as `apply_patch` → `custom_tool_call` with
30
+ the raw `input` string (Codex rejects a `function_call` for those; the
31
+ grammar is passed to the model in the tool description); `namespace`
32
+ (MCP) tools are flattened per request and answered with `namespace` +
33
+ the inner `name`. Hosted tools (`web_search`, …) are dropped.
34
+ - History: `function_call` / `custom_tool_call` and their outputs become
35
+ `tool_use` / `tool_result`; orphan outputs are dropped and calls with no
36
+ output get a synthetic `"aborted"` result so the Anthropic pairing rules
37
+ hold. `reasoning` and hosted-tool items are dropped.
38
+ - Stream: `response.created` → per item `output_item.added` (text deltas
39
+ only inside an open item) → `output_item.done` → `response.completed`
40
+ with `response.id` and complete usage details (`cached_tokens`,
41
+ `reasoning_tokens`). `max_tokens` stops become `response.incomplete`
42
+ (`max_output_tokens`).
43
+ - Errors: pre-content failures get an OpenAI-style error body with a real
44
+ status (400 / 429 with `Retry-After`, which Codex needs to retry a 429 /
45
+ 502). A context overflow on a streaming request — upstream overflow or
46
+ `context_budget_action: reject` — becomes `response.failed` with code
47
+ `context_length_exceeded`, the only overflow signal Codex recognizes. A
48
+ failure after the stream started is `response.failed` (`server_error`),
49
+ which Codex retries.
50
+ - Profile selection as on the other routes (body `profile` >
51
+ `X-CodeRouter-Profile` > `X-CodeRouter-Mode` > auto router > default);
52
+ Codex's `session-id` header feeds llama-server slot affinity.
53
+ - Non-streaming JSON responses are supported for other clients.
54
+ - Tool outputs that carry images (Codex `view_image`, MCP image results)
55
+ become image blocks, not base64 text. Usage reports OpenAI semantics —
56
+ `input_tokens` includes cache reads and writes — so Codex's
57
+ context-window accounting (and its auto-compaction) sees the real
58
+ prompt size. A stream that ends without `message_stop`, or with a block
59
+ still open, is reported as `response.failed` (retryable) rather than a
60
+ `response.completed` that would silently drop the partial item.
61
+ Flattened tool names are capped at 64 characters (hash suffix) for
62
+ strict OpenAI-compatible backends, and a custom-tool call whose
63
+ arguments hold a single string under another key still reaches
64
+ `apply_patch` as raw text.
65
+
66
+ ### Changed
67
+
68
+ - Docs: quickstart Pattern B (ja/en) now configures Codex through
69
+ CodeRouter; README and the "do I need CodeRouter?" guide updated.
70
+
71
+ ### Known limits
72
+
73
+ - Reasoning items are not produced or round-tripped; hosted tools are not
74
+ emulated; `previous_response_id` (server-side conversation state) is not
75
+ supported — Codex does not use it on HTTP.
76
+
77
+ ---
78
+
79
+ ## [v2.18.0] — 2026-10-24 (route on Claude Code's own request hints)
80
+
81
+ ### Added
82
+
83
+ - **auto_router matchers on Claude Code's gateway hint headers.** With
84
+ `CLAUDE_CODE_GATEWAY_HINT_HEADERS=1` (Claude Code 2.1.273+), every request
85
+ says what it is. Three new `RuleMatcher` fields read those headers:
86
+ - `request_class` — `x-claude-code-request-class` (`main` / `subagent` /
87
+ `workflow` / `compaction` / `auxiliary`), case-insensitive;
88
+ - `agent_type` — `x-claude-code-agent-type` (e.g. `Explore`),
89
+ case-insensitive;
90
+ - `compaction: true` — `x-claude-code-compaction` is truthy (`false` is
91
+ rejected at load, like the other boolean matchers).
92
+ Typical use: auto-mode classifier / title calls (`auxiliary`) to the
93
+ smallest local model, compaction to a long-context profile, `Explore`
94
+ sub-agents to a fast one. Without the headers these matchers never match,
95
+ so existing rule sets behave exactly as before. `classify()` gained an
96
+ optional `hints` argument; both `/v1/messages` and `/v1/chat/completions`
97
+ pass the headers through. Docs: `docs/guides/subagent-routing.md` / `.en.md`.
98
+ - **`slot_affinity_slots` (provider; llama.cpp only).** For
99
+ `llama-server --parallel N`: requests carrying a conversation key
100
+ (`x-claude-code-session-id`) get `id_slot = sha256(key) % N`, so every
101
+ turn of a conversation reuses the same slot's prompt cache instead of
102
+ re-prefilling on whichever slot is free. Stable across restarts; an
103
+ explicit `id_slot` in `extra_body` wins; off by default. Works on both the
104
+ native (`kind: anthropic`) and translated (`kind: openai_compat`) paths,
105
+ and survives every internal request rebuild (thinking strip for backends
106
+ without thinking, `tool_choice` emulation, `cache_control` strip,
107
+ OpenAI→Anthropic translation). The main conversation and its compaction
108
+ share a key; sub-agents and auxiliary calls get `<session>:<class>:<agent>`
109
+ so they do not queue on — or evict — the main conversation's slot.
110
+ Docs: `docs/backends/llamacpp-direct.md` / `.en.md`.
111
+ - **`vscode-init` also writes `CLAUDE_CODE_GATEWAY_HINT_HEADERS=1`**, and
112
+ `doctor --check-claude-code` reports (as info) when it is missing.
113
+
114
+ ---
115
+
12
116
  ## [v2.17.0] — 2026-10-24 (time-to-first-token cut-off, retry signals)
13
117
 
14
118
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: coderouter-cli
3
- Version: 2.17.0
3
+ Version: 2.19.0
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
@@ -66,7 +66,7 @@ Description-Content-Type: text/markdown
66
66
  ## 何ができるか — 30 秒で
67
67
 
68
68
  ```
69
- あなたのエージェント (Claude Code / agy ほか ※)
69
+ あなたのエージェント (Claude Code / codex / agy)
70
70
  │
71
71
  ▼
72
72
  ┌─ CodeRouter ─┐
@@ -76,8 +76,6 @@ Description-Content-Type: text/markdown
76
76
  └──────────────┘
77
77
  ```
78
78
 
79
- ※ 現行の codex CLI は Responses API(`/v1/responses`)専用になったため、CodeRouter 経由ではまだ使えません(対応予定)。直結の代替手順 → [quickstart Pattern B](./docs/start/quickstart.md#pattern-b-codex-cli-で使う)
80
-
81
79
  **やってくれること:**
82
80
 
83
81
  - ローカルモデルが壊した tool calling を Claude Code に届く前に修復する
@@ -147,7 +145,7 @@ ANTHROPIC_BASE_URL=http://localhost:8088 ANTHROPIC_AUTH_TOKEN=dummy claude
147
145
  | Claude Code + ローカル Ollama で tool calling が壊れる | **必須** — tool 修復 (+ 必要なら wire 変換) |
148
146
  | Claude Code + ローカルで長時間回すと止まる | **必須級** — 6 系統ガード + self-healing |
149
147
  | Ollama v0.14+ / LM Studio にネイティブ直結で動いてる | **便利** — 直結に無い fallback / ガード / 診断を追加 (passthrough で翻訳ゼロ) |
150
- | codex / agy + Ollama 直繋ぎで動いてる | オプション — フォールバックが欲しいなら(codex は `/v1/responses` 対応後) |
148
+ | codex / agy + Ollama 直繋ぎで動いてる | オプション — フォールバックが欲しいなら(codex は v2.19.0 の `/v1/responses` 経由) |
151
149
  | Claude API を直接叩いてて問題ない | 不要 |
152
150
 
153
151
  詳細は → [要否判定ガイド](./docs/start/when-do-i-need-coderouter.md)
@@ -21,7 +21,7 @@
21
21
  ## What it does — in 30 seconds
22
22
 
23
23
  ```
24
- Your agent (Claude Code / agy, etc. *)
24
+ Your agent (Claude Code / codex / agy)
25
25
  │
26
26
  ▼
27
27
  ┌─ CodeRouter ──┐
@@ -31,7 +31,6 @@ Your agent (Claude Code / agy, etc. *)
31
31
  └────────────────┘
32
32
  ```
33
33
 
34
- \* Current codex CLI speaks only the Responses API (`/v1/responses`), so it cannot go through CodeRouter yet (planned). Direct-connect workaround → [quickstart Pattern B](./docs/start/quickstart.en.md#pattern-b-use-it-with-the-codex-cli)
35
34
 
36
35
  **What it does for you:**
37
36
 
@@ -83,7 +82,7 @@ That's it. Claude Code works as usual, but your local Ollama is answering behind
83
82
  |---|---|
84
83
  | Claude Code + local Ollama, tool calling breaks | **Yes** — wire translation + tool repair |
85
84
  | Claude Code + local, dies after long sessions | **Helpful** — 6 guards + self-healing |
86
- | codex / agy + Ollama works fine | Optional — if you want fallback (codex: once `/v1/responses` lands) |
85
+ | codex / agy + Ollama works fine | Optional — if you want fallback (codex: via `/v1/responses`, v2.19.0+) |
87
86
  | Using Claude API directly, no issues | Not needed |
88
87
 
89
88
  Full decision matrix → [Do I need CodeRouter?](./docs/start/when-do-i-need-coderouter.en.md)
@@ -21,7 +21,7 @@
21
21
  ## 何ができるか — 30 秒で
22
22
 
23
23
  ```
24
- あなたのエージェント (Claude Code / agy ほか ※)
24
+ あなたのエージェント (Claude Code / codex / agy)
25
25
  │
26
26
  ▼
27
27
  ┌─ CodeRouter ─┐
@@ -31,8 +31,6 @@
31
31
  └──────────────┘
32
32
  ```
33
33
 
34
- ※ 現行の codex CLI は Responses API(`/v1/responses`)専用になったため、CodeRouter 経由ではまだ使えません(対応予定)。直結の代替手順 → [quickstart Pattern B](./docs/start/quickstart.md#pattern-b-codex-cli-で使う)
35
-
36
34
  **やってくれること:**
37
35
 
38
36
  - ローカルモデルが壊した tool calling を Claude Code に届く前に修復する
@@ -102,7 +100,7 @@ ANTHROPIC_BASE_URL=http://localhost:8088 ANTHROPIC_AUTH_TOKEN=dummy claude
102
100
  | Claude Code + ローカル Ollama で tool calling が壊れる | **必須** — tool 修復 (+ 必要なら wire 変換) |
103
101
  | Claude Code + ローカルで長時間回すと止まる | **必須級** — 6 系統ガード + self-healing |
104
102
  | Ollama v0.14+ / LM Studio にネイティブ直結で動いてる | **便利** — 直結に無い fallback / ガード / 診断を追加 (passthrough で翻訳ゼロ) |
105
- | codex / agy + Ollama 直繋ぎで動いてる | オプション — フォールバックが欲しいなら(codex は `/v1/responses` 対応後) |
103
+ | codex / agy + Ollama 直繋ぎで動いてる | オプション — フォールバックが欲しいなら(codex は v2.19.0 の `/v1/responses` 経由) |
106
104
  | Claude API を直接叩いてて問題ない | 不要 |
107
105
 
108
106
  詳細は → [要否判定ガイド](./docs/start/when-do-i-need-coderouter.md)
@@ -46,6 +46,7 @@ from coderouter.adapters.base import (
46
46
  StreamChunk,
47
47
  StreamTruncatedError,
48
48
  )
49
+ from coderouter.adapters.slot_affinity import apply_slot_affinity
49
50
  from coderouter.credentials import resolve_provider_credential
50
51
  from coderouter.logging import (
51
52
  get_logger,
@@ -243,6 +244,9 @@ class AnthropicAdapter(BaseAdapter):
243
244
  body.update(dumped)
244
245
  body["model"] = self.config.model
245
246
  body["stream"] = stream
247
+ apply_slot_affinity(
248
+ body, slots=self.config.slot_affinity_slots, key=req.session_key
249
+ )
246
250
  return body
247
251
 
248
252
  # ------------------------------------------------------------------
@@ -65,6 +65,9 @@ class ChatRequest(BaseModel):
65
65
 
66
66
  # CodeRouter-specific extension (not sent upstream)
67
67
  profile: str | None = Field(default=None, exclude=True)
68
+ # v2.18.0: conversation key for KV-slot affinity (see
69
+ # ``ProviderConfig.slot_affinity_slots``). Never serialized.
70
+ session_key: str | None = Field(default=None, exclude=True)
68
71
 
69
72
 
70
73
  class ChatResponse(BaseModel):
@@ -30,6 +30,7 @@ from coderouter.adapters.base import (
30
30
  StreamChunk,
31
31
  StreamTruncatedError,
32
32
  )
33
+ from coderouter.adapters.slot_affinity import apply_slot_affinity
33
34
  from coderouter.credentials import resolve_provider_credential
34
35
  from coderouter.logging import (
35
36
  get_logger,
@@ -182,6 +183,11 @@ class OpenAICompatAdapter(BaseAdapter):
182
183
  value = getattr(request, field, None)
183
184
  if value is not None:
184
185
  body[field] = value
186
+ apply_slot_affinity(
187
+ body,
188
+ slots=self.config.slot_affinity_slots,
189
+ key=getattr(request, "session_key", None),
190
+ )
185
191
  if stream:
186
192
  # Request a terminal usage chunk. Providers that honor this
187
193
  # (OpenAI, OpenRouter, Ollama >=0.x) will send one extra chunk
@@ -0,0 +1,54 @@
1
+ """v2.18.0: KV-slot affinity for llama-server (``id_slot``).
2
+
3
+ llama-server started with ``--parallel N`` serves N slots, each holding its
4
+ own prompt cache. Without a hint it picks a free slot, so consecutive turns
5
+ of one conversation can land on different slots and re-prefill the whole
6
+ prompt. Sending ``id_slot`` pins a conversation to one slot.
7
+
8
+ The slot is ``sha256(key) % N`` — stable across processes and restarts
9
+ (Python's ``hash`` is salted per process).
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import hashlib
15
+ from collections.abc import Mapping
16
+ from typing import Any
17
+
18
+ # Request classes whose prompt shares the main conversation's prefix: they
19
+ # belong on the main conversation's slot. Everything else (sub-agents,
20
+ # auxiliary calls such as the auto-mode classifier or titles, workflows) has
21
+ # its own prompt and gets its own key, so it neither waits on the main slot
22
+ # nor evicts its cache.
23
+ _MAIN_CLASSES = frozenset({"", "main", "compaction"})
24
+
25
+
26
+ def affinity_key(hints: Mapping[str, str]) -> str | None:
27
+ """Conversation key for slot affinity, from Claude Code's hint headers.
28
+
29
+ ``None`` when there is no session id. ``main`` / ``compaction`` (and a
30
+ missing class) share ``<session>``; other classes get
31
+ ``<session>:<class>:<agent_type>``.
32
+ """
33
+ session = hints.get("session_id")
34
+ if not session:
35
+ return None
36
+ request_class = hints.get("request_class", "").lower()
37
+ if request_class in _MAIN_CLASSES:
38
+ return session
39
+ return f"{session}:{request_class}:{hints.get('agent_type', '').lower()}"
40
+
41
+
42
+ def slot_for(key: str, slots: int) -> int:
43
+ digest = hashlib.sha256(key.encode("utf-8")).digest()
44
+ return int.from_bytes(digest[:8], "big") % slots
45
+
46
+
47
+ def apply_slot_affinity(body: dict[str, Any], *, slots: int | None, key: str | None) -> None:
48
+ """Set ``body["id_slot"]`` when affinity is configured and a key exists.
49
+
50
+ An ``id_slot`` already present (e.g. from ``extra_body``) wins.
51
+ """
52
+ if not slots or not key or "id_slot" in body:
53
+ return
54
+ body["id_slot"] = slot_for(key, slots)
@@ -483,7 +483,8 @@ def _build_parser() -> argparse.ArgumentParser:
483
483
  help=(
484
484
  "v2.16.0: do not write the Claude Code gateway settings "
485
485
  "(ENABLE_TOOL_SEARCH=false, CLAUDE_CODE_AUTO_MODE_SERVER=0, "
486
- "and --max-context-tokens). Use when the chain is "
486
+ "CLAUDE_CODE_GATEWAY_HINT_HEADERS=1 and --max-context-tokens). "
487
+ "Use when the chain is "
487
488
  "api.anthropic.com only."
488
489
  ),
489
490
  )
@@ -562,6 +562,23 @@ class ProviderConfig(BaseModel):
562
562
  # withholds those opening events from the client. ``None`` (default)
563
563
  # disables it. Typical use: a local llama-server still loading a model
564
564
  # or chewing through a long prompt while a cloud fallback could answer.
565
+ # v2.18.0: KV-slot affinity for llama-server started with
566
+ # ``--parallel N``. When set to N and the request carries a conversation
567
+ # key (Claude Code's ``x-claude-code-session-id`` hint header), the body
568
+ # gets ``id_slot = stable_hash(key) % N`` so every turn of a conversation
569
+ # lands on the same slot and reuses its prompt cache instead of
570
+ # re-prefilling on whichever slot is free. llama.cpp only (other servers
571
+ # ignore or reject ``id_slot``); ``None`` (default) sends nothing.
572
+ slot_affinity_slots: int | None = Field(
573
+ default=None,
574
+ ge=1,
575
+ le=256,
576
+ description=(
577
+ "v2.18.0: llama-server --parallel N. Pins each conversation to "
578
+ "slot hash(session) % N via id_slot so its KV cache is reused. "
579
+ "llama.cpp only. None disables."
580
+ ),
581
+ )
565
582
  ttft_timeout_s: float | None = Field(
566
583
  default=None,
567
584
  gt=0.0,
@@ -1639,6 +1656,21 @@ class RuleMatcher(BaseModel):
1639
1656
  # declares any tools); ``False`` is rejected by ``_exactly_one``
1640
1657
  # since a "no-tools" rule would shadow the default fall-through.
1641
1658
  has_tools: bool | None = None
1659
+ # v2.18.0: Claude Code gateway hint headers. Claude Code 2.1.273+ sends
1660
+ # these to a custom ANTHROPIC_BASE_URL when
1661
+ # ``CLAUDE_CODE_GATEWAY_HINT_HEADERS=1`` is set (``coderouter
1662
+ # vscode-init`` sets it). They say what a request *is* — something the
1663
+ # body heuristics above can only guess:
1664
+ # * ``request_class`` — ``x-claude-code-request-class``: ``main`` /
1665
+ # ``subagent`` / ``workflow`` / ``compaction`` / ``auxiliary``
1666
+ # (auto-mode classifier, titles, …). Case-insensitive exact match.
1667
+ # * ``agent_type`` — ``x-claude-code-agent-type`` (e.g. ``Explore``),
1668
+ # case-insensitive exact match.
1669
+ # * ``compaction: True`` — ``x-claude-code-compaction`` is truthy.
1670
+ # Without the headers these matchers simply never match.
1671
+ request_class: str | None = None
1672
+ agent_type: str | None = None
1673
+ compaction: bool | None = None
1642
1674
 
1643
1675
  _MATCHER_FIELDS: tuple[str, ...] = (
1644
1676
  "has_image",
@@ -1649,12 +1681,15 @@ class RuleMatcher(BaseModel):
1649
1681
  "content_token_count_min",
1650
1682
  "has_tools",
1651
1683
  "cjk_ratio_min",
1684
+ "request_class",
1685
+ "agent_type",
1686
+ "compaction",
1652
1687
  )
1653
1688
 
1654
1689
  # Boolean matcher fields carry meaning only at ``True`` — the runtime
1655
1690
  # evaluator uses ``is True`` — so a ``False`` value is a dead rule that
1656
1691
  # never matches. ``_exactly_one`` rejects it explicitly (see below).
1657
- _BOOL_MATCHER_FIELDS: tuple[str, ...] = ("has_image", "has_tools")
1692
+ _BOOL_MATCHER_FIELDS: tuple[str, ...] = ("has_image", "has_tools", "compaction")
1658
1693
 
1659
1694
  @model_validator(mode="after")
1660
1695
  def _exactly_one(self) -> Self:
@@ -125,6 +125,18 @@ def check(version: Version | None, env: Mapping[str, str]) -> list[ClaudeCodeFin
125
125
  )
126
126
  )
127
127
 
128
+ if env.get("CLAUDE_CODE_GATEWAY_HINT_HEADERS", "").lower() in ("1", "true"):
129
+ out.append(ClaudeCodeFinding("ok", "CLAUDE_CODE_GATEWAY_HINT_HEADERS=1"))
130
+ else:
131
+ out.append(
132
+ ClaudeCodeFinding(
133
+ "info",
134
+ "CLAUDE_CODE_GATEWAY_HINT_HEADERS is not set: auto_router rules "
135
+ "on request_class / agent_type / compaction (v2.18.0) never "
136
+ "match without it.",
137
+ )
138
+ )
139
+
128
140
  if env.get("CLAUDE_CODE_AUTO_MODE_SERVER") == "0":
129
141
  out.append(ClaudeCodeFinding("ok", "CLAUDE_CODE_AUTO_MODE_SERVER=0"))
130
142
  else:
@@ -31,6 +31,7 @@ from fastapi import APIRouter, Header, HTTPException, Request
31
31
  from fastapi.responses import JSONResponse, Response, StreamingResponse
32
32
 
33
33
  from coderouter.adapters.base import StreamTruncatedError
34
+ from coderouter.adapters.slot_affinity import affinity_key
34
35
  from coderouter.guards.context_budget import ContextBudgetRejectError
35
36
  from coderouter.guards.tool_loop import ToolCountExceededError, ToolLoopBreakError
36
37
  from coderouter.ingress.anthropic_errors import (
@@ -49,7 +50,7 @@ from coderouter.routing import (
49
50
  MidStreamError,
50
51
  NoProvidersAvailableError,
51
52
  )
52
- from coderouter.routing.auto_router import RESERVED_PROFILE_NAME, classify
53
+ from coderouter.routing.auto_router import RESERVED_PROFILE_NAME, classify, extract_gateway_hints
53
54
  from coderouter.routing.fallback_trace import (
54
55
  SSE_FALLBACK_EVENT,
55
56
  current_fallback_trace,
@@ -226,6 +227,11 @@ async def messages(
226
227
  if anthropic_beta:
227
228
  anth_req.anthropic_beta = anthropic_beta
228
229
 
230
+ # v2.18.0: Claude Code gateway hint headers — routing matchers below,
231
+ # and the conversation key for llama-server KV-slot affinity.
232
+ gateway_hints = extract_gateway_hints(request.headers)
233
+ anth_req.session_key = affinity_key(gateway_hints)
234
+
229
235
  # Profile selection — body field wins over header (same policy as OpenAI route).
230
236
  if anth_req.profile is None and x_coderouter_profile:
231
237
  anth_req.profile = x_coderouter_profile
@@ -253,7 +259,7 @@ async def messages(
253
259
  # AnthropicRequest), so both OpenAI and Anthropic ingress use the same
254
260
  # classifier without a shared request shim.
255
261
  if anth_req.profile is None and config.default_profile == RESERVED_PROFILE_NAME:
256
- anth_req.profile = classify(payload, config)
262
+ anth_req.profile = classify(payload, config, gateway_hints)
257
263
 
258
264
  if anth_req.profile is not None:
259
265
  try:
@@ -19,6 +19,7 @@ from coderouter.ingress.dashboard_routes import router as dashboard_router
19
19
  from coderouter.ingress.launcher_routes import router as launcher_router
20
20
  from coderouter.ingress.metrics_routes import router as metrics_router
21
21
  from coderouter.ingress.openai_routes import router as openai_router
22
+ from coderouter.ingress.responses_routes import router as responses_router
22
23
  from coderouter.logging import configure_logging, get_logger
23
24
  from coderouter.metrics import install_collector
24
25
  from coderouter.plugins import discover_and_load
@@ -491,6 +492,8 @@ def create_app(config_path: str | None = None) -> FastAPI:
491
492
 
492
493
  app.include_router(openai_router, prefix="/v1", tags=["openai-compat"])
493
494
  app.include_router(anthropic_router, prefix="/v1", tags=["anthropic-compat"])
495
+ # v2.19.0: OpenAI Responses API (Codex CLI).
496
+ app.include_router(responses_router, prefix="/v1", tags=["openai-responses"])
494
497
  # v1.5-A: /metrics.json sits at the root (no /v1 prefix) — metrics are not
495
498
  # part of the OpenAI / Anthropic API surface, and Prometheus-style
496
499
  # endpoints conventionally live at the root in v1.5-B.
@@ -32,9 +32,10 @@ from fastapi import APIRouter, Header, HTTPException, Request
32
32
  from fastapi.responses import JSONResponse, StreamingResponse
33
33
 
34
34
  from coderouter.adapters.base import ChatRequest
35
+ from coderouter.adapters.slot_affinity import affinity_key
35
36
  from coderouter.logging import get_logger
36
37
  from coderouter.routing import FallbackEngine, NoProvidersAvailableError
37
- from coderouter.routing.auto_router import RESERVED_PROFILE_NAME, classify
38
+ from coderouter.routing.auto_router import RESERVED_PROFILE_NAME, classify, extract_gateway_hints
38
39
  from coderouter.routing.fallback_trace import current_fallback_trace
39
40
 
40
41
  router = APIRouter()
@@ -199,6 +200,10 @@ async def chat_completions(
199
200
  except Exception as exc: # pydantic.ValidationError, etc.
200
201
  raise HTTPException(status_code=422, detail=str(exc)) from exc
201
202
 
203
+ # v2.18.0: gateway hint headers (routing matchers + KV-slot affinity key).
204
+ gateway_hints = extract_gateway_hints(request.headers)
205
+ chat_req.session_key = affinity_key(gateway_hints)
206
+
202
207
  # Header-based override (body wins if both are set — see module docstring)
203
208
  if chat_req.profile is None and x_coderouter_profile:
204
209
  chat_req.profile = x_coderouter_profile
@@ -226,7 +231,7 @@ async def chat_completions(
226
231
  # When inactive, the engine still falls through to
227
232
  # ``config.default_profile`` on its own — same semantics as pre-v1.6.
228
233
  if chat_req.profile is None and config.default_profile == RESERVED_PROFILE_NAME:
229
- chat_req.profile = classify(payload, config)
234
+ chat_req.profile = classify(payload, config, gateway_hints)
230
235
 
231
236
  # Validate profile exists before we kick off any upstream call
232
237
  if chat_req.profile is not None: