coderouter-cli 2.7.10__tar.gz → 2.8.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 (266) hide show
  1. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/CHANGELOG.md +47 -0
  2. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/PKG-INFO +1 -1
  3. coderouter_cli-2.8.0/coderouter/adapters/registry.py +60 -0
  4. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/config/schemas.py +12 -2
  5. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/plugins/base.py +54 -26
  6. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/plugins/loader.py +8 -5
  7. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/plugins/registry.py +13 -2
  8. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/routing/fallback.py +7 -3
  9. coderouter_cli-2.8.0/docs/designs/agent-cli-plugin-extraction.md +410 -0
  10. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/designs/external-agents-adapter.md +4 -0
  11. coderouter_cli-2.8.0/docs/designs/orchestration-companion.md +109 -0
  12. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/pyproject.toml +1 -1
  13. coderouter_cli-2.8.0/tests/test_plugin_adapter.py +404 -0
  14. coderouter_cli-2.7.10/coderouter/adapters/registry.py +0 -23
  15. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/.gitignore +0 -0
  16. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/LICENSE +0 -0
  17. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/README.en.md +0 -0
  18. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/README.md +0 -0
  19. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/__init__.py +0 -0
  20. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/__main__.py +0 -0
  21. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/adapters/__init__.py +0 -0
  22. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/adapters/agent_cli.py +0 -0
  23. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/adapters/anthropic_native.py +0 -0
  24. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/adapters/base.py +0 -0
  25. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/adapters/openai_compat.py +0 -0
  26. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/cli.py +0 -0
  27. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/cli_stats.py +0 -0
  28. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/config/__init__.py +0 -0
  29. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/config/capability_registry.py +0 -0
  30. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/config/env_file.py +0 -0
  31. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/config/loader.py +0 -0
  32. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/cost.py +0 -0
  33. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/data/__init__.py +0 -0
  34. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/data/model-capabilities.yaml +0 -0
  35. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/doctor.py +0 -0
  36. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/doctor_apply.py +0 -0
  37. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/env_security.py +0 -0
  38. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/errors.py +0 -0
  39. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/gguf_introspect.py +0 -0
  40. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/guards/__init__.py +0 -0
  41. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/guards/_fingerprint.py +0 -0
  42. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/guards/backend_health.py +0 -0
  43. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/guards/context_budget.py +0 -0
  44. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/guards/continuous_probe.py +0 -0
  45. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/guards/drift_actions.py +0 -0
  46. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/guards/drift_detection.py +0 -0
  47. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/guards/memory_budget.py +0 -0
  48. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/guards/memory_pressure.py +0 -0
  49. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/guards/self_healing.py +0 -0
  50. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/guards/tool_loop.py +0 -0
  51. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/hardware.py +0 -0
  52. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/ingress/__init__.py +0 -0
  53. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/ingress/anthropic_routes.py +0 -0
  54. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/ingress/app.py +0 -0
  55. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/ingress/dashboard_routes.py +0 -0
  56. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/ingress/launcher_routes.py +0 -0
  57. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/ingress/metrics_routes.py +0 -0
  58. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/ingress/openai_routes.py +0 -0
  59. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/language_tax.py +0 -0
  60. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/launcher_speculative.py +0 -0
  61. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/logging.py +0 -0
  62. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/metrics/__init__.py +0 -0
  63. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/metrics/collector.py +0 -0
  64. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/metrics/prometheus.py +0 -0
  65. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/output_filters.py +0 -0
  66. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/plugins/__init__.py +0 -0
  67. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/routing/__init__.py +0 -0
  68. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/routing/adaptive.py +0 -0
  69. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/routing/auto_router.py +0 -0
  70. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/routing/budget.py +0 -0
  71. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/routing/capability.py +0 -0
  72. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/state/__init__.py +0 -0
  73. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/state/audit_log.py +0 -0
  74. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/state/replay.py +0 -0
  75. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/state/request_log.py +0 -0
  76. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/state/store.py +0 -0
  77. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/state/suggest_rules.py +0 -0
  78. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/token_estimation.py +0 -0
  79. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/token_estimation_accurate.py +0 -0
  80. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/translation/__init__.py +0 -0
  81. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/translation/anthropic.py +0 -0
  82. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/translation/convert.py +0 -0
  83. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/coderouter/translation/tool_repair.py +0 -0
  84. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/README.en.md +0 -0
  85. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/README.md +0 -0
  86. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/assets/dashboard-demo.png +0 -0
  87. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/backends/claude-code-llamacpp-vllm.en.md +0 -0
  88. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/backends/claude-code-llamacpp-vllm.md +0 -0
  89. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/backends/external-agents.en.md +0 -0
  90. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/backends/external-agents.md +0 -0
  91. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/backends/gguf_dl.en.md +0 -0
  92. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/backends/gguf_dl.md +0 -0
  93. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/backends/hf-ollama-models.en.md +0 -0
  94. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/backends/hf-ollama-models.md +0 -0
  95. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/backends/install-backends.en.md +0 -0
  96. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/backends/install-backends.md +0 -0
  97. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/backends/launcher-quickstart.en.md +0 -0
  98. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/backends/launcher-quickstart.md +0 -0
  99. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/backends/launcher.en.md +0 -0
  100. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/backends/launcher.md +0 -0
  101. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/backends/llamacpp-direct.en.md +0 -0
  102. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/backends/llamacpp-direct.md +0 -0
  103. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/backends/lmstudio-direct.en.md +0 -0
  104. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/backends/lmstudio-direct.md +0 -0
  105. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/backends/verify-ollama-0.23.1.md +0 -0
  106. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/concepts/architecture.en.md +0 -0
  107. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/concepts/architecture.md +0 -0
  108. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/concepts/context-budget.en.md +0 -0
  109. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/concepts/context-budget.md +0 -0
  110. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/concepts/continuous-probing.en.md +0 -0
  111. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/concepts/continuous-probing.md +0 -0
  112. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/concepts/drift-detection.en.md +0 -0
  113. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/concepts/drift-detection.md +0 -0
  114. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/concepts/partial-stitch.en.md +0 -0
  115. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/concepts/partial-stitch.md +0 -0
  116. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/designs/v1.5-dashboard-mockup.html +0 -0
  117. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/designs/v1.6-auto-router-verification.md +0 -0
  118. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/designs/v1.6-auto-router.md +0 -0
  119. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/guides/free-tier-guide.en.md +0 -0
  120. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/guides/free-tier-guide.md +0 -0
  121. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/guides/language-tax.en.md +0 -0
  122. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/guides/language-tax.md +0 -0
  123. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/guides/remote-access.en.md +0 -0
  124. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/guides/remote-access.md +0 -0
  125. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/guides/security.en.md +0 -0
  126. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/guides/security.md +0 -0
  127. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/guides/troubleshooting.en.md +0 -0
  128. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/guides/troubleshooting.md +0 -0
  129. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/guides/usage-guide.en.md +0 -0
  130. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/guides/usage-guide.md +0 -0
  131. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/low-memory-integration.en.md +0 -0
  132. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/low-memory-integration.md +0 -0
  133. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/openrouter-roster/CHANGES.md +0 -0
  134. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/openrouter-roster/README.md +0 -0
  135. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/openrouter-roster/latest.json +0 -0
  136. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/retrospectives/v0.4.md +0 -0
  137. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/retrospectives/v0.5-verify.md +0 -0
  138. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/retrospectives/v0.5.md +0 -0
  139. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/retrospectives/v0.6.md +0 -0
  140. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/retrospectives/v0.7.md +0 -0
  141. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/retrospectives/v1.0-verify.md +0 -0
  142. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/retrospectives/v1.0.md +0 -0
  143. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/start/quickstart.en.md +0 -0
  144. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/start/quickstart.md +0 -0
  145. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/start/when-do-i-need-coderouter.en.md +0 -0
  146. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/docs/start/when-do-i-need-coderouter.md +0 -0
  147. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/examples/.env.example +0 -0
  148. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/examples/README.md +0 -0
  149. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/examples/providers-agent-cli.yaml +0 -0
  150. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/examples/providers-multiagent.yaml +0 -0
  151. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/examples/providers.context-budget-test.yaml +0 -0
  152. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/examples/providers.llamacpp-vllm.yaml +0 -0
  153. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/examples/providers.nvidia-nim.yaml +0 -0
  154. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/examples/providers.ollama-auto-custom.yaml +0 -0
  155. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/examples/providers.ollama-auto.yaml +0 -0
  156. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/examples/providers.ollama-free-chain.yaml +0 -0
  157. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/examples/providers.raspberrypi.yaml +0 -0
  158. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/examples/providers.yaml +0 -0
  159. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/scripts/demo_traffic.sh +0 -0
  160. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/scripts/openrouter_roster_diff.py +0 -0
  161. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/scripts/smoke_v2_2.sh +0 -0
  162. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/scripts/verify-providers.yaml +0 -0
  163. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/scripts/verify_ollama_0_23.py +0 -0
  164. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/scripts/verify_v0_5.sh +0 -0
  165. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/scripts/verify_v1_0.sh +0 -0
  166. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/__init__.py +0 -0
  167. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/conftest.py +0 -0
  168. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_adapter_anthropic.py +0 -0
  169. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_agent_cli.py +0 -0
  170. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_audit_log.py +0 -0
  171. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_auto_router.py +0 -0
  172. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_auto_router_cjk.py +0 -0
  173. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_backend_health.py +0 -0
  174. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_budget.py +0 -0
  175. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_capability.py +0 -0
  176. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_capability_degraded_payload.py +0 -0
  177. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_capability_registry.py +0 -0
  178. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_capability_registry_cache_control.py +0 -0
  179. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_capability_tool_choice.py +0 -0
  180. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_claude_code_suitability.py +0 -0
  181. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_cli.py +0 -0
  182. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_cli_bind_warning.py +0 -0
  183. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_cli_stats.py +0 -0
  184. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_config.py +0 -0
  185. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_config_shim_actions.py +0 -0
  186. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_context_budget.py +0 -0
  187. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_continuous_probe.py +0 -0
  188. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_dashboard_endpoint.py +0 -0
  189. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_doctor.py +0 -0
  190. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_doctor_apply.py +0 -0
  191. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_doctor_cache_probe.py +0 -0
  192. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_drift_actions.py +0 -0
  193. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_drift_detection.py +0 -0
  194. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_drift_detection_integration.py +0 -0
  195. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_env_file.py +0 -0
  196. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_env_security.py +0 -0
  197. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_errors.py +0 -0
  198. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_examples_yaml.py +0 -0
  199. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_fallback.py +0 -0
  200. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_fallback_anthropic.py +0 -0
  201. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_fallback_cache_control.py +0 -0
  202. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_fallback_cache_observed.py +0 -0
  203. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_fallback_cache_strip.py +0 -0
  204. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_fallback_empty_response.py +0 -0
  205. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_fallback_misconfig_warn.py +0 -0
  206. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_fallback_paid_gate.py +0 -0
  207. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_fallback_thinking.py +0 -0
  208. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_fallback_tool_choice_emulate.py +0 -0
  209. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_fix_h1_prometheus_drift.py +0 -0
  210. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_fix_h2_h6_translation.py +0 -0
  211. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_fix_h3_client_reuse.py +0 -0
  212. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_fix_h4_h5_guards.py +0 -0
  213. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_fix_h7_probe_restore.py +0 -0
  214. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_fix_h8_launcher_auth.py +0 -0
  215. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_fix_mA_routing.py +0 -0
  216. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_fix_mB_adapters.py +0 -0
  217. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_fix_mC_convert.py +0 -0
  218. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_fix_mD_logging_metrics.py +0 -0
  219. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_fix_mE_config_validation.py +0 -0
  220. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_fix_mF_ingress.py +0 -0
  221. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_gguf_introspect.py +0 -0
  222. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_guards_tool_loop.py +0 -0
  223. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_hardware.py +0 -0
  224. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_ingress_anthropic.py +0 -0
  225. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_ingress_count_tokens.py +0 -0
  226. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_ingress_profile.py +0 -0
  227. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_language_tax.py +0 -0
  228. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_language_tax_integration.py +0 -0
  229. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_launcher_mtp.py +0 -0
  230. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_launcher_mtp_fallback.py +0 -0
  231. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_launcher_provider_sync.py +0 -0
  232. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_memory_budget.py +0 -0
  233. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_memory_pressure.py +0 -0
  234. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_metrics_cache.py +0 -0
  235. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_metrics_collector.py +0 -0
  236. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_metrics_cost.py +0 -0
  237. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_metrics_endpoint.py +0 -0
  238. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_metrics_jsonl.py +0 -0
  239. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_metrics_prometheus.py +0 -0
  240. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_metrics_prometheus_cache.py +0 -0
  241. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_models_passthrough.py +0 -0
  242. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_openai_compat.py +0 -0
  243. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_openrouter_roster_diff.py +0 -0
  244. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_output_filters.py +0 -0
  245. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_output_filters_adapters.py +0 -0
  246. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_partial_stitch.py +0 -0
  247. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_plugins_integration.py +0 -0
  248. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_plugins_loader.py +0 -0
  249. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_plugins_registry.py +0 -0
  250. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_reasoning_strip.py +0 -0
  251. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_repair_byte_fallback.py +0 -0
  252. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_request_log.py +0 -0
  253. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_role_normalization.py +0 -0
  254. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_routing_adaptive.py +0 -0
  255. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_self_healing.py +0 -0
  256. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_setup_sh.py +0 -0
  257. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_state_store.py +0 -0
  258. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_token_estimation.py +0 -0
  259. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_token_estimation_accurate.py +0 -0
  260. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_tokens_saved_metric.py +0 -0
  261. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_tool_repair.py +0 -0
  262. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_tool_repair_lenient.py +0 -0
  263. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_tool_repair_r4.py +0 -0
  264. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_toolrepair_bench.py +0 -0
  265. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_translation_anthropic.py +0 -0
  266. {coderouter_cli-2.7.10 → coderouter_cli-2.8.0}/tests/test_translation_reverse.py +0 -0
@@ -9,6 +9,53 @@ are kept verbatim where the Japanese text itself is the subject).
9
9
 
10
10
  ---
11
11
 
12
+ ## [v2.8.0] — 2026-07-11 (Plugin SDK: Adapter hook wired — Phase 2a of the agent_cli extraction)
13
+
14
+ Opens the Plugin SDK's Adapter surface: the previously dead-end `Adapter`
15
+ Protocol (name-only) is now a real engine-integrated hook, so an external
16
+ plugin package can provide new `kind` values for providers.yaml without
17
+ touching Core. This is Phase 2a of the agent_cli plugin-extraction design
18
+ (`docs/designs/agent-cli-plugin-extraction.md`): hook wiring only — the
19
+ in-core `agent_cli` adapter is unchanged and keeps working exactly as in
20
+ v2.7.10; the actual move into `coderouter-plugin-agents` is Phase 2b/2c.
21
+
22
+ ### Added
23
+
24
+ - **`Adapter` plugin Protocol** (`coderouter/plugins/base.py`) — `kind: str`
25
+ plus synchronous `build(config: ProviderConfig) -> BaseAdapter`. A factory
26
+ shape (kind → adapter), unlike the per-request hooks: construction happens
27
+ once at startup and does no I/O. The `adapter` entry-point group
28
+ (`coderouter.adapter`, singular — matching the loader's group mechanics)
29
+ moved from the future list into the active groups; the existing two-stage
30
+ gate (installed + listed in `plugins.enabled`) applies as-is.
31
+ - **`build_adapter` plugin resolution** (`coderouter/adapters/registry.py`)
32
+ — resolution order is in-core kinds first (`openai_compat` / `anthropic` /
33
+ `agent_cli`; a plugin can never shadow them), then plugin-provided kinds,
34
+ then a `ValueError` listing every known kind plus an install/enable hint.
35
+ Both engine call sites (startup adapter cache + runtime
36
+ `register_provider`) pass the plugin registry.
37
+ - **Tests** (`tests/test_plugin_adapter.py`, new, 10) — plugin-kind
38
+ resolution, in-core shadowing prevention, unknown-kind error contents,
39
+ two-stage gate via the real entry-point loader path, runtime
40
+ `register_provider` with a plugin kind, and an E2E request through
41
+ `POST /v1/chat/completions` served by a plugin-provided adapter.
42
+
43
+ ### Changed
44
+
45
+ - **`ProviderConfig.kind`: `Literal[...]` → `str`** (`config/schemas.py`) —
46
+ plugin kinds cannot be known at config-load time (plugins are discovered
47
+ after the config is parsed), so the closed Literal had to open. Fail-fast
48
+ for a typo'd kind moves one step later but stays at startup: the engine
49
+ builds adapters for **all** providers eagerly in its constructor, so an
50
+ unknown kind still aborts `serve` at load with a message that now lists
51
+ in-core and plugin kinds (strictly more helpful than the old pydantic
52
+ error). Recorded as a design deviation in
53
+ `agent-cli-plugin-extraction.md` §8.1, including the residual limitation
54
+ that `doctor` (HTTP-probe based) does not surface typo'd kinds.
55
+ - Plugin-group bookkeeping: `adapter` no longer warns as
56
+ "plugin-group-not-yet-active"; `PluginRegistry` gained an `adapters`
57
+ view alongside `input_filters` / `observers`.
58
+
12
59
  ## [v2.7.10] — 2026-07-11 (agent_cli Phase 1c: antigravity — Phase 1 complete)
13
60
 
14
61
  Completes agent_cli Phase 1: `agent: antigravity` (the Google Antigravity
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: coderouter-cli
3
- Version: 2.7.10
3
+ Version: 2.8.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
@@ -0,0 +1,60 @@
1
+ """Adapter factory — maps `kind` strings to adapter classes."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING
6
+
7
+ from coderouter.adapters.anthropic_native import AnthropicAdapter
8
+ from coderouter.adapters.base import BaseAdapter
9
+ from coderouter.adapters.openai_compat import OpenAICompatAdapter
10
+ from coderouter.config.schemas import ProviderConfig
11
+
12
+ if TYPE_CHECKING:
13
+ from coderouter.plugins.registry import PluginRegistry
14
+
15
+ # in-core kinds, in resolution order. Kept as a tuple (not derived from
16
+ # the if-chain below) so the "Unknown adapter kind" error message and
17
+ # the plugin-shadow guard have a single source of truth.
18
+ _IN_CORE_KINDS: tuple[str, ...] = ("openai_compat", "anthropic", "agent_cli")
19
+
20
+
21
+ def _plugin_kinds(plugin_registry: PluginRegistry | None) -> list[str]:
22
+ """``kind`` values served by enabled adapter plugins, for error text."""
23
+ if plugin_registry is None:
24
+ return []
25
+ return [factory.kind for factory in plugin_registry.adapters]
26
+
27
+
28
+ def build_adapter(
29
+ provider: ProviderConfig,
30
+ plugin_registry: PluginRegistry | None = None,
31
+ ) -> BaseAdapter:
32
+ """Construct an adapter from a ProviderConfig.
33
+
34
+ Resolution order (docs/designs/agent-cli-plugin-extraction.md §3.2):
35
+ in-core kinds first, then plugin-provided kinds, then a fail-fast
36
+ error. In-core kinds are checked first so a plugin can never shadow
37
+ a kind Core itself guarantees (``openai_compat`` / ``anthropic`` /,
38
+ during the Phase 2b migration window, ``agent_cli``).
39
+ """
40
+ if provider.kind == "openai_compat":
41
+ return OpenAICompatAdapter(provider)
42
+ if provider.kind == "anthropic":
43
+ return AnthropicAdapter(provider)
44
+ if provider.kind == "agent_cli":
45
+ # Imported lazily so the external-agent adapter (and its subprocess /
46
+ # os plumbing) is only pulled in when a config actually uses it.
47
+ from coderouter.adapters.agent_cli import AgentCliAdapter
48
+
49
+ return AgentCliAdapter(provider)
50
+ if plugin_registry is not None:
51
+ for factory in plugin_registry.adapters:
52
+ if factory.kind == provider.kind:
53
+ return factory.build(provider)
54
+ raise ValueError(
55
+ f"Unknown adapter kind {provider.kind!r}. "
56
+ f"in-core kinds: {', '.join(_IN_CORE_KINDS)}; "
57
+ f"plugin-provided kinds: {_plugin_kinds(plugin_registry)}. "
58
+ f"If a plugin should provide {provider.kind!r}, ensure it is "
59
+ f"installed AND listed in plugins.enabled."
60
+ )
@@ -342,13 +342,23 @@ class ProviderConfig(BaseModel):
342
342
  model_config = ConfigDict(extra="forbid")
343
343
 
344
344
  name: str = Field(..., description="Unique identifier used in profiles.yaml")
345
- kind: Literal["openai_compat", "anthropic", "agent_cli"] = Field(
345
+ # v2.8.0: widened from Literal["openai_compat", "anthropic", "agent_cli"]
346
+ # to str so a provider can name a kind served by an adapter plugin
347
+ # (docs/designs/agent-cli-plugin-extraction.md §3). Config loading
348
+ # happens before plugin discovery (coderouter/ingress/app.py
349
+ # ``load_config`` then ``discover_and_load``), so pydantic can't know
350
+ # the full set of valid kinds at this point — an unknown kind still
351
+ # fails fast, just one step later, in ``build_adapter`` when the
352
+ # engine builds its adapter cache at startup.
353
+ kind: str = Field(
346
354
  default="openai_compat",
347
355
  description=(
348
356
  "Adapter type. 'openai_compat' covers llama.cpp / Ollama / "
349
357
  "OpenRouter / LM Studio / Together / Groq. 'anthropic' is the "
350
358
  "native Anthropic Messages API passthrough (v0.3.x). 'agent_cli' "
351
- "invokes an external coding-agent CLI one-shot (see AgentCliConfig)."
359
+ "invokes an external coding-agent CLI one-shot (see AgentCliConfig). "
360
+ "Other values must be served by an adapter plugin listed in "
361
+ "plugins.enabled."
352
362
  ),
353
363
  )
354
364
  # base_url is required for HTTP-backed adapters (openai_compat / anthropic)
@@ -1,11 +1,13 @@
1
- """Plugin SDK Protocol contracts (v2.3.0).
1
+ """Plugin SDK Protocol contracts (v2.3.0, Adapter wired in v2.8.0).
2
2
 
3
- Six extension points are defined here. Two are wired into the engine
4
- in v2.3.0 (:class:`InputFilter`, :class:`Observer`); four are
5
- Protocol-only (:class:`Frontend`, :class:`Guard`, :class:`OutputFilter`,
6
- :class:`Adapter`) and will get engine integration when a real plugin
7
- drives the requirement see ``docs/inside/plugin-architecture-draft.md``
8
- §3 for the full design rationale.
3
+ Six extension points are defined here. Three are wired into the engine
4
+ (:class:`InputFilter`, :class:`Observer` since v2.3.0; :class:`Adapter`
5
+ since v2.8.0 see ``docs/designs/agent-cli-plugin-extraction.md`` §2);
6
+ three remain Protocol-only (:class:`Frontend`, :class:`Guard`,
7
+ :class:`OutputFilter`) and will get engine integration when a real
8
+ plugin drives the requirement see
9
+ ``docs/inside/plugin-architecture-draft.md`` §3 for the full design
10
+ rationale.
9
11
 
10
12
  Why declare contracts ahead of integration? It lets a plugin author
11
13
  build against the SDK *now* (and ship a working ``coderouter.frontend``
@@ -14,9 +16,11 @@ backward-incompatible Protocol revision later. ``runtime_checkable``
14
16
  is used so :func:`isinstance` checks work in the loader for clearer
15
17
  error messages.
16
18
 
17
- All hooks are async. Failures must NEVER block the engine response —
18
- the engine wraps every hook call in try/except and degrades gracefully
19
- (see ``coderouter/routing/fallback.py`` integration site).
19
+ InputFilter / Observer are async and run repeatedly on the hot path;
20
+ failures must NEVER block the engine response, so the engine wraps
21
+ every hook call in try/except and degrades gracefully (see
22
+ ``coderouter/routing/fallback.py`` integration site). Adapter is
23
+ different in shape — see its docstring below.
20
24
  """
21
25
  from __future__ import annotations
22
26
 
@@ -25,7 +29,8 @@ from typing import TYPE_CHECKING, Any, Protocol, runtime_checkable
25
29
  if TYPE_CHECKING:
26
30
  # Avoid circular imports at runtime — Protocol typing only needs
27
31
  # these for documentation and static analysis.
28
- from coderouter.config.schemas import CodeRouterConfig
32
+ from coderouter.adapters.base import BaseAdapter
33
+ from coderouter.config.schemas import CodeRouterConfig, ProviderConfig
29
34
  from coderouter.translation.anthropic import (
30
35
  AnthropicRequest,
31
36
  AnthropicResponse,
@@ -93,6 +98,44 @@ class Observer(Protocol):
93
98
  async def on_event(self, event_type: str, payload: dict[str, Any]) -> None: ...
94
99
 
95
100
 
101
+ # ====================================================================
102
+ # Adapter hook (engine integration in v2.8.0)
103
+ # ====================================================================
104
+
105
+
106
+ @runtime_checkable
107
+ class Adapter(Protocol):
108
+ """New ``kind`` value in providers.yaml, backed by a plugin.
109
+
110
+ The plugin declares the ``kind`` string it serves and a factory
111
+ that turns a matching :class:`~coderouter.config.schemas.ProviderConfig`
112
+ into a :class:`~coderouter.adapters.base.BaseAdapter` instance —
113
+ the same surface :func:`coderouter.adapters.registry.build_adapter`
114
+ uses for in-core kinds, so the engine treats plugin adapters
115
+ indistinguishably from built-ins once registered. See
116
+ ``docs/designs/agent-cli-plugin-extraction.md`` §2 for the design
117
+ rationale.
118
+
119
+ Shape-wise this hook differs from :class:`InputFilter` /
120
+ :class:`Observer`: those are instances the engine calls repeatedly
121
+ on the hot path, so they're async. An adapter provider is instead
122
+ a **factory** consulted once per provider at engine startup (and
123
+ again if the provider is re-registered at runtime) — construction
124
+ is I/O-free, so :meth:`build` is synchronous, matching
125
+ ``build_adapter``.
126
+ """
127
+
128
+ name: str
129
+ # The ``kind`` value this plugin serves in providers.yaml. Distinct
130
+ # from ``name`` (the plugin's own identifier, used in
131
+ # ``plugins.enabled`` / logs) — kept 1:1 for now; a future
132
+ # ``kinds: tuple[str, ...]`` can generalize this if a real plugin
133
+ # needs to serve more than one kind.
134
+ kind: str
135
+
136
+ def build(self, config: ProviderConfig) -> BaseAdapter: ...
137
+
138
+
96
139
  # ====================================================================
97
140
  # Future hooks (Protocol-only, engine integration in v2.4+)
98
141
  # ====================================================================
@@ -151,18 +194,3 @@ class OutputFilter(Protocol):
151
194
  async def transform(
152
195
  self, response: AnthropicResponse
153
196
  ) -> AnthropicResponse: ...
154
-
155
-
156
- @runtime_checkable
157
- class Adapter(Protocol):
158
- """New ``kind`` value in providers.yaml (e.g. ``bedrock-native``).
159
-
160
- Plugins implement the same async surface as
161
- :class:`coderouter.adapters.base.BaseAdapter` so the engine can
162
- treat them indistinguishably from built-in adapters once the
163
- loader registers the new ``kind`` mapping.
164
-
165
- Not yet integrated — Protocol contract only.
166
- """
167
-
168
- name: str
@@ -38,10 +38,14 @@ if TYPE_CHECKING:
38
38
 
39
39
  logger = get_logger(__name__)
40
40
 
41
- # Active hook groups in v2.3.0. The engine wires these into the
42
- # request flow; plugins targeting them will see their methods called
43
- # at runtime.
44
- PLUGIN_GROUPS_V2_3: tuple[str, ...] = ("input_filter", "observer")
41
+ # Active hook groups. The engine wires these into the request flow;
42
+ # plugins targeting them will see their methods called at runtime.
43
+ # ``input_filter`` / ``observer`` since v2.3.0; ``adapter`` joined in
44
+ # v2.8.0 (docs/designs/agent-cli-plugin-extraction.md §2.4) its
45
+ # factories are consulted from ``build_adapter``, not iterated on the
46
+ # hot path like the other two, but it goes through the same
47
+ # discover-then-enable-gate machinery below.
48
+ PLUGIN_GROUPS_V2_3: tuple[str, ...] = ("input_filter", "observer", "adapter")
45
49
 
46
50
  # Hook groups whose Protocol contracts are stable but whose engine
47
51
  # integration is deferred. Listing them here means a plugin author
@@ -51,7 +55,6 @@ PLUGIN_GROUPS_FUTURE: tuple[str, ...] = (
51
55
  "frontend",
52
56
  "guard",
53
57
  "output_filter",
54
- "adapter",
55
58
  )
56
59
 
57
60
 
@@ -20,8 +20,8 @@ from typing import Any
20
20
  class PluginRegistry:
21
21
  """In-memory registry of loaded plugin instances grouped by hook kind.
22
22
 
23
- Use the typed ``input_filters`` / ``observers`` properties on the
24
- hot path; plugin code should not iterate ``_by_group`` directly.
23
+ Use the typed ``input_filters`` / ``observers`` / ``adapters``
24
+ properties; plugin code should not iterate ``_by_group`` directly.
25
25
  """
26
26
 
27
27
  def __init__(self) -> None:
@@ -65,6 +65,17 @@ class PluginRegistry:
65
65
  """Plugins registered as ``coderouter.observer``."""
66
66
  return list(self._by_group.get("observer", ()))
67
67
 
68
+ @property
69
+ def adapters(self) -> list[Any]:
70
+ """Plugins registered as ``coderouter.adapter`` (kind factories).
71
+
72
+ Unlike ``input_filters`` / ``observers``, these aren't called
73
+ repeatedly on the hot path — :func:`coderouter.adapters.registry.build_adapter`
74
+ consults this list once per provider to resolve a plugin-served
75
+ ``kind`` (v2.8.0, docs/designs/agent-cli-plugin-extraction.md §2.4).
76
+ """
77
+ return list(self._by_group.get("adapter", ()))
78
+
68
79
  def is_empty(self) -> bool:
69
80
  """True iff no plugin instance has been registered, in any group.
70
81
 
@@ -1104,9 +1104,13 @@ class FallbackEngine:
1104
1104
  # via ``add_done_callback(_observer_tasks.discard)`` in
1105
1105
  # :meth:`_fanout_observers`.
1106
1106
  self._observer_tasks: set[asyncio.Task[None]] = set()
1107
- # Cache adapters so we don't re-instantiate per request
1107
+ # Cache adapters so we don't re-instantiate per request. v2.8.0:
1108
+ # pass the plugin registry through so a provider whose ``kind``
1109
+ # is served by an enabled adapter plugin resolves via
1110
+ # ``build_adapter``'s plugin lookup (agent-cli-plugin-extraction
1111
+ # §3.5) instead of raising "Unknown adapter kind".
1108
1112
  self._adapters: dict[str, BaseAdapter] = {
1109
- p.name: build_adapter(p) for p in config.providers
1113
+ p.name: build_adapter(p, self._plugin_registry) for p in config.providers
1110
1114
  }
1111
1115
  # v1.9-C: per-process adaptive routing adjuster (rolling-window
1112
1116
  # latency + error-rate observations, debounced rank changes).
@@ -1217,7 +1221,7 @@ class FallbackEngine:
1217
1221
  break
1218
1222
  if not replaced:
1219
1223
  self.config.providers.append(provider)
1220
- self._adapters[provider.name] = build_adapter(provider)
1224
+ self._adapters[provider.name] = build_adapter(provider, self._plugin_registry)
1221
1225
 
1222
1226
  try:
1223
1227
  chain = self.config.profile_by_name(profile_name)