coding-proxy 0.3.0a3__tar.gz → 0.3.1a2__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.
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/AGENTS.md +2 -1
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/CHANGELOG.md +29 -10
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/PKG-INFO +9 -1
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/README.md +8 -0
- coding_proxy-0.3.1a2/docs/issue.md +99 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/docs/zh-CN/README.md +8 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/pyproject.toml +1 -1
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/config/config.default.yaml +3 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/convert/vendor_channels.py +281 -38
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/routing/error_classifier.py +14 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/routing/executor.py +13 -11
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/routing/model_mapper.py +0 -20
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/routing/usage_parser.py +0 -30
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/server/dashboard.py +5 -4
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_error_classifier.py +38 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_model_mapper.py +0 -18
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_parse_usage.py +0 -62
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_router_executor.py +205 -15
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_vendor_channels.py +1047 -25
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/uv.lock +1 -1
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/.github/workflows/ci.yml +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/.github/workflows/coverage.yml +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/.github/workflows/release.yml +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/.gitignore +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/.pre-commit-config.yaml +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/CLAUDE.md +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/LICENSE +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/assets/dashboard-v0.2.4.png +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/docs/arch/config-reference.md +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/docs/arch/convert.md +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/docs/arch/design-patterns.md +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/docs/arch/routing.md +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/docs/arch/testing.md +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/docs/arch/vendors.md +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/docs/ci-cd.md +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/docs/framework.md +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/docs/guide/api-reference.md +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/docs/guide/cli-reference.md +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/docs/guide/dashboard.md +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/docs/guide/monitoring.md +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/docs/guide/quickstart.md +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/docs/guide/vendors.md +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/docs/user-guide.md +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/__init__.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/__init__.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/__main__.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/auth/__init__.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/auth/providers/__init__.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/auth/providers/base.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/auth/providers/github.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/auth/providers/google.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/auth/runtime.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/auth/store.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/cli/__init__.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/cli/auth_commands.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/cli/banner.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/compat/__init__.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/compat/canonical.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/compat/session_store.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/config/__init__.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/config/auth_schema.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/config/loader.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/config/resiliency.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/config/routing.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/config/schema.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/config/server.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/config/vendors.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/convert/__init__.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/convert/anthropic_to_gemini.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/convert/anthropic_to_openai.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/convert/gemini_sse_adapter.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/convert/gemini_to_anthropic.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/convert/openai_to_anthropic.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/logging/__init__.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/logging/db.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/logging/formatters.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/logging/stats.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/model/__init__.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/model/auth.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/model/compat.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/model/constants.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/model/pricing.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/model/token.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/model/vendor.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/native_api/__init__.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/native_api/config.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/native_api/extractors/__init__.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/native_api/extractors/anthropic.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/native_api/extractors/gemini.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/native_api/extractors/openai.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/native_api/handler.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/native_api/operation.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/native_api/routes.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/native_api/usage_registry.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/pricing.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/routing/__init__.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/routing/circuit_breaker.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/routing/quota_guard.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/routing/rate_limit.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/routing/retry.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/routing/router.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/routing/session_manager.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/routing/tier.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/routing/usage_recorder.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/server/__init__.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/server/app.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/server/factory.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/server/responses.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/server/routes.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/streaming/__init__.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/streaming/anthropic_compat.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/vendors/__init__.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/vendors/alibaba.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/vendors/anthropic.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/vendors/antigravity.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/vendors/base.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/vendors/copilot.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/vendors/copilot_models.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/vendors/copilot_token_manager.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/vendors/copilot_urls.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/vendors/doubao.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/vendors/kimi.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/vendors/minimax.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/vendors/mixins.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/vendors/native_anthropic.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/vendors/token_manager.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/vendors/xiaomi.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/src/coding/proxy/vendors/zhipu.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/__init__.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_antigravity.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_app_routes.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_auto_login.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_banner.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_circuit_breaker.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_cli_usage.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_compat.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_config_init.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_config_loader.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_convert_request.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_convert_response.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_convert_sse.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_copilot.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_copilot_convert_request.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_copilot_convert_response.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_copilot_models.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_copilot_urls.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_currency.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_logging_dual_write.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_mixins.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_model_auth.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_model_compat.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_model_constants.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_model_pricing.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_model_token.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_model_vendor.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_native_api_base_url_override.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_native_api_extractors.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_native_api_handler.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_native_api_operation.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_native_api_routes.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_native_vendors.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_parse_usage_gemini.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_pricing.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_quota_guard.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_rate_limit.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_router_chain.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_runtime_reauth.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_schema.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_streaming_anthropic_compat.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_tier.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_tiers_config.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_time_range.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_token_logger.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_token_logger_native_columns.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_token_manager.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_types.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_vendor_streaming.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/tests/test_vendors.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a2}/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,35 @@
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
-
|
|
14
|
-
- fix(
|
|
15
|
-
-
|
|
16
|
-
|
|
7
|
+
- fix(vendor-channels): 新增 zhipu 同 vendor 自清理通道,修复 GLM-5 自循环 400 + tool_results 偶发降级;
|
|
8
|
+
- fix(vendor-channels): 修复 `_rewrite_srvtoolu_ids` 块顺序敏感性导致 inline tool_result 漏改名,进而 enforce 阶段 dict key 与 tool_use_ids 错位、anthropic 报 `tool_use ids without tool_result blocks immediately after` 的 cascade failover 问题(改为两遍扫描:先收集 id_map,再统一改写所有 tool_result.tool_use_id 引用);
|
|
9
|
+
- fix(vendor-channels): `enforce_anthropic_tool_pairing` 增加全局 sanity check pass,主循环边角错位让 dangling tool_use 漏过校验时兜底合成 is_error 占位并打 `pairing_sanity_repaired` 标签,避免 anthropic 二次报错;
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
- fix(vendor-channels): 新增 `anthropic → zhipu` 跨供应商转换通道,修复 Anthropic beta 功能(web search, computer use)产生的 `server_tool_use` 块导致 zhipu 400 错误的问题;
|
|
14
|
+
- fix(error-classifier): 增强语义拒绝检测,识别 zhipu 等供应商返回的中文错误消息(如「API 调用参数有误」code=1210),确保正确触发故障转移;
|
|
15
|
+
- fix(vendor-channels): `_remove_vendor_blocks` 增加空内容占位保护,防止内容块全部剥离后消息结构不合法。
|
|
16
|
+
|
|
17
|
+
## [v0.3.0](https://github.com/ThreeFish-AI/coding-proxy/releases/tag/v0.3.0) — 2026-04-20
|
|
18
|
+
|
|
19
|
+
> [!IMPORTANT]
|
|
20
|
+
>
|
|
21
|
+
> **🚀 OpenAI、Anthropic、Gemini 原生 API 进驻 Coding Proxy!**
|
|
22
|
+
>
|
|
23
|
+
> 服务对象不在局限 Claude Code,凡兼容 OpenAI、Anthropic、Gemini 三巨头 API 协议的客户端,出口 LLM 流量可统一收敛到 Coding Proxy。
|
|
24
|
+
|
|
25
|
+
### ✨ 核心亮点
|
|
26
|
+
|
|
27
|
+
- feat(native-api): 新增 `/api/{openai,gemini,anthropic}/**` 原生 LLM API 全量 catch-all 透传通道;
|
|
28
|
+
- feat(dashboard): 新增实时 Web Dashboard 页面,聚合展示流量与用量统计;
|
|
29
|
+
- feat(usage): `usage` 区分 Claude Code 场景(`'cc'`)与原生 API 场景(`'api'`);
|
|
30
|
+
- refactor(vendor-channels): 将供应商转换通道从目标专属重构为源→目标绑定模型;
|
|
31
|
+
- docs(user-guide): 补充 POST /v1/messages 完整 API 参考文档;
|
|
32
|
+
|
|
33
|
+
### 🔧 更多特性
|
|
34
|
+
|
|
35
|
+
- feat(server): 默认监听端口 `8046` → `3392`,规范化 [Negentropy](https://github.com/ThreeFish-AI/negentropy) 体系端口;
|
|
17
36
|
|
|
18
37
|
## [v0.2.3](https://github.com/ThreeFish-AI/coding-proxy/releases/tag/v0.2.3) — 2026-04-16
|
|
19
38
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: coding-proxy
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.1a2
|
|
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
|
|
@@ -113,6 +113,14 @@ export ANTHROPIC_BASE_URL=http://127.0.0.1:3392
|
|
|
113
113
|
claude
|
|
114
114
|
```
|
|
115
115
|
|
|
116
|
+
### 5. Peek at the Dashboard
|
|
117
|
+
|
|
118
|
+
Curious about your real-time token spend, latency, and circuit breaker pulse? Pop open your browser and head to:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
open http://127.0.0.1:3392/dashboard
|
|
122
|
+
```
|
|
123
|
+
|
|
116
124
|
---
|
|
117
125
|
|
|
118
126
|
## 🛠️ The CLI Console Guide
|
|
@@ -86,6 +86,14 @@ export ANTHROPIC_BASE_URL=http://127.0.0.1:3392
|
|
|
86
86
|
claude
|
|
87
87
|
```
|
|
88
88
|
|
|
89
|
+
### 5. Peek at the Dashboard
|
|
90
|
+
|
|
91
|
+
Curious about your real-time token spend, latency, and circuit breaker pulse? Pop open your browser and head to:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
open http://127.0.0.1:3392/dashboard
|
|
95
|
+
```
|
|
96
|
+
|
|
89
97
|
---
|
|
90
98
|
|
|
91
99
|
## 🛠️ The CLI Console Guide
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# Issue 处理档案
|
|
2
|
+
|
|
3
|
+
> 维护已处理过的 Issue 摘要(问题描述、表因根因、处理方式、后续防范、同类问题影响与处理注意事项),便于同类问题的跨上下文处理。识别相同 Issue 时应在原条目追加复盘,避免同 Issue 多处维护。
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## zhipu 自循环 400 + tool_results 偶发降级
|
|
8
|
+
|
|
9
|
+
**问题描述**
|
|
10
|
+
|
|
11
|
+
生产日志反复出现下述链路: 请求一开始命中 zhipu 主 tier, 但在含 `tool_results` 的多轮工具调用场景下偶发返回 400, 触发到 copilot 二级 tier。具体日志特征:
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
WARNING Tier zhipu likely format incompatibility (400 + tool_results), trying next tier without recording failure
|
|
15
|
+
WARNING Tier zhipu semantic rejection (400), trying next tier without recording failure
|
|
16
|
+
DEBUG Applied transition channel zhipu → copilot: rewritten_38_srvtoolu_ids, stripped_16_thinking_blocks, removed_3_cache_control_fields, misplaced_tool_result_relocated
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
zhipu → copilot 通道的 adaptations 列表暴露了上一轮 zhipu 响应中存在的非标准产物 (`srvtoolu_*` ID、自签 thinking、错位的 `tool_result`)。
|
|
20
|
+
|
|
21
|
+
**表因**
|
|
22
|
+
|
|
23
|
+
zhipu 自身偶发返回 400, 但错误体非 JSON 结构, 由 `_is_likely_request_format_error()` 判定为「格式不兼容」并跳过当前 tier。
|
|
24
|
+
|
|
25
|
+
**根因**
|
|
26
|
+
|
|
27
|
+
1. zhipu 是 `NativeAnthropicVendor` 薄透传供应商, **不做任何请求体预处理**。
|
|
28
|
+
2. `executor._determine_source_vendor` 三条优先级路径均以 `source != target_name` 过滤掉了同 vendor 自转换。
|
|
29
|
+
3. `VENDOR_TRANSITIONS` 注册表中无 `("zhipu", "zhipu")` 条目。
|
|
30
|
+
|
|
31
|
+
后果: GLM-5 偶发产出非标准产物 (assistant 内联 `tool_result`、`server_tool_use_delta` 流式残块) 后, Claude Code 把这些产物原样回送下一轮请求时, **没有任何清洗发生**, 直接被转发到 zhipu 自身, 命中 zhipu 端的输入校验返回 400。
|
|
32
|
+
|
|
33
|
+
**处理方式**
|
|
34
|
+
|
|
35
|
+
- 在 `vendor_channels.py` 新增 `prepare_zhipu_self_cleanup` 函数, 仅修复 zhipu 自身拒绝的两类产物:
|
|
36
|
+
1. 剥离 `server_tool_use_delta` 流式残块
|
|
37
|
+
2. `enforce_anthropic_tool_pairing` 把 assistant 内联 `tool_result` 重定位到紧随 user 消息
|
|
38
|
+
- 显式 **保留** zhipu 原生支持的特性: `srvtoolu_*` ID、`server_tool_use` 类型、自签 thinking signature、`cache_control` (cache_read 已在生产实证)、顶层 `thinking` 参数。
|
|
39
|
+
- 在 `VENDOR_TRANSITIONS` 注册 `("zhipu", "zhipu") = prepare_zhipu_self_cleanup`。
|
|
40
|
+
- 在 `executor._determine_source_vendor` 三条优先级路径中, 把「`source != target`」过滤替换为「通道已注册」门控 (`get_transition_channel(...) is not None`), 让自转换通道在显式注册时启用, 未注册时退化为原行为。
|
|
41
|
+
|
|
42
|
+
**后续防范**
|
|
43
|
+
|
|
44
|
+
- 新增 `NativeAnthropicVendor` 子类 (minimax / kimi / doubao / xiaomi / alibaba 等) 时, 若上游 vendor 偶发产出违反 Anthropic 规范的产物, 可按需注册同名自清理通道, executor 无需任何额外改动。
|
|
45
|
+
- 同 vendor 自转换通道应**精确剪裁**: 仅修复 vendor 自身拒绝的产物, 不要套用跨 vendor 通道的全量清理 (会误伤 vendor 原生支持的特性, 如 cache_control 损失带来 cache_read miss)。
|
|
46
|
+
|
|
47
|
+
**同类问题影响与处理注意事项**
|
|
48
|
+
|
|
49
|
+
- `enforce_anthropic_tool_pairing` 仅识别 `tool_use` 类型 (不含 `server_tool_use`), 因为 `server_tool_use` 由 vendor 自身执行, 不需要客户端 `tool_result`。构造测试或类似清洗逻辑时需注意此差别。
|
|
50
|
+
- `_is_likely_request_format_error()` 把「400 + tool_results + 非结构化错误体」一律标记为格式不兼容并跳过 tier 不计熔断器, 这层兜底虽能维持可用性但会**掩盖** vendor 自身的间歇性问题, 让根因更难发现。处理类似 400 偶发时, 应优先看 `Applied transition channel` 日志中的 adaptations 列表, 它能精确暴露上游响应中的非标准产物。
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## anthropic 报 messages.X tool_use 缺 tool_result (zhipu→anthropic 故障转移失败)
|
|
55
|
+
|
|
56
|
+
**问题描述**
|
|
57
|
+
|
|
58
|
+
zhipu 完成响应后, executor 故障转移至 anthropic 时反复失败 (HTTP 400):
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
DEBUG Applied transition channel zhipu → anthropic: rewritten_86_srvtoolu_ids, misplaced_tool_result_relocated, stripped_18_thinking_blocks
|
|
62
|
+
WARNING anthropic stream error: status=400 ... messages.3: `tool_use` ids were found without `tool_result` blocks immediately after: toolu_normalized_3.
|
|
63
|
+
INFO Failover: anthropic → zhipu (reason: HTTP 400)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
adaptations 列表显示 `misplaced_tool_result_relocated` 但**没有** `orphaned_tool_use_repaired`, 即 enforce 单遍扫描视角下认为所有 tool_use 都已配对; 但 anthropic 仍报 messages.X 缺 tool_result, 导致请求级 cascade failover 反复回到 zhipu。
|
|
67
|
+
|
|
68
|
+
**表因**
|
|
69
|
+
|
|
70
|
+
`prepare_zhipu_to_anthropic` 链路输出的请求体中, 某个 assistant 的 `tool_use` 在紧邻的 user 消息中没有匹配的 `tool_result` 块。
|
|
71
|
+
|
|
72
|
+
**根因**
|
|
73
|
+
|
|
74
|
+
`_rewrite_srvtoolu_ids` 采用单遍正向扫描: 在同一次循环中一边收集 srvtoolu_* → toolu_normalized_* 的 id_map, 一边改写遇到的 `tool_result.tool_use_id`。GLM-5 流式偶发将 inline tool_result 输出在本消息 `server_tool_use` 之前 (block 顺序异常), 导致:
|
|
75
|
+
|
|
76
|
+
1. 处理 inline tool_result 时, id_map 尚未填入对应 srvtoolu_* → 漏改名, inline 仍保留 `srvtoolu_X`
|
|
77
|
+
2. 处理本消息 server_tool_use 时, 填入 id_map 并把 tool_use 改名为 `toolu_normalized_X`
|
|
78
|
+
3. 进入 `enforce_anthropic_tool_pairing` 时:
|
|
79
|
+
- A 步 extracted dict key = `srvtoolu_X` (inline 保留的旧 ID)
|
|
80
|
+
- B 步 tool_use_ids = `[toolu_normalized_X]` (已改名)
|
|
81
|
+
- F 步 `uid in extracted` 检查失败 (key 错位), 但若 next user 已含其他 stale tool_result 让 existing_result_ids "巧合" 命中, F 步会跳过 synth → 不触发 orphan 标签
|
|
82
|
+
- 最终 anthropic 看到 messages.X 真的缺 toolu_normalized_X 的 tool_result → 400
|
|
83
|
+
|
|
84
|
+
**处理方式**
|
|
85
|
+
|
|
86
|
+
- `_rewrite_srvtoolu_ids` 改为**两遍扫描**: Pass 1 仅遍历 assistant 消息, 收集 id_map 并改写 tool_use 自身的 id 与 type; Pass 2 全量遍历所有消息 (含 user / 异常 assistant 内联), 统一改写所有 `tool_result.tool_use_id` 引用。彻底消除 block 顺序敏感性。
|
|
87
|
+
- `enforce_anthropic_tool_pairing` 主循环结束后追加**全局 sanity check pass**: 重新遍历每条 assistant, 验证其 tool_use_ids 全部在 next user 的 tool_result 中存在; 发现遗漏直接合成 is_error 占位并打 `pairing_sanity_repaired` 标签。作为防御深度抵御未来其他主循环边角错位。
|
|
88
|
+
- A 步对 `tool_use_id` 缺失的破损 inline tool_result 也计入 relocated_count (避免 silent drop 影响 adaptations 标签可观测性)。
|
|
89
|
+
|
|
90
|
+
**后续防范**
|
|
91
|
+
|
|
92
|
+
- 任何"按出现顺序填充字典 + 同遍引用查询"的两阶段操作都应警惕**顺序耦合**问题。两遍扫描 (collect → apply) 是消除此类 bug 的标准 pattern。
|
|
93
|
+
- 关键校验函数应有**主循环 + 全局 sanity check** 的双层结构, 单层校验在边角场景下容易被绕过。
|
|
94
|
+
- 处理 anthropic `tool_use ids without tool_result blocks immediately after` 类 cascade failover 时, **adaptations 标签能否复现日志**是定位 root cause 的强信号: 若 enforce 视角与 anthropic 视角不一致 (有 misplaced 但无 orphan, anthropic 仍报错), 必有上游 _rewrite / id 改写阶段的隐藏漏洞。
|
|
95
|
+
|
|
96
|
+
**同类问题影响与处理注意事项**
|
|
97
|
+
|
|
98
|
+
- 任何对 messages 进行 ID 重写的转换链 (如 `_rewrite_srvtoolu_ids`、`anthropic_to_openai`、`anthropic_to_gemini`) 都应使用两遍扫描或一次性收集后再批量改写, 以保证 block 顺序无关性。
|
|
99
|
+
- enforce 类校验函数若依赖 dict key 与 list 元素的**等同性**, 必须先确保两者在同一参考系下 (改名前 vs 改名后); 否则错位会以 "看起来 OK 实际有漏" 的方式静默泄漏到下游。
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "coding-proxy"
|
|
3
|
-
version = "0.3.
|
|
3
|
+
version = "0.3.1a2"
|
|
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
|