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.
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/AGENTS.md +2 -1
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/CHANGELOG.md +19 -10
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/PKG-INFO +1 -1
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/pyproject.toml +1 -1
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/config/config.default.yaml +3 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/routing/model_mapper.py +0 -20
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/routing/usage_parser.py +0 -30
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/server/dashboard.py +5 -4
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_model_mapper.py +0 -18
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_parse_usage.py +0 -62
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/uv.lock +1 -1
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/.github/workflows/ci.yml +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/.github/workflows/coverage.yml +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/.github/workflows/release.yml +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/.gitignore +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/.pre-commit-config.yaml +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/CLAUDE.md +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/LICENSE +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/README.md +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/assets/dashboard-v0.2.4.png +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/docs/arch/config-reference.md +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/docs/arch/convert.md +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/docs/arch/design-patterns.md +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/docs/arch/routing.md +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/docs/arch/testing.md +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/docs/arch/vendors.md +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/docs/ci-cd.md +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/docs/framework.md +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/docs/guide/api-reference.md +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/docs/guide/cli-reference.md +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/docs/guide/dashboard.md +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/docs/guide/monitoring.md +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/docs/guide/quickstart.md +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/docs/guide/vendors.md +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/docs/user-guide.md +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/docs/zh-CN/README.md +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/__init__.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/__init__.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/__main__.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/auth/__init__.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/auth/providers/__init__.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/auth/providers/base.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/auth/providers/github.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/auth/providers/google.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/auth/runtime.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/auth/store.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/cli/__init__.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/cli/auth_commands.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/cli/banner.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/compat/__init__.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/compat/canonical.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/compat/session_store.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/config/__init__.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/config/auth_schema.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/config/loader.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/config/resiliency.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/config/routing.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/config/schema.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/config/server.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/config/vendors.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/convert/__init__.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/convert/anthropic_to_gemini.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/convert/anthropic_to_openai.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/convert/gemini_sse_adapter.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/convert/gemini_to_anthropic.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/convert/openai_to_anthropic.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/convert/vendor_channels.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/logging/__init__.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/logging/db.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/logging/formatters.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/logging/stats.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/model/__init__.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/model/auth.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/model/compat.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/model/constants.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/model/pricing.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/model/token.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/model/vendor.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/native_api/__init__.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/native_api/config.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/native_api/extractors/__init__.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/native_api/extractors/anthropic.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/native_api/extractors/gemini.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/native_api/extractors/openai.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/native_api/handler.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/native_api/operation.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/native_api/routes.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/native_api/usage_registry.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/pricing.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/routing/__init__.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/routing/circuit_breaker.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/routing/error_classifier.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/routing/executor.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/routing/quota_guard.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/routing/rate_limit.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/routing/retry.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/routing/router.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/routing/session_manager.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/routing/tier.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/routing/usage_recorder.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/server/__init__.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/server/app.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/server/factory.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/server/responses.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/server/routes.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/streaming/__init__.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/streaming/anthropic_compat.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/vendors/__init__.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/vendors/alibaba.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/vendors/anthropic.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/vendors/antigravity.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/vendors/base.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/vendors/copilot.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/vendors/copilot_models.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/vendors/copilot_token_manager.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/vendors/copilot_urls.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/vendors/doubao.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/vendors/kimi.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/vendors/minimax.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/vendors/mixins.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/vendors/native_anthropic.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/vendors/token_manager.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/vendors/xiaomi.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/vendors/zhipu.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/__init__.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_antigravity.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_app_routes.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_auto_login.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_banner.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_circuit_breaker.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_cli_usage.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_compat.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_config_init.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_config_loader.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_convert_request.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_convert_response.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_convert_sse.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_copilot.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_copilot_convert_request.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_copilot_convert_response.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_copilot_models.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_copilot_urls.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_currency.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_error_classifier.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_logging_dual_write.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_mixins.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_model_auth.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_model_compat.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_model_constants.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_model_pricing.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_model_token.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_model_vendor.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_native_api_base_url_override.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_native_api_extractors.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_native_api_handler.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_native_api_operation.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_native_api_routes.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_native_vendors.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_parse_usage_gemini.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_pricing.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_quota_guard.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_rate_limit.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_router_chain.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_router_executor.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_runtime_reauth.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_schema.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_streaming_anthropic_compat.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_tier.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_tiers_config.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_time_range.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_token_logger.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_token_logger_native_columns.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_token_manager.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_types.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_vendor_channels.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_vendor_streaming.py +0 -0
- {coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/tests/test_vendors.py +0 -0
- {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
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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.
|
|
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.
|
|
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 (
|
|
708
|
+
if (visiblePoints.length) {
|
|
708
709
|
html += '<div id="chart-tooltip-items">';
|
|
709
|
-
|
|
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 &&
|
|
726
|
-
const total =
|
|
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
|
-
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/convert/anthropic_to_gemini.py
RENAMED
|
File without changes
|
{coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/convert/anthropic_to_openai.py
RENAMED
|
File without changes
|
{coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/convert/gemini_sse_adapter.py
RENAMED
|
File without changes
|
{coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/convert/gemini_to_anthropic.py
RENAMED
|
File without changes
|
{coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/convert/openai_to_anthropic.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/native_api/extractors/__init__.py
RENAMED
|
File without changes
|
{coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/native_api/extractors/anthropic.py
RENAMED
|
File without changes
|
{coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/native_api/extractors/gemini.py
RENAMED
|
File without changes
|
{coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/native_api/extractors/openai.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/streaming/anthropic_compat.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{coding_proxy-0.3.0a3 → coding_proxy-0.3.1a1}/src/coding/proxy/vendors/copilot_token_manager.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|