coding-proxy 0.2.4a3__tar.gz → 0.2.4a5__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 (167) hide show
  1. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/CHANGELOG.md +4 -0
  2. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/PKG-INFO +13 -12
  3. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/README.md +12 -11
  4. coding_proxy-0.2.4a5/docs/arch/config-reference.md +259 -0
  5. coding_proxy-0.2.4a5/docs/arch/convert.md +101 -0
  6. coding_proxy-0.2.4a5/docs/arch/design-patterns.md +607 -0
  7. coding_proxy-0.2.4a5/docs/arch/routing.md +180 -0
  8. coding_proxy-0.2.4a5/docs/arch/testing.md +114 -0
  9. coding_proxy-0.2.4a5/docs/arch/vendors.md +404 -0
  10. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/docs/ci-cd.md +41 -41
  11. coding_proxy-0.2.4a5/docs/framework.md +499 -0
  12. coding_proxy-0.2.4a5/docs/guide/api-reference.md +362 -0
  13. coding_proxy-0.2.4a5/docs/guide/cli-reference.md +238 -0
  14. coding_proxy-0.2.4a5/docs/guide/dashboard.md +63 -0
  15. coding_proxy-0.2.4a5/docs/guide/monitoring.md +207 -0
  16. coding_proxy-0.2.4a5/docs/guide/quickstart.md +103 -0
  17. coding_proxy-0.2.4a5/docs/guide/vendors.md +247 -0
  18. coding_proxy-0.2.4a5/docs/user-guide.md +245 -0
  19. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/docs/zh-CN/README.md +12 -11
  20. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/pyproject.toml +1 -1
  21. coding_proxy-0.2.4a5/src/coding/proxy/convert/vendor_channels.py +378 -0
  22. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/routing/executor.py +45 -72
  23. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/routing/router.py +2 -8
  24. coding_proxy-0.2.4a5/src/coding/proxy/server/request_normalizer.py +162 -0
  25. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/server/routes.py +5 -11
  26. coding_proxy-0.2.4a5/tests/test_request_normalizer.py +811 -0
  27. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/tests/test_router_executor.py +104 -96
  28. coding_proxy-0.2.4a5/tests/test_vendor_channels.py +761 -0
  29. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/uv.lock +1 -1
  30. coding_proxy-0.2.4a3/docs/framework.md +0 -1640
  31. coding_proxy-0.2.4a3/docs/user-guide.md +0 -1771
  32. coding_proxy-0.2.4a3/src/coding/proxy/server/request_normalizer.py +0 -541
  33. coding_proxy-0.2.4a3/tests/test_request_normalizer.py +0 -983
  34. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/.github/workflows/ci.yml +0 -0
  35. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/.github/workflows/coverage.yml +0 -0
  36. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/.github/workflows/release.yml +0 -0
  37. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/.gitignore +0 -0
  38. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/.pre-commit-config.yaml +0 -0
  39. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/AGENTS.md +0 -0
  40. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/CLAUDE.md +0 -0
  41. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/LICENSE +0 -0
  42. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/assets/dashboard-v0.2.3.png +0 -0
  43. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/__init__.py +0 -0
  44. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/__init__.py +0 -0
  45. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/__main__.py +0 -0
  46. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/auth/__init__.py +0 -0
  47. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/auth/providers/__init__.py +0 -0
  48. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/auth/providers/base.py +0 -0
  49. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/auth/providers/github.py +0 -0
  50. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/auth/providers/google.py +0 -0
  51. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/auth/runtime.py +0 -0
  52. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/auth/store.py +0 -0
  53. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/cli/__init__.py +0 -0
  54. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/cli/auth_commands.py +0 -0
  55. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/cli/banner.py +0 -0
  56. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/compat/__init__.py +0 -0
  57. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/compat/canonical.py +0 -0
  58. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/compat/session_store.py +0 -0
  59. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/config/__init__.py +0 -0
  60. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/config/auth_schema.py +0 -0
  61. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/config/config.default.yaml +0 -0
  62. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/config/loader.py +0 -0
  63. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/config/resiliency.py +0 -0
  64. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/config/routing.py +0 -0
  65. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/config/schema.py +0 -0
  66. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/config/server.py +0 -0
  67. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/config/vendors.py +0 -0
  68. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/convert/__init__.py +0 -0
  69. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/convert/anthropic_to_gemini.py +0 -0
  70. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/convert/anthropic_to_openai.py +0 -0
  71. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/convert/gemini_sse_adapter.py +0 -0
  72. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/convert/gemini_to_anthropic.py +0 -0
  73. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/convert/openai_to_anthropic.py +0 -0
  74. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/logging/__init__.py +0 -0
  75. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/logging/db.py +0 -0
  76. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/logging/formatters.py +0 -0
  77. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/logging/stats.py +0 -0
  78. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/model/__init__.py +0 -0
  79. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/model/auth.py +0 -0
  80. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/model/compat.py +0 -0
  81. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/model/constants.py +0 -0
  82. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/model/pricing.py +0 -0
  83. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/model/token.py +0 -0
  84. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/model/vendor.py +0 -0
  85. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/pricing.py +0 -0
  86. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/routing/__init__.py +0 -0
  87. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/routing/circuit_breaker.py +0 -0
  88. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/routing/error_classifier.py +0 -0
  89. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/routing/model_mapper.py +0 -0
  90. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/routing/quota_guard.py +0 -0
  91. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/routing/rate_limit.py +0 -0
  92. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/routing/retry.py +0 -0
  93. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/routing/session_manager.py +0 -0
  94. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/routing/tier.py +0 -0
  95. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/routing/usage_parser.py +0 -0
  96. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/routing/usage_recorder.py +0 -0
  97. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/server/__init__.py +0 -0
  98. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/server/app.py +0 -0
  99. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/server/dashboard.py +0 -0
  100. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/server/factory.py +0 -0
  101. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/server/responses.py +0 -0
  102. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/streaming/__init__.py +0 -0
  103. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/streaming/anthropic_compat.py +0 -0
  104. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/vendors/__init__.py +0 -0
  105. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/vendors/alibaba.py +0 -0
  106. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/vendors/anthropic.py +0 -0
  107. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/vendors/antigravity.py +0 -0
  108. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/vendors/base.py +0 -0
  109. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/vendors/copilot.py +0 -0
  110. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/vendors/copilot_models.py +0 -0
  111. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/vendors/copilot_token_manager.py +0 -0
  112. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/vendors/copilot_urls.py +0 -0
  113. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/vendors/doubao.py +0 -0
  114. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/vendors/kimi.py +0 -0
  115. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/vendors/minimax.py +0 -0
  116. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/vendors/mixins.py +0 -0
  117. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/vendors/native_anthropic.py +0 -0
  118. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/vendors/token_manager.py +0 -0
  119. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/vendors/xiaomi.py +0 -0
  120. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/src/coding/proxy/vendors/zhipu.py +0 -0
  121. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/tests/__init__.py +0 -0
  122. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/tests/test_antigravity.py +0 -0
  123. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/tests/test_app_routes.py +0 -0
  124. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/tests/test_auto_login.py +0 -0
  125. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/tests/test_banner.py +0 -0
  126. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/tests/test_circuit_breaker.py +0 -0
  127. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/tests/test_cli_usage.py +0 -0
  128. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/tests/test_compat.py +0 -0
  129. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/tests/test_config_init.py +0 -0
  130. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/tests/test_config_loader.py +0 -0
  131. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/tests/test_convert_request.py +0 -0
  132. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/tests/test_convert_response.py +0 -0
  133. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/tests/test_convert_sse.py +0 -0
  134. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/tests/test_copilot.py +0 -0
  135. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/tests/test_copilot_convert_request.py +0 -0
  136. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/tests/test_copilot_convert_response.py +0 -0
  137. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/tests/test_copilot_models.py +0 -0
  138. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/tests/test_copilot_urls.py +0 -0
  139. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/tests/test_currency.py +0 -0
  140. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/tests/test_error_classifier.py +0 -0
  141. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/tests/test_logging_dual_write.py +0 -0
  142. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/tests/test_mixins.py +0 -0
  143. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/tests/test_model_auth.py +0 -0
  144. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/tests/test_model_compat.py +0 -0
  145. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/tests/test_model_constants.py +0 -0
  146. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/tests/test_model_mapper.py +0 -0
  147. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/tests/test_model_pricing.py +0 -0
  148. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/tests/test_model_token.py +0 -0
  149. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/tests/test_model_vendor.py +0 -0
  150. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/tests/test_native_vendors.py +0 -0
  151. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/tests/test_parse_usage.py +0 -0
  152. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/tests/test_pricing.py +0 -0
  153. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/tests/test_quota_guard.py +0 -0
  154. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/tests/test_rate_limit.py +0 -0
  155. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/tests/test_router_chain.py +0 -0
  156. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/tests/test_runtime_reauth.py +0 -0
  157. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/tests/test_schema.py +0 -0
  158. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/tests/test_streaming_anthropic_compat.py +0 -0
  159. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/tests/test_tier.py +0 -0
  160. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/tests/test_tiers_config.py +0 -0
  161. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/tests/test_time_range.py +0 -0
  162. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/tests/test_token_logger.py +0 -0
  163. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/tests/test_token_manager.py +0 -0
  164. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/tests/test_types.py +0 -0
  165. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/tests/test_vendor_streaming.py +0 -0
  166. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/tests/test_vendors.py +0 -0
  167. {coding_proxy-0.2.4a3 → coding_proxy-0.2.4a5}/tests/test_zhipu.py +0 -0
@@ -4,6 +4,10 @@
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ - 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 异常;
8
+ - 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)不触发任何通道;
9
+ - feat(vendor-channels): 新增 zhipu→anthropic、zhipu→copilot、copilot→zhipu 三条源→目标绑定转换通道,在跨供应商故障转移时自动清理源 vendor 产物(thinking 块、cache_control 字段、thinking 参数、tool_use/tool_result 配对),消除 `likely format incompatibility (400 + tool_results)` 错误;
10
+
7
11
  ## [v0.2.3](https://github.com/ThreeFish-AI/coding-proxy/releases/tag/v0.2.3) — 2026-04-16
8
12
 
9
13
  - feat(dashboard): 新增实时 Web Dashboard 页面,聚合展示流量与用量统计;
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: coding-proxy
3
- Version: 0.2.4a3
3
+ Version: 0.2.4a5
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
@@ -60,10 +60,10 @@ When you're deeply immersed in your coding "zone" with **Claude Code** (or any A
60
60
  <img src="assets/dashboard-v0.2.3.png">
61
61
  </div>
62
62
 
63
- - **⛓️ N-tier Chained Failover**: Autonomous descending sequence, supporting Claude's official plans, as well as Coding Plans from GitHub Copilot, Z AI, MiniMax, Alibaba Qwen, Xiaomi, Kimi, Doubao, etc.
63
+ - **⛓️ N-tier Chained Failover**: Autonomous descending sequence, supporting Claude's official plans, as well as Coding Plans from GitHub Copilot, Google Antigravity, Z AI, MiniMax, Alibaba Qwen, Xiaomi, Kimi, Doubao, etc.
64
64
  - **🛡️ Smart Resilience & Quota Guardians**: Every single vendor node comes fully armed with an independent **Circuit Breaker** and **Quota Guard** to proactively dodge avalanches without breaking a sweat.
65
65
  - **👻 Phantom-like Transparency**: **100% transparent** to the client! No code tweaks required. Overwrite `ANTHROPIC_BASE_URL` with a single line, and you're good to go.
66
- - **🔄 Universal Alchemy (Formats & Models)**: Native support for two-way request/streaming (SSE) translations between Anthropic ←→ Gemini. Plus, auto/DIY model name mapping (e.g., effortlessly morphing `claude-*` into `glm-*`).
66
+ - **🔄 Universal Alchemy (Formats & Models)**: Native support for two-way request/streaming (SSE) translations between Anthropic ←→ Gemini and Anthropic ←→ OpenAI. Plus, auto/DIY model name mapping (e.g., effortlessly morphing `claude-*` into `glm-*`).
67
67
  - **📊 Extreme Observability**: Built-in, zero-BS local monitoring powered by a `SQLite WAL`. The CLI provides a one-click detailed Token usage dashboard (`coding-proxy usage`).
68
68
  - **⚡ Featherweight Standalone Deployment**: A fully asynchronous architecture (`FastAPI` + `httpx`). Zero dependency on Redis, message queues, or other heavy machinery—absolutely no extra baggage for your dev rig.
69
69
 
@@ -122,6 +122,7 @@ claude
122
122
  | Command | Description | Example Usage |
123
123
  | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------- |
124
124
  | `start` | **Fire up the proxy server.** Supports custom ports and configuration paths. | `coding-proxy start -p 8080 -c ~/config.yaml` |
125
+ | `auth` | **Manage OAuth credentials.** Sub-commands: `login` (browser OAuth), `status` (token validity), `reauth` (re-authenticate), `logout` (clear tokens). | `coding-proxy auth login -p github` |
125
126
  | `status` | **Check proxy health.** Shows circuit breaker states (OPEN/CLOSED) and quota status across all tiers. | `coding-proxy status` |
126
127
  | `usage` | **Token Stats Dashboard.** Stalks every single token consumed, failovers triggered, and latency across day/vendor/model dimensions. | `coding-proxy usage -d 7 -v anthropic` |
127
128
  | `reset` | **The emergency flush button.** Force-reset all circuit breakers and quotas instantly when you've confirmed the main vendor is back from the dead. | `coding-proxy reset` |
@@ -153,29 +154,29 @@ graph RL
153
154
  subgraph NTier["N-tier"]
154
155
  direction TB
155
156
 
156
- subgraph Tier0 ["Tier 0: Anthropic"]
157
+ subgraph Tier0 ["Tier 0: Zhipu"]
157
158
  direction RL
158
- G0{"CB / Quota"}:::gateway -- "✅ Pass" --> API0(("Anthropic API")):::api
159
+ G0{"CB / Quota"}:::gateway -- "✅ Pass" --> API0(("GLM API")):::api
159
160
  end
160
161
 
161
- subgraph Tier1 ["Tier 1: GitHub Copilot"]
162
+ subgraph Tier1 ["Tier 1: Anthropic"]
162
163
  direction RL
163
- G1{"CB / Quota"}:::gateway -- "✅ Pass" --> API1(("Copilot API")):::api
164
+ G1{"CB / Quota"}:::gateway -- "✅ Pass" --> API1(("Anthropic API")):::api
164
165
  end
165
166
 
166
- subgraph Tier2 ["Tier 2: Google Antigravity"]
167
+ subgraph Tier2 ["Tier 2: GitHub Copilot"]
167
168
  direction RL
168
- G2{"CB / Quota"}:::gateway -- "✅ Pass" --> API2(("Gemini API")):::api
169
+ G2{"CB / Quota"}:::gateway -- "✅ Pass" --> API2(("Copilot API")):::api
169
170
  end
170
171
 
171
- subgraph TierN ["Tier N: Zhipu"]
172
+ subgraph Tier3 ["Tier 3: Google Antigravity"]
172
173
  direction RL
173
- APIN(("GLM API")):::fallback
174
+ API3(("Gemini API")):::fallback
174
175
  end
175
176
 
176
177
  Tier0 -. "❌ Blocked / API Error" .-> Tier1
177
178
  Tier1 -. "❌ Blocked / API Error" .-> Tier2
178
- Tier2 -. "🆘 Safety Net Downgrade" .-> TierN
179
+ Tier2 -. "🆘 Safety Net Downgrade" .-> Tier3
179
180
  end
180
181
 
181
182
  end
@@ -33,10 +33,10 @@ When you're deeply immersed in your coding "zone" with **Claude Code** (or any A
33
33
  <img src="assets/dashboard-v0.2.3.png">
34
34
  </div>
35
35
 
36
- - **⛓️ N-tier Chained Failover**: Autonomous descending sequence, supporting Claude's official plans, as well as Coding Plans from GitHub Copilot, Z AI, MiniMax, Alibaba Qwen, Xiaomi, Kimi, Doubao, etc.
36
+ - **⛓️ N-tier Chained Failover**: Autonomous descending sequence, supporting Claude's official plans, as well as Coding Plans from GitHub Copilot, Google Antigravity, Z AI, MiniMax, Alibaba Qwen, Xiaomi, Kimi, Doubao, etc.
37
37
  - **🛡️ Smart Resilience & Quota Guardians**: Every single vendor node comes fully armed with an independent **Circuit Breaker** and **Quota Guard** to proactively dodge avalanches without breaking a sweat.
38
38
  - **👻 Phantom-like Transparency**: **100% transparent** to the client! No code tweaks required. Overwrite `ANTHROPIC_BASE_URL` with a single line, and you're good to go.
39
- - **🔄 Universal Alchemy (Formats & Models)**: Native support for two-way request/streaming (SSE) translations between Anthropic ←→ Gemini. Plus, auto/DIY model name mapping (e.g., effortlessly morphing `claude-*` into `glm-*`).
39
+ - **🔄 Universal Alchemy (Formats & Models)**: Native support for two-way request/streaming (SSE) translations between Anthropic ←→ Gemini and Anthropic ←→ OpenAI. Plus, auto/DIY model name mapping (e.g., effortlessly morphing `claude-*` into `glm-*`).
40
40
  - **📊 Extreme Observability**: Built-in, zero-BS local monitoring powered by a `SQLite WAL`. The CLI provides a one-click detailed Token usage dashboard (`coding-proxy usage`).
41
41
  - **⚡ Featherweight Standalone Deployment**: A fully asynchronous architecture (`FastAPI` + `httpx`). Zero dependency on Redis, message queues, or other heavy machinery—absolutely no extra baggage for your dev rig.
42
42
 
@@ -95,6 +95,7 @@ claude
95
95
  | Command | Description | Example Usage |
96
96
  | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------- |
97
97
  | `start` | **Fire up the proxy server.** Supports custom ports and configuration paths. | `coding-proxy start -p 8080 -c ~/config.yaml` |
98
+ | `auth` | **Manage OAuth credentials.** Sub-commands: `login` (browser OAuth), `status` (token validity), `reauth` (re-authenticate), `logout` (clear tokens). | `coding-proxy auth login -p github` |
98
99
  | `status` | **Check proxy health.** Shows circuit breaker states (OPEN/CLOSED) and quota status across all tiers. | `coding-proxy status` |
99
100
  | `usage` | **Token Stats Dashboard.** Stalks every single token consumed, failovers triggered, and latency across day/vendor/model dimensions. | `coding-proxy usage -d 7 -v anthropic` |
100
101
  | `reset` | **The emergency flush button.** Force-reset all circuit breakers and quotas instantly when you've confirmed the main vendor is back from the dead. | `coding-proxy reset` |
@@ -126,29 +127,29 @@ graph RL
126
127
  subgraph NTier["N-tier"]
127
128
  direction TB
128
129
 
129
- subgraph Tier0 ["Tier 0: Anthropic"]
130
+ subgraph Tier0 ["Tier 0: Zhipu"]
130
131
  direction RL
131
- G0{"CB / Quota"}:::gateway -- "✅ Pass" --> API0(("Anthropic API")):::api
132
+ G0{"CB / Quota"}:::gateway -- "✅ Pass" --> API0(("GLM API")):::api
132
133
  end
133
134
 
134
- subgraph Tier1 ["Tier 1: GitHub Copilot"]
135
+ subgraph Tier1 ["Tier 1: Anthropic"]
135
136
  direction RL
136
- G1{"CB / Quota"}:::gateway -- "✅ Pass" --> API1(("Copilot API")):::api
137
+ G1{"CB / Quota"}:::gateway -- "✅ Pass" --> API1(("Anthropic API")):::api
137
138
  end
138
139
 
139
- subgraph Tier2 ["Tier 2: Google Antigravity"]
140
+ subgraph Tier2 ["Tier 2: GitHub Copilot"]
140
141
  direction RL
141
- G2{"CB / Quota"}:::gateway -- "✅ Pass" --> API2(("Gemini API")):::api
142
+ G2{"CB / Quota"}:::gateway -- "✅ Pass" --> API2(("Copilot API")):::api
142
143
  end
143
144
 
144
- subgraph TierN ["Tier N: Zhipu"]
145
+ subgraph Tier3 ["Tier 3: Google Antigravity"]
145
146
  direction RL
146
- APIN(("GLM API")):::fallback
147
+ API3(("Gemini API")):::fallback
147
148
  end
148
149
 
149
150
  Tier0 -. "❌ Blocked / API Error" .-> Tier1
150
151
  Tier1 -. "❌ Blocked / API Error" .-> Tier2
151
- Tier2 -. "🆘 Safety Net Downgrade" .-> TierN
152
+ Tier2 -. "🆘 Safety Net Downgrade" .-> Tier3
152
153
  end
153
154
 
154
155
  end
@@ -0,0 +1,259 @@
1
+ # 配置字段参考
2
+
3
+ > **路径约定**:本文档中模块路径均相对于 `src/coding/proxy/`。
4
+ >
5
+ > **定位**:本文档是所有配置参数的**规范来源(Single Source of Truth)**。设计模式章节和模块详情中引用参数默认值时,统一链接至此。
6
+
7
+ [TOC]
8
+
9
+ ---
10
+
11
+ ## 1. 配置模块结构
12
+
13
+ 配置模型已从单体 `schema.py` 正交拆分为 5 个子模块:
14
+
15
+ | 子模块 | 文件 | 核心类型 |
16
+ | --------------- | ----------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
17
+ | **server** | [`config/server.py`](../../src/coding/proxy/config/server.py) | `ServerConfig`, `DatabaseConfig`, `LoggingConfig` |
18
+ | **vendors** | [`config/vendors.py`](../../src/coding/proxy/config/vendors.py) | `AnthropicConfig`, `CopilotConfig`, `AntigravityConfig`, `ZhipuConfig`, `MinimaxConfig`, `KimiConfig`, `DoubaoConfig`, `XiaomiConfig`, `AlibabaConfig` |
19
+ | **resiliency** | [`config/resiliency.py`](../../src/coding/proxy/config/resiliency.py) | `CircuitBreakerConfig`, `RetryConfig`, `FailoverConfig`, `QuotaGuardConfig` |
20
+ | **routing** | [`config/routing.py`](../../src/coding/proxy/config/routing.py) | `VendorType`, `VendorConfig`, `ModelMappingRule`, `ModelPricingEntry` |
21
+ | **auth_schema** | [`config/auth_schema.py`](../../src/coding/proxy/config/auth_schema.py) | `AuthConfig` |
22
+
23
+ `config/schema.py` 作为聚合入口点 re-export 所有符号,并保留 `ProxyConfig` 顶层模型及旧格式迁移逻辑。
24
+
25
+ ---
26
+
27
+ ## 2. 配置搜索优先级
28
+
29
+ [`config/loader.py`](../../src/coding/proxy/config/loader.py) 按以下顺序搜索配置文件:
30
+
31
+ ```mermaid
32
+ flowchart TD
33
+ A["CLI --config 参数<br/>(显式指定)"] -->|"未指定"| B["./config.yaml<br/>(项目根目录)"]
34
+ B -->|"不存在"| C["~/.coding-proxy/config.yaml<br/>(用户目录)"]
35
+ C -->|"不存在"| D["Pydantic 默认值"]
36
+
37
+ style A fill:#1a5276,color:#fff
38
+ style D fill:#7b241c,color:#fff
39
+ ```
40
+
41
+ **环境变量展开**:语法 `${VARIABLE_NAME}`,递归处理 dict/list/str,未定义变量保留原文。
42
+
43
+ ---
44
+
45
+ ## 3. 服务器配置
46
+
47
+ ### 3.1 ServerConfig
48
+
49
+ | 字段 | 类型 | 默认值 | 说明 |
50
+ | ------ | ---- | ------------- | -------- |
51
+ | `host` | str | `"127.0.0.1"` | 监听地址 |
52
+ | `port` | int | `8046` | 监听端口 |
53
+
54
+ ### 3.2 DatabaseConfig
55
+
56
+ | 字段 | 类型 | 默认值 | 说明 |
57
+ | -------------------------- | ---- | ----------------------------- | --------------------- |
58
+ | `path` | str | `"~/.coding-proxy/usage.db"` | SQLite 数据库文件路径 |
59
+ | `compat_state_path` | str | `"~/.coding-proxy/compat.db"` | 兼容性会话存储路径 |
60
+ | `compat_state_ttl_seconds` | int | `86400` | 兼容性会话 TTL(秒) |
61
+
62
+ ### 3.3 LoggingConfig
63
+
64
+ | 字段 | 类型 | 默认值 | 说明 |
65
+ | -------------- | ----------- | --------- | ---------------------------------------- |
66
+ | `level` | str | `"INFO"` | 控制台日志级别 |
67
+ | `file` | str \| null | `null` | 文件日志路径(`null` 时输出到控制台) |
68
+ | `max_bytes` | int | `5242880` | 单个日志文件最大字节数(5 MB),触发轮转 |
69
+ | `backup_count` | int | `5` | 保留的已压缩备份文件数 |
70
+
71
+ ### 3.4 AuthConfig
72
+
73
+ | 字段 | 类型 | 默认值 | 说明 |
74
+ | ------------------ | ---- | ------ | ------------------------------------ |
75
+ | `token_store_path` | str | `""` | Token Store 文件路径(空则使用默认) |
76
+
77
+ ---
78
+
79
+ ## 4. VendorConfig 通用字段
80
+
81
+ | 字段 | 类型 | 默认值 | 说明 |
82
+ | ------------ | ---- | -------- | -------------------------------------------------------------------------------------------------------------------- |
83
+ | `vendor` | enum | -- | 供应商类型:`anthropic` / `copilot` / `antigravity` / `zhipu` / `minimax` / `kimi` / `doubao` / `xiaomi` / `alibaba` |
84
+ | `enabled` | bool | `true` | 是否启用 |
85
+ | `base_url` | str | `""` | API 基础 URL(留空使用各供应商默认值) |
86
+ | `timeout_ms` | int | `300000` | 请求超时(毫秒) |
87
+
88
+ ---
89
+
90
+ ## 5. VendorConfig 弹性字段
91
+
92
+ | 字段 | 类型 | 默认值 | 说明 |
93
+ | -------------------- | -------------- | -------------------- | --------------------------- |
94
+ | `circuit_breaker` | config \| None | `None` | 熔断器配置(None = 终端层) |
95
+ | `retry` | config | `RetryConfig()` | 重试策略配置 |
96
+ | `quota_guard` | config | `QuotaGuardConfig()` | 日度配额守卫配置 |
97
+ | `weekly_quota_guard` | config | `QuotaGuardConfig()` | 周度配额守卫配置 |
98
+
99
+ <a id="elastic-params"></a>
100
+
101
+ ### 5.1 CircuitBreakerConfig — 熔断器参数
102
+
103
+ > **设计语义**:参见 [设计模式 -- Circuit Breaker](./design-patterns.md#circuit-breaker)
104
+
105
+ | 字段 | 类型 | 默认值 | 说明 |
106
+ | -------------------------- | ---- | ------ | --------------------------------- |
107
+ | `failure_threshold` | int | `3` | 触发 OPEN 的连续失败次数 |
108
+ | `recovery_timeout_seconds` | int | `300` | OPEN → HALF_OPEN 等待秒数 |
109
+ | `success_threshold` | int | `2` | HALF_OPEN → CLOSED 所需连续成功数 |
110
+ | `max_recovery_seconds` | int | `3600` | 指数退避最大恢复时间(秒) |
111
+
112
+ ### 5.2 QuotaGuardConfig — 配额守卫参数
113
+
114
+ > **设计语义**:参见 [设计模式 -- QuotaGuard State Machine](./design-patterns.md#quota-guard)
115
+
116
+ | 字段 | 类型 | 默认值 | 说明 |
117
+ | ------------------------ | ----- | ------- | ------------------------------------ |
118
+ | `enabled` | bool | `false` | 是否启用配额守卫 |
119
+ | `token_budget` | int | `0` | 滑动窗口内的 Token 预算上限 |
120
+ | `window_hours` | float | `5.0` | 滑动窗口大小(小时) |
121
+ | `threshold_percent` | float | `99.0` | 触发 QUOTA_EXCEEDED 的用量百分比阈值 |
122
+ | `probe_interval_seconds` | int | `300` | QUOTA_EXCEEDED 状态下探测间隔(秒) |
123
+
124
+ ### 5.3 RetryConfig — 重试策略参数
125
+
126
+ > **设计语义**:参见 [设计模式 -- Retry with Full Jitter](./design-patterns.md#retry)
127
+
128
+ | 字段 | 类型 | 默认值 | 说明 |
129
+ | -------------------- | ----- | ------ | ---------------- |
130
+ | `max_retries` | int | `2` | 最大重试次数 |
131
+ | `initial_delay_ms` | int | `500` | 初始延迟(毫秒) |
132
+ | `max_delay_ms` | int | `5000` | 最大延迟(毫秒) |
133
+ | `backoff_multiplier` | float | `2.0` | 退避倍数 |
134
+ | `jitter` | bool | `true` | 是否启用抖动 |
135
+
136
+ ### 5.4 FailoverConfig — 故障转移参数
137
+
138
+ > **设计语义**:参见 [请求生命周期 -- 故障转移判定](../framework.md#fault-overhead)
139
+
140
+ | 字段 | 类型 | 默认值 |
141
+ | ------------------------ | --------- | ---------------------------------------------------------------------------------- |
142
+ | `status_codes` | list[int] | `[429, 403, 503, 500, 529]` |
143
+ | `error_types` | list[str] | `["rate_limit_error", "overloaded_error", "api_error"]` |
144
+ | `error_message_patterns` | list[str] | `["quota", "limit exceeded", "usage cap", "capacity", "internal network failure"]` |
145
+
146
+ ---
147
+
148
+ ## 6. 供应商专属字段
149
+
150
+ ### 6.1 Copilot 专属字段
151
+
152
+ | 字段 | 类型 | 默认值 | 说明 |
153
+ | -------------------------- | ---- | --------------- | -------------------------------------------------- |
154
+ | `github_token` | str | `""` | GitHub OAuth token / PAT(支持 `${ENV_VAR}`) |
155
+ | `account_type` | str | `"individual"` | 账号类型:`individual` / `business` / `enterprise` |
156
+ | `token_url` | str | `"https://..."` | Token 交换端点 |
157
+ | `models_cache_ttl_seconds` | int | `300` | 模型列表缓存 TTL |
158
+
159
+ ### 6.2 Antigravity 专属字段
160
+
161
+ | 字段 | 类型 | 默认值 | 说明 |
162
+ | ---------------- | ---- | ----------------------------------- | --------------------------- |
163
+ | `client_id` | str | `""` | Google OAuth2 Client ID |
164
+ | `client_secret` | str | `""` | Google OAuth2 Client Secret |
165
+ | `refresh_token` | str | `""` | Google OAuth2 Refresh Token |
166
+ | `model_endpoint` | str | `"models/claude-sonnet-4-20250514"` | Gemini 模型端点路径 |
167
+
168
+ ### 6.3 原生 Anthropic 兼容供应商共用字段
169
+
170
+ 适用于 `zhipu` / `minimax` / `kimi` / `doubao` / `xiaomi` / `alibaba`。
171
+
172
+ | 字段 | 类型 | 默认值 | 说明 |
173
+ | --------- | ---- | ------ | ---------------------------- |
174
+ | `api_key` | str | `""` | API Key(支持 `${ENV_VAR}`) |
175
+
176
+ ---
177
+
178
+ ## 7. 模型映射规则
179
+
180
+ ### 7.1 ModelMappingRule 字段
181
+
182
+ | 字段 | 类型 | 说明 |
183
+ | ---------- | --------- | ------------------------------------------ |
184
+ | `pattern` | str | 匹配模式(精确/通配符/正则) |
185
+ | `target` | str | 目标模型名称 |
186
+ | `is_regex` | bool | 是否为正则表达式(默认 `false`) |
187
+ | `vendors` | list[str] | 规则作用域(留空应用于所有原生兼容供应商) |
188
+
189
+ ### 7.2 ModelPricingEntry 字段
190
+
191
+ | 字段 | 类型 | 说明 |
192
+ | --------------------------- | ----- | -------------------------------------------------- |
193
+ | `vendor` | str | 供应商名称 |
194
+ | `model` | str | 实际模型名 |
195
+ | `input_cost_per_mtok` | float | 输入 Token 单价($/百万 token,支持 `$`/`¥` 前缀) |
196
+ | `output_cost_per_mtok` | float | 输出 Token 单价 |
197
+ | `cache_write_cost_per_mtok` | float | 缓存创建 Token 单价 |
198
+ | `cache_read_cost_per_mtok` | float | 缓存读取 Token 单价 |
199
+
200
+ ---
201
+
202
+ ## 8. tiers — 显式优先级
203
+
204
+ | 字段 | 类型 | 说明 |
205
+ | ------- | ------------------------ | ------------------------------------------ |
206
+ | `tiers` | list[VendorType] \| None | 降级链路优先级(None 时回退 vendors 顺序) |
207
+
208
+ ---
209
+
210
+ ## 9. vendors 列表格式(推荐)
211
+
212
+ 推荐使用 `vendors` 列表格式,每个 vendor 自包含其弹性配置:
213
+
214
+ ```yaml
215
+ vendors:
216
+ - vendor: anthropic
217
+ enabled: true
218
+ base_url: https://api.anthropic.com
219
+ timeout_ms: 300000
220
+ circuit_breaker:
221
+ failure_threshold: 3
222
+ recovery_timeout_seconds: 300
223
+ quota_guard:
224
+ enabled: false
225
+ weekly_quota_guard:
226
+ enabled: false
227
+
228
+ - vendor: copilot
229
+ enabled: false
230
+ github_token: "${GITHUB_TOKEN}"
231
+ account_type: individual
232
+ circuit_breaker:
233
+ failure_threshold: 3
234
+ quota_guard:
235
+ enabled: true
236
+ token_budget: 3000000
237
+ window_hours: 4.0
238
+
239
+ - vendor: zhipu
240
+ enabled: true
241
+ api_key: "${ZHIPU_API_KEY}"
242
+ # 无 circuit_breaker -> 终端层
243
+
244
+ - vendor: minimax
245
+ enabled: false
246
+ api_key: "${MINIMAX_API_KEY}"
247
+
248
+ tiers: [anthropic, copilot, zhipu] # 显式优先级(可选)
249
+ ```
250
+
251
+ ### Legacy Flat 格式(向后兼容)
252
+
253
+ 旧的 flat 格式字段(`primary`/`copilot`/`antigravity`/`fallback`/`circuit_breaker`/`*_quota_guard`)仍受支持,通过 `ProxyConfig._migrate_legacy_fields()` 自动迁移为 vendors 列表格式。
254
+
255
+ 迁移规则:
256
+ 1. `anthropic` 字段名 → `primary`
257
+ 2. `zhipu` 字段名 → `fallback`
258
+ 3. 若无 `vendors` 字段,从 legacy flat 字段自动生成 vendors 列表
259
+ 4. 迁移时发出 INFO 日志建议迁移至新格式
@@ -0,0 +1,101 @@
1
+ # 格式转换模块(convert/)
2
+
3
+ > **路径约定**:本文档中模块路径均相对于 `src/coding/proxy/`。
4
+ >
5
+ > **定位**:从 `framework.md` 提取,详述 Anthropic ↔ Gemini ↔ OpenAI 三向格式转换。
6
+
7
+ [TOC]
8
+
9
+ ---
10
+
11
+ ## 1. 模块总览
12
+
13
+ [`convert/`](../../src/coding/proxy/convert/) 模块提供独立的纯函数适配器层,支持三向格式转换:
14
+
15
+ | 转换方向 | 模块 | 说明 |
16
+ | -------------------------- | ----------------------------------------------------------------------------------------- | ------------------ |
17
+ | Anthropic → Gemini | [`convert/anthropic_to_gemini.py`](../../src/coding/proxy/convert/anthropic_to_gemini.py) | 请求格式转换 |
18
+ | Gemini → Anthropic | [`convert/gemini_to_anthropic.py`](../../src/coding/proxy/convert/gemini_to_anthropic.py) | 响应格式转换 |
19
+ | Gemini SSE → Anthropic SSE | [`convert/gemini_sse_adapter.py`](../../src/coding/proxy/convert/gemini_sse_adapter.py) | 流式事件重构 |
20
+ | Anthropic → OpenAI | [`convert/anthropic_to_openai.py`](../../src/coding/proxy/convert/anthropic_to_openai.py) | Copilot 请求适配 |
21
+ | OpenAI → Anthropic | [`convert/openai_to_anthropic.py`](../../src/coding/proxy/convert/openai_to_anthropic.py) | Copilot 响应逆适配 |
22
+
23
+ ---
24
+
25
+ ## 2. 请求转换(Anthropic → Gemini)
26
+
27
+ **应用位置**:[`convert/anthropic_to_gemini.py`](../../src/coding/proxy/convert/anthropic_to_gemini.py) -- `convert_request()`
28
+
29
+ **转换映射**:
30
+
31
+ | Anthropic 字段 | Gemini 字段 | 说明 |
32
+ | --------------------------------- | ---------------------------------- | ------------------------------------------------ |
33
+ | `system`(str \| list) | `systemInstruction.parts[].text` | 支持字符串和文本块列表两种格式 |
34
+ | `messages[]` | `contents[]` | 角色映射:`assistant` → `model`,`user` → `user` |
35
+ | `content`(text) | `parts[].text` | 文本内容块 |
36
+ | `content`(image) | `parts[].inlineData` | Base64 数据 + MIME 类型 |
37
+ | `content`(tool_use) | `parts[].functionCall` | `name` + `input` → `args` |
38
+ | `content`(tool_result) | `parts[].functionResponse` | `tool_use_id` → `name`,`content` → `result` |
39
+ | `max_tokens` | `generationConfig.maxOutputTokens` | |
40
+ | `temperature` / `top_p` / `top_k` | `generationConfig.*` | 参数名驼峰转换 |
41
+ | `stop_sequences` | `generationConfig.stopSequences` | |
42
+
43
+ **不支持的字段**(静默剥离并记录 WARNING):`tools`、`tool_choice`、`metadata`、`extended_thinking`、`thinking`
44
+
45
+ ---
46
+
47
+ ## 3. 响应转换(Gemini → Anthropic)
48
+
49
+ **应用位置**:[`convert/gemini_to_anthropic.py`](../../src/coding/proxy/convert/gemini_to_anthropic.py) -- `convert_response()` / `extract_usage()`
50
+
51
+ **finishReason 映射**:
52
+
53
+ | Gemini | Anthropic |
54
+ | --------------------------------- | ------------ |
55
+ | `STOP` | `end_turn` |
56
+ | `MAX_TOKENS` | `max_tokens` |
57
+ | `SAFETY` / `RECITATION` / `OTHER` | `end_turn` |
58
+
59
+ **Parts 转换**:
60
+ - `text` → `{"type": "text", "text": "..."}`
61
+ - `functionCall` → `{"type": "tool_use", "id": "toolu_...", "name": "...", "input": {...}}`
62
+
63
+ **Usage 提取**:
64
+ - `usageMetadata.promptTokenCount` → `input_tokens`
65
+ - `usageMetadata.candidatesTokenCount` → `output_tokens`
66
+ - 缓存字段填 0(Gemini 不直接暴露缓存信息)
67
+
68
+ ---
69
+
70
+ ## 4. SSE 流适配
71
+
72
+ **应用位置**:[`convert/gemini_sse_adapter.py`](../../src/coding/proxy/convert/gemini_sse_adapter.py) -- `adapt_sse_stream()`
73
+
74
+ 将 Gemini SSE 流重构为 Anthropic 消息生命周期事件序列:
75
+
76
+ ```mermaid
77
+ flowchart LR
78
+ Input["Gemini SSE chunks"] --> MS["message_start<br/>← 首次收到内容时发出"]
79
+ MS --> CBS["content_block_start<br/>← 内容块开始"]
80
+ CBS --> CBD["content_block_delta*<br/>← 增量文本"]
81
+ CBD --> CBS2["content_block_stop<br/>← 内容块结束"]
82
+ CBS2 --> MD["message_delta<br/>← stop_reason + output_tokens"]
83
+ MD --> MSP["message_stop<br/>← 消息结束"]
84
+
85
+ style Input fill:#1a5276,color:#fff
86
+ style MSP fill:#196f3d,color:#fff
87
+ ```
88
+
89
+ **边界情况处理**:
90
+ - 空 parts 后跟有 text 的 chunk → 延迟发出 `message_start` + `content_block_start`
91
+ - 流结束但未收到 `finishReason` → 补发默认 `message_delta`(`stop_reason: "end_turn"`)+ `message_stop`
92
+
93
+ ---
94
+
95
+ ## 5. OpenAI 格式转换
96
+
97
+ **应用位置**:
98
+ - [`convert/anthropic_to_openai.py`](../../src/coding/proxy/convert/anthropic_to_openai.py) -- Anthropic → OpenAI Chat Completions 请求格式
99
+ - [`convert/openai_to_anthropic.py`](../../src/coding/proxy/convert/openai_to_anthropic.py) -- OpenAI Chat Completions → Anthropic 响应格式
100
+
101
+ 专为 CopilotVendor 适配,处理 Anthropic Messages API 与 OpenAI Chat Completions API 之间的双向格式差异(角色映射、工具格式、usage 字段名等)。