coding-proxy 0.3.0a3__tar.gz → 0.3.1a1__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 (178) hide show
  1. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/AGENTS.md +2 -1
  2. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/CHANGELOG.md +19 -10
  3. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/PKG-INFO +1 -1
  4. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/pyproject.toml +1 -1
  5. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/config/config.default.yaml +3 -0
  6. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/routing/model_mapper.py +0 -20
  7. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/routing/usage_parser.py +0 -30
  8. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/server/dashboard.py +5 -4
  9. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_model_mapper.py +0 -18
  10. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_parse_usage.py +0 -62
  11. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/uv.lock +1 -1
  12. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/.github/workflows/ci.yml +0 -0
  13. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/.github/workflows/coverage.yml +0 -0
  14. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/.github/workflows/release.yml +0 -0
  15. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/.gitignore +0 -0
  16. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/.pre-commit-config.yaml +0 -0
  17. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/CLAUDE.md +0 -0
  18. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/LICENSE +0 -0
  19. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/README.md +0 -0
  20. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/assets/dashboard-v0.2.4.png +0 -0
  21. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/docs/arch/config-reference.md +0 -0
  22. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/docs/arch/convert.md +0 -0
  23. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/docs/arch/design-patterns.md +0 -0
  24. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/docs/arch/routing.md +0 -0
  25. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/docs/arch/testing.md +0 -0
  26. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/docs/arch/vendors.md +0 -0
  27. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/docs/ci-cd.md +0 -0
  28. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/docs/framework.md +0 -0
  29. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/docs/guide/api-reference.md +0 -0
  30. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/docs/guide/cli-reference.md +0 -0
  31. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/docs/guide/dashboard.md +0 -0
  32. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/docs/guide/monitoring.md +0 -0
  33. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/docs/guide/quickstart.md +0 -0
  34. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/docs/guide/vendors.md +0 -0
  35. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/docs/user-guide.md +0 -0
  36. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/docs/zh-CN/README.md +0 -0
  37. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/__init__.py +0 -0
  38. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/__init__.py +0 -0
  39. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/__main__.py +0 -0
  40. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/auth/__init__.py +0 -0
  41. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/auth/providers/__init__.py +0 -0
  42. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/auth/providers/base.py +0 -0
  43. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/auth/providers/github.py +0 -0
  44. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/auth/providers/google.py +0 -0
  45. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/auth/runtime.py +0 -0
  46. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/auth/store.py +0 -0
  47. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/cli/__init__.py +0 -0
  48. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/cli/auth_commands.py +0 -0
  49. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/cli/banner.py +0 -0
  50. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/compat/__init__.py +0 -0
  51. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/compat/canonical.py +0 -0
  52. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/compat/session_store.py +0 -0
  53. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/config/__init__.py +0 -0
  54. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/config/auth_schema.py +0 -0
  55. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/config/loader.py +0 -0
  56. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/config/resiliency.py +0 -0
  57. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/config/routing.py +0 -0
  58. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/config/schema.py +0 -0
  59. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/config/server.py +0 -0
  60. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/config/vendors.py +0 -0
  61. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/convert/__init__.py +0 -0
  62. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/convert/anthropic_to_gemini.py +0 -0
  63. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/convert/anthropic_to_openai.py +0 -0
  64. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/convert/gemini_sse_adapter.py +0 -0
  65. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/convert/gemini_to_anthropic.py +0 -0
  66. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/convert/openai_to_anthropic.py +0 -0
  67. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/convert/vendor_channels.py +0 -0
  68. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/logging/__init__.py +0 -0
  69. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/logging/db.py +0 -0
  70. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/logging/formatters.py +0 -0
  71. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/logging/stats.py +0 -0
  72. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/model/__init__.py +0 -0
  73. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/model/auth.py +0 -0
  74. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/model/compat.py +0 -0
  75. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/model/constants.py +0 -0
  76. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/model/pricing.py +0 -0
  77. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/model/token.py +0 -0
  78. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/model/vendor.py +0 -0
  79. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/native_api/__init__.py +0 -0
  80. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/native_api/config.py +0 -0
  81. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/native_api/extractors/__init__.py +0 -0
  82. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/native_api/extractors/anthropic.py +0 -0
  83. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/native_api/extractors/gemini.py +0 -0
  84. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/native_api/extractors/openai.py +0 -0
  85. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/native_api/handler.py +0 -0
  86. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/native_api/operation.py +0 -0
  87. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/native_api/routes.py +0 -0
  88. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/native_api/usage_registry.py +0 -0
  89. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/pricing.py +0 -0
  90. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/routing/__init__.py +0 -0
  91. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/routing/circuit_breaker.py +0 -0
  92. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/routing/error_classifier.py +0 -0
  93. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/routing/executor.py +0 -0
  94. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/routing/quota_guard.py +0 -0
  95. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/routing/rate_limit.py +0 -0
  96. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/routing/retry.py +0 -0
  97. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/routing/router.py +0 -0
  98. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/routing/session_manager.py +0 -0
  99. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/routing/tier.py +0 -0
  100. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/routing/usage_recorder.py +0 -0
  101. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/server/__init__.py +0 -0
  102. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/server/app.py +0 -0
  103. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/server/factory.py +0 -0
  104. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/server/responses.py +0 -0
  105. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/server/routes.py +0 -0
  106. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/streaming/__init__.py +0 -0
  107. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/streaming/anthropic_compat.py +0 -0
  108. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/vendors/__init__.py +0 -0
  109. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/vendors/alibaba.py +0 -0
  110. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/vendors/anthropic.py +0 -0
  111. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/vendors/antigravity.py +0 -0
  112. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/vendors/base.py +0 -0
  113. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/vendors/copilot.py +0 -0
  114. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/vendors/copilot_models.py +0 -0
  115. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/vendors/copilot_token_manager.py +0 -0
  116. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/vendors/copilot_urls.py +0 -0
  117. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/vendors/doubao.py +0 -0
  118. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/vendors/kimi.py +0 -0
  119. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/vendors/minimax.py +0 -0
  120. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/vendors/mixins.py +0 -0
  121. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/vendors/native_anthropic.py +0 -0
  122. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/vendors/token_manager.py +0 -0
  123. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/vendors/xiaomi.py +0 -0
  124. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/vendors/zhipu.py +0 -0
  125. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/__init__.py +0 -0
  126. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_antigravity.py +0 -0
  127. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_app_routes.py +0 -0
  128. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_auto_login.py +0 -0
  129. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_banner.py +0 -0
  130. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_circuit_breaker.py +0 -0
  131. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_cli_usage.py +0 -0
  132. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_compat.py +0 -0
  133. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_config_init.py +0 -0
  134. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_config_loader.py +0 -0
  135. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_convert_request.py +0 -0
  136. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_convert_response.py +0 -0
  137. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_convert_sse.py +0 -0
  138. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_copilot.py +0 -0
  139. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_copilot_convert_request.py +0 -0
  140. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_copilot_convert_response.py +0 -0
  141. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_copilot_models.py +0 -0
  142. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_copilot_urls.py +0 -0
  143. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_currency.py +0 -0
  144. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_error_classifier.py +0 -0
  145. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_logging_dual_write.py +0 -0
  146. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_mixins.py +0 -0
  147. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_model_auth.py +0 -0
  148. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_model_compat.py +0 -0
  149. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_model_constants.py +0 -0
  150. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_model_pricing.py +0 -0
  151. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_model_token.py +0 -0
  152. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_model_vendor.py +0 -0
  153. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_native_api_base_url_override.py +0 -0
  154. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_native_api_extractors.py +0 -0
  155. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_native_api_handler.py +0 -0
  156. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_native_api_operation.py +0 -0
  157. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_native_api_routes.py +0 -0
  158. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_native_vendors.py +0 -0
  159. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_parse_usage_gemini.py +0 -0
  160. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_pricing.py +0 -0
  161. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_quota_guard.py +0 -0
  162. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_rate_limit.py +0 -0
  163. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_router_chain.py +0 -0
  164. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_router_executor.py +0 -0
  165. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_runtime_reauth.py +0 -0
  166. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_schema.py +0 -0
  167. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_streaming_anthropic_compat.py +0 -0
  168. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_tier.py +0 -0
  169. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_tiers_config.py +0 -0
  170. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_time_range.py +0 -0
  171. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_token_logger.py +0 -0
  172. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_token_logger_native_columns.py +0 -0
  173. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_token_manager.py +0 -0
  174. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_types.py +0 -0
  175. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_vendor_channels.py +0 -0
  176. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_vendor_streaming.py +0 -0
  177. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_vendors.py +0 -0
  178. {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_zhipu.py +0 -0
@@ -47,10 +47,11 @@
47
47
  3. **Link Validity**: 确保所有引用的 URL 可访问且具备明确的上下文价值;
48
48
  4. **Git Commit**: 在需要提交变更到 Git 时,一律使用 Shell 调用 Claude Code 的自定义 Slash Command: `/commit` 进行 git commit 操作(若环境中未安装 Claude Code,则直接读取 `~/.claude/commands/commit.md`,按照其中的规则进行 git commit 操作)。不要执行 Rebase。
49
49
  5. **Pre-commit Hooks**: 克隆仓库后执行 `uv run pre-commit install` 激活本地 Git hooks,使 Ruff lint(含 auto-fix)、Ruff format 及通用代码卫生检查在每次 commit 前自动运行。若 hooks 自动修复了问题,提交会被中断,执行 `git add -p` 审阅修复内容后重新提交即可。
50
+ 6. **Issue**: 在 docs/issue.md 中维护你处理过的 Issue 摘要(问题描述、表因根因、处理方式、后续防范、同类问题影响与处理注意实现等),便于同类问题的跨上下文处理;注意识别相同 Issue,不要同 Issue 多处维护。
50
51
  - **Package Management Standardization (包管理规范)**:
51
52
  1. **Python**: 严禁使用 pip/poetry,**必须**统一使用 `uv` 进行包管理与脚本执行(如 `uv run`);
52
53
  2. **JavaScript/TypeScript**: 严禁使用 npm/yarn,**必须**统一使用 `pnpm` 进行包管理与脚本执行。
53
- - **Database Management**: 谨慎操作,数据迁移、测试等操作严禁将现有数据删除。
54
+ - **Database Management**: 谨慎操作,数据迁移、测试等操作严禁将现有数据删除,谨慎操作数据迁移的回滚,防止数据被清理。
54
55
 
55
56
  ## Documentation Standards (文档规范)
56
57
 
@@ -4,16 +4,25 @@
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
- - feat(server): 默认监听端口 `8046` → `3392`,避免与常见企业端口段冲突;BREAKING: 已将端口固化进客户端 `ANTHROPIC_BASE_URL` / SDK `base_url` / 监控看板 URL 的用户需同步更新,或显式通过 `--port 8046` / `server.port: 8046` 回退到旧值;
8
- - feat(native-api): 原生 API 透传三家 provider (`openai` / `gemini` / `anthropic`) `enabled` 默认由 `false` → `true` 开箱即用;`config.default.yaml` 顶层追加 `native_api:` 实体配置块(首次启动自动拷贝至 `~/.coding-proxy/config.yaml`,用户直接编辑 `base_url` 即可将上游切换至第三方代理);同时新增 `NATIVE_OPENAI_BASE_URL` / `NATIVE_GEMINI_BASE_URL` / `NATIVE_ANTHROPIC_BASE_URL` 三枚环境变量覆写通道(空串/纯空白视作未设置),三级优先级 **env > yaml > 内置默认** 由 `NativeApiConfig._apply_env_overrides` `@model_validator(mode="after")` 统一注入;BREAKING: 升级后 `/api/{openai,gemini,anthropic}/**` 默认暴露,proxy 仍不保管凭据(`Authorization` / `x-api-key` / `?key=` 均由客户端透传),如需关闭显式设置 `native_api.<provider>.enabled: false`;
9
- - feat(native-api): 新增 `/api/{openai,gemini,anthropic}/**` 原生 LLM API 全量 catch-all 透传通道——客户端只需改 SDK `base_url` 即可复用 proxy 链路访问 OpenAI / Gemini / Anthropic 官方 API,认证完全透传不保管凭据;核心由 `NativeProxyHandler` + `OperationClassifier` + `NativeUsageExtractor` Registry 三件套组成,与既有 `/v1/messages` Claude Code 链路正交共存、零回归;首版覆盖 chat / completions / responses / embeddings / audio / image / count_tokens / moderations / cachedContents / messages / batches 等全量端点;
10
- - feat(usage): `usage_log` 新增 `client_category` / `operation` / `endpoint` / `extra_usage_json` 四列(全部 `DEFAULT`、幂等迁移),区分 Claude Code 场景(`'cc'`)与原生 API 场景(`'api'`),承载规范化操作名与非规范 token 字段(reasoning / audio / thoughts / server_tool_use 等);`query_usage` 支持按新列过滤,`_PERIOD_SQL` 聚合追加 `client_category, operation` 维度;
11
- - feat(usage-parser): `parse_usage_from_chunk` 扩展识别 Gemini SSE `usageMetadata.*`(promptTokenCount / candidatesTokenCount / cachedContentTokenCount / thoughtsTokenCount / toolUsePromptTokenCount),新增 `gemini_usage_metadata` evidence kind,既有 Anthropic/OpenAI 分支行为零变更;
12
- - refactor(vendor-channels): 彻底收敛跨供应商兼容性逻辑——删除 `server/request_normalizer.py` 入口通用规范化层,将 `srvtoolu_*` ID 重写、`server_tool_use_delta` 私有块剥离全部迁入源→目标绑定通道(`prepare_zhipu_to_anthropic`、`prepare_zhipu_to_copilot`);新增 `infer_source_vendor_from_body` 内容感知源推断,在无会话状态的首次请求场景下兜底识别源供应商;`_RouteExecutor._determine_source_vendor` 扩充为三级优先级(failed_tier → session_state → body inference),确保未注册转换对不触发任何清洗;
13
- - refactor(count-tokens): `/v1/messages/count_tokens` 端点移除无条件 `strip_thinking_blocks` 过度防御,改为基于 `infer_source_vendor_from_body` + `get_transition_channel` 的按需通道清洗,语义与 `/v1/messages` 对齐;
14
- - fix(request-normalizer): 重设计 zhipu→anthropic 跨供应商 tool_use/tool_result 配对修复——以单遍自包含 `enforce_anthropic_tool_pairing` 替代原有多步串联管线(剥离→重定位→孤儿修复),消除步骤间隐式依赖导致的孤儿 tool_use 漏修问题,彻底根治 `tool_use ids were found without tool_result blocks` 400 异常;
15
- - refactor(vendor-channels): 将供应商转换通道从「目标 vendor 专属」重构为「源→目标绑定」模型——注册表键从 `target_vendor` 改为 `(source, target)` 二元组,通道函数从 `prepare_for_X` 重命名为 `prepare_X_to_Y`,触发逻辑从 `_needs_vendor_channel` 替换为 `_determine_source_vendor`(基于请求内 `failed_tier_name` 和会话历史推断源 vendor),未注册的转换对(如 anthropic→zhipu)不触发任何通道;
16
- - feat(vendor-channels): 新增 zhipu→anthropic、zhipu→copilot、copilot→zhipu 三条源→目标绑定转换通道,在跨供应商故障转移时自动清理源 vendor 产物(thinking 块、cache_control 字段、thinking 参数、tool_use/tool_result 配对),消除 `likely format incompatibility (400 + tool_results)` 错误;
7
+ ## [v0.3.0](https://github.com/ThreeFish-AI/coding-proxy/releases/tag/v0.3.0) 2026-04-20
8
+
9
+ > [!IMPORTANT]
10
+ >
11
+ > **🚀 OpenAI、Anthropic、Gemini 原生 API 进驻 Coding Proxy!**
12
+ >
13
+ > 服务对象不在局限 Claude Code,凡兼容 OpenAI、Anthropic、Gemini 三巨头 API 协议的客户端,出口 LLM 流量可统一收敛到 Coding Proxy。
14
+
15
+ ### 核心亮点
16
+
17
+ - feat(native-api): 新增 `/api/{openai,gemini,anthropic}/**` 原生 LLM API 全量 catch-all 透传通道;
18
+ - feat(dashboard): 新增实时 Web Dashboard 页面,聚合展示流量与用量统计;
19
+ - feat(usage): `usage` 区分 Claude Code 场景(`'cc'`)与原生 API 场景(`'api'`);
20
+ - refactor(vendor-channels): 将供应商转换通道从目标专属重构为源→目标绑定模型;
21
+ - docs(user-guide): 补充 POST /v1/messages 完整 API 参考文档;
22
+
23
+ ### 🔧 更多特性
24
+
25
+ - feat(server): 默认监听端口 `8046` → `3392`,规范化 [Negentropy](https://github.com/ThreeFish-AI/negentropy) 体系端口;
17
26
 
18
27
  ## [v0.2.3](https://github.com/ThreeFish-AI/coding-proxy/releases/tag/v0.2.3) — 2026-04-16
19
28
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: coding-proxy
3
- Version: 0.3.0a3
3
+ Version: 0.3.1a1
4
4
  Summary: A High-Availability, Transparent, and Smart Multi-Vendor Proxy for Claude Code. Support Claude Plans, GitHub Copilot, Google Antigravity, ZAI/GLM, MiniMax, Qwen, Xiaomi, Kimi, Doubao...
5
5
  Project-URL: Source Code, https://github.com/ThreeFish-AI/coding-proxy
6
6
  Project-URL: User Guide, https://github.com/ThreeFish-AI/coding-proxy/blob/master/docs/user-guide.md
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "coding-proxy"
3
- version = "0.3.0a3"
3
+ version = "0.3.1a1"
4
4
  description = "A High-Availability, Transparent, and Smart Multi-Vendor Proxy for Claude Code. Support Claude Plans, GitHub Copilot, Google Antigravity, ZAI/GLM, MiniMax, Qwen, Xiaomi, Kimi, Doubao..."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
@@ -485,6 +485,9 @@ pricing:
485
485
  - vendor: gemini
486
486
  model: text-embedding-004
487
487
  input_cost_per_mtok: $0.10
488
+ - vendor: gemini
489
+ model: text-embedding-005
490
+ input_cost_per_mtok: $0.10
488
491
  # ── Google Antigravity(参照 Anthropic 定价估算) ──
489
492
  - vendor: antigravity
490
493
  model: claude-opus-4-6-thinking
@@ -62,12 +62,6 @@ class ModelMapper:
62
62
  continue
63
63
  if not rule.is_regex and "*" not in rule.pattern:
64
64
  if rule.pattern == model:
65
- logger.debug(
66
- "Model mapped: %s -> %s (vendor=%s exact)",
67
- model,
68
- rule.target,
69
- display_name,
70
- )
71
65
  return rule.target
72
66
 
73
67
  # 2. 通配符/正则匹配
@@ -77,23 +71,9 @@ class ModelMapper:
77
71
  if rule.is_regex:
78
72
  compiled = self._compiled[rule.pattern]
79
73
  if compiled.fullmatch(model):
80
- logger.debug(
81
- "Model mapped: %s -> %s (vendor=%s regex=%s)",
82
- model,
83
- rule.target,
84
- display_name,
85
- rule.pattern,
86
- )
87
74
  return rule.target
88
75
  elif "*" in rule.pattern:
89
76
  if fnmatch.fnmatch(model, rule.pattern):
90
- logger.debug(
91
- "Model mapped: %s -> %s (vendor=%s glob=%s)",
92
- model,
93
- rule.target,
94
- display_name,
95
- rule.pattern,
96
- )
97
77
  return rule.target
98
78
 
99
79
  # 3. 默认值
@@ -172,10 +172,6 @@ def parse_usage_from_chunk(
172
172
  if isinstance(msg, dict) and "usage" in msg:
173
173
  u = msg["usage"]
174
174
  input_tokens = u.get("input_tokens", 0) or u.get("prompt_tokens", 0)
175
- if input_tokens > 0:
176
- logger.debug(
177
- "Extracted input tokens from message.usage: %d", input_tokens
178
- )
179
175
  _set_if_nonzero(usage, "input_tokens", input_tokens)
180
176
  _set_if_nonzero(
181
177
  usage, "cache_creation_tokens", u.get("cache_creation_input_tokens", 0)
@@ -204,18 +200,6 @@ def parse_usage_from_chunk(
204
200
  cache_creation_tokens = u.get("cache_creation_input_tokens", 0)
205
201
  cache_read_tokens = u.get("cache_read_input_tokens", 0)
206
202
 
207
- _label = f" ({vendor_label})" if vendor_label else ""
208
- if output_tokens > 0:
209
- logger.debug(
210
- "Extracted output tokens from data.usage: %d%s",
211
- output_tokens,
212
- _label,
213
- )
214
- if input_tokens > 0:
215
- logger.debug(
216
- "Extracted input tokens from data.usage: %d%s", input_tokens, _label
217
- )
218
-
219
203
  _set_if_nonzero(usage, "output_tokens", output_tokens)
220
204
  _set_if_nonzero(usage, "input_tokens", input_tokens)
221
205
  _set_if_nonzero(usage, "cache_creation_tokens", cache_creation_tokens)
@@ -241,20 +225,6 @@ def parse_usage_from_chunk(
241
225
  thoughts_tc = int(um.get("thoughtsTokenCount", 0) or 0)
242
226
  tool_use_tc = int(um.get("toolUsePromptTokenCount", 0) or 0)
243
227
 
244
- _label = f" ({vendor_label})" if vendor_label else ""
245
- if prompt_tc > 0:
246
- logger.debug(
247
- "Extracted Gemini prompt tokens from usageMetadata: %d%s",
248
- prompt_tc,
249
- _label,
250
- )
251
- if cand_tc > 0:
252
- logger.debug(
253
- "Extracted Gemini candidates tokens from usageMetadata: %d%s",
254
- cand_tc,
255
- _label,
256
- )
257
-
258
228
  _set_if_nonzero(usage, "input_tokens", prompt_tc)
259
229
  _set_if_nonzero(usage, "output_tokens", cand_tc)
260
230
  _set_if_nonzero(usage, "cache_read_tokens", cached_tc)
@@ -699,14 +699,15 @@ function makeExternalTooltipHandler(opts = {}) {
699
699
 
700
700
  const titleLines = tooltip.title || [];
701
701
  const dataPoints = tooltip.dataPoints || [];
702
+ const visiblePoints = dataPoints.filter(dp => dp.raw);
702
703
 
703
704
  let html = '';
704
705
  if (titleLines.length) {
705
706
  html += '<div id="chart-tooltip-title">' + titleLines.join('<br>') + '</div>';
706
707
  }
707
- if (dataPoints.length) {
708
+ if (visiblePoints.length) {
708
709
  html += '<div id="chart-tooltip-items">';
709
- dataPoints.forEach(dp => {
710
+ visiblePoints.forEach(dp => {
710
711
  // 折线图: borderColor 为字符串;甜甜圈图: backgroundColor 为数组
711
712
  const bg = dp.dataset.backgroundColor;
712
713
  const color = dp.dataset.borderColor
@@ -722,8 +723,8 @@ function makeExternalTooltipHandler(opts = {}) {
722
723
  });
723
724
  html += '</div>';
724
725
  }
725
- if (showTotal && dataPoints.length > 1) {
726
- const total = dataPoints.reduce((s, dp) => s + (dp.raw || 0), 0);
726
+ if (showTotal && visiblePoints.length > 1) {
727
+ const total = visiblePoints.reduce((s, dp) => s + (dp.raw || 0), 0);
727
728
  if (total > 0) {
728
729
  html += '<div id="chart-tooltip-footer">合计: ' + fmtTotalFn(total) + '</div>';
729
730
  }
@@ -1,7 +1,5 @@
1
1
  """模型映射器单元测试."""
2
2
 
3
- import logging
4
-
5
3
  from coding.proxy.config.schema import ModelMappingRule
6
4
  from coding.proxy.routing.model_mapper import ModelMapper
7
5
 
@@ -95,19 +93,3 @@ def test_legacy_rule_only_applies_to_fallback():
95
93
  )
96
94
  == "claude-sonnet-4-20250514"
97
95
  )
98
-
99
-
100
- def test_zhipu_vendor_logs_with_original_name(caplog):
101
- """zhipu 供应商传入时,日志应显示 vendor=zhipu 而非 vendor=fallback."""
102
- caplog.set_level(logging.DEBUG, logger="coding.proxy.routing.model_mapper")
103
- mapper = _make_mapper(
104
- [
105
- ModelMappingRule(pattern="claude-sonnet-*", target="glm-5.1"),
106
- ]
107
- )
108
- result = mapper.map("claude-sonnet-4-20250514", vendor="zhipu")
109
- assert result == "glm-5.1"
110
-
111
- # 日志中应包含 vendor=zhipu 而非 vendor=fallback
112
- assert any("vendor=zhipu" in r.message for r in caplog.records)
113
- assert not any("vendor=fallback" in r.message for r in caplog.records)
@@ -1,7 +1,5 @@
1
1
  """SSE chunk 用量解析单元测试 — 覆盖 Anthropic / OpenAI(Zhipu) / 混合格式."""
2
2
 
3
- import logging
4
-
5
3
  from coding.proxy.routing.usage_parser import _set_if_nonzero, parse_usage_from_chunk
6
4
 
7
5
 
@@ -267,63 +265,3 @@ def test_multiple_sse_lines_in_single_chunk():
267
265
  parse_usage_from_chunk(chunk, usage)
268
266
  assert usage["input_tokens"] == 80
269
267
  assert usage["output_tokens"] == 20
270
-
271
-
272
- # --- vendor_label 日志标签 ---
273
-
274
-
275
- def test_vendor_label_anthropic(caplog):
276
- """传入 vendor_label=Anthropic 时,日志应标注 (Anthropic)."""
277
- caplog.set_level(logging.DEBUG, logger="coding.proxy.routing.usage_parser")
278
- usage: dict = {}
279
- parse_usage_from_chunk(
280
- _sse(
281
- '{"type":"message_delta","delta":{},"usage":{"output_tokens":42,"input_tokens":10}}'
282
- ),
283
- usage,
284
- vendor_label="Anthropic",
285
- )
286
- assert any("(Anthropic)" in r.message for r in caplog.records)
287
-
288
-
289
- def test_vendor_label_openai(caplog):
290
- """传入 vendor_label=OpenAI 时,日志应标注 (OpenAI)."""
291
- caplog.set_level(logging.DEBUG, logger="coding.proxy.routing.usage_parser")
292
- usage: dict = {}
293
- parse_usage_from_chunk(
294
- _sse('{"usage":{"prompt_tokens":100,"completion_tokens":25}}'),
295
- usage,
296
- vendor_label="OpenAI",
297
- )
298
- assert any("(OpenAI)" in r.message for r in caplog.records)
299
-
300
-
301
- def test_vendor_label_gemini(caplog):
302
- """传入 vendor_label=Gemini 时,日志应标注 (Gemini)."""
303
- caplog.set_level(logging.DEBUG, logger="coding.proxy.routing.usage_parser")
304
- usage: dict = {}
305
- parse_usage_from_chunk(
306
- _sse(
307
- '{"type":"message_delta","delta":{},"usage":{"output_tokens":30,"input_tokens":200}}'
308
- ),
309
- usage,
310
- vendor_label="Gemini",
311
- )
312
- assert any("(Gemini)" in r.message for r in caplog.records)
313
-
314
-
315
- def test_no_vendor_label_omits_parenthesis(caplog):
316
- """不传 vendor_label 时,日志不应包含括号标签."""
317
- caplog.set_level(logging.DEBUG, logger="coding.proxy.routing.usage_parser")
318
- usage: dict = {}
319
- parse_usage_from_chunk(
320
- _sse('{"type":"message_delta","delta":{},"usage":{"output_tokens":10}}'),
321
- usage,
322
- )
323
- # 不应有任何带括号的 vendor 标签
324
- for record in caplog.records:
325
- assert (
326
- "(" not in record.message
327
- or "Extracted" not in record.message
328
- or ") " not in record.message[record.message.index("(") :]
329
- )
@@ -74,7 +74,7 @@ wheels = [
74
74
 
75
75
  [[package]]
76
76
  name = "coding-proxy"
77
- version = "0.3.0a3"
77
+ version = "0.3.1a1"
78
78
  source = { editable = "." }
79
79
  dependencies = [
80
80
  { name = "aiosqlite" },
File without changes
File without changes
File without changes