ccproxy-api 0.1.6__py3-none-any.whl → 0.2.0__py3-none-any.whl
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.
- ccproxy/api/__init__.py +1 -15
- ccproxy/api/app.py +439 -212
- ccproxy/api/bootstrap.py +30 -0
- ccproxy/api/decorators.py +85 -0
- ccproxy/api/dependencies.py +145 -176
- ccproxy/api/format_validation.py +54 -0
- ccproxy/api/middleware/cors.py +6 -3
- ccproxy/api/middleware/errors.py +402 -530
- ccproxy/api/middleware/hooks.py +563 -0
- ccproxy/api/middleware/normalize_headers.py +59 -0
- ccproxy/api/middleware/request_id.py +35 -16
- ccproxy/api/middleware/streaming_hooks.py +292 -0
- ccproxy/api/routes/__init__.py +5 -14
- ccproxy/api/routes/health.py +39 -672
- ccproxy/api/routes/plugins.py +277 -0
- ccproxy/auth/__init__.py +2 -19
- ccproxy/auth/bearer.py +25 -15
- ccproxy/auth/dependencies.py +123 -157
- ccproxy/auth/exceptions.py +0 -12
- ccproxy/auth/manager.py +35 -49
- ccproxy/auth/managers/__init__.py +10 -0
- ccproxy/auth/managers/base.py +523 -0
- ccproxy/auth/managers/base_enhanced.py +63 -0
- ccproxy/auth/managers/token_snapshot.py +77 -0
- ccproxy/auth/models/base.py +65 -0
- ccproxy/auth/models/credentials.py +40 -0
- ccproxy/auth/oauth/__init__.py +4 -18
- ccproxy/auth/oauth/base.py +533 -0
- ccproxy/auth/oauth/cli_errors.py +37 -0
- ccproxy/auth/oauth/flows.py +430 -0
- ccproxy/auth/oauth/protocol.py +366 -0
- ccproxy/auth/oauth/registry.py +408 -0
- ccproxy/auth/oauth/router.py +396 -0
- ccproxy/auth/oauth/routes.py +186 -113
- ccproxy/auth/oauth/session.py +151 -0
- ccproxy/auth/oauth/templates.py +342 -0
- ccproxy/auth/storage/__init__.py +2 -5
- ccproxy/auth/storage/base.py +279 -5
- ccproxy/auth/storage/generic.py +134 -0
- ccproxy/cli/__init__.py +1 -2
- ccproxy/cli/_settings_help.py +351 -0
- ccproxy/cli/commands/auth.py +1519 -793
- ccproxy/cli/commands/config/commands.py +209 -276
- ccproxy/cli/commands/plugins.py +669 -0
- ccproxy/cli/commands/serve.py +75 -810
- ccproxy/cli/commands/status.py +254 -0
- ccproxy/cli/decorators.py +83 -0
- ccproxy/cli/helpers.py +22 -60
- ccproxy/cli/main.py +359 -10
- ccproxy/cli/options/claude_options.py +0 -25
- ccproxy/config/__init__.py +7 -11
- ccproxy/config/core.py +227 -0
- ccproxy/config/env_generator.py +232 -0
- ccproxy/config/runtime.py +67 -0
- ccproxy/config/security.py +36 -3
- ccproxy/config/settings.py +382 -441
- ccproxy/config/toml_generator.py +299 -0
- ccproxy/config/utils.py +452 -0
- ccproxy/core/__init__.py +7 -271
- ccproxy/{_version.py → core/_version.py} +16 -3
- ccproxy/core/async_task_manager.py +516 -0
- ccproxy/core/async_utils.py +47 -14
- ccproxy/core/auth/__init__.py +6 -0
- ccproxy/core/constants.py +16 -50
- ccproxy/core/errors.py +53 -0
- ccproxy/core/id_utils.py +20 -0
- ccproxy/core/interfaces.py +16 -123
- ccproxy/core/logging.py +473 -18
- ccproxy/core/plugins/__init__.py +77 -0
- ccproxy/core/plugins/cli_discovery.py +211 -0
- ccproxy/core/plugins/declaration.py +455 -0
- ccproxy/core/plugins/discovery.py +604 -0
- ccproxy/core/plugins/factories.py +967 -0
- ccproxy/core/plugins/hooks/__init__.py +30 -0
- ccproxy/core/plugins/hooks/base.py +58 -0
- ccproxy/core/plugins/hooks/events.py +46 -0
- ccproxy/core/plugins/hooks/implementations/__init__.py +16 -0
- ccproxy/core/plugins/hooks/implementations/formatters/__init__.py +11 -0
- ccproxy/core/plugins/hooks/implementations/formatters/json.py +552 -0
- ccproxy/core/plugins/hooks/implementations/formatters/raw.py +370 -0
- ccproxy/core/plugins/hooks/implementations/http_tracer.py +431 -0
- ccproxy/core/plugins/hooks/layers.py +44 -0
- ccproxy/core/plugins/hooks/manager.py +186 -0
- ccproxy/core/plugins/hooks/registry.py +139 -0
- ccproxy/core/plugins/hooks/thread_manager.py +203 -0
- ccproxy/core/plugins/hooks/types.py +22 -0
- ccproxy/core/plugins/interfaces.py +416 -0
- ccproxy/core/plugins/loader.py +166 -0
- ccproxy/core/plugins/middleware.py +233 -0
- ccproxy/core/plugins/models.py +59 -0
- ccproxy/core/plugins/protocol.py +180 -0
- ccproxy/core/plugins/runtime.py +519 -0
- ccproxy/{observability/context.py → core/request_context.py} +137 -94
- ccproxy/core/status_report.py +211 -0
- ccproxy/core/transformers.py +13 -8
- ccproxy/data/claude_headers_fallback.json +558 -0
- ccproxy/data/codex_headers_fallback.json +121 -0
- ccproxy/http/__init__.py +30 -0
- ccproxy/http/base.py +95 -0
- ccproxy/http/client.py +323 -0
- ccproxy/http/hooks.py +642 -0
- ccproxy/http/pool.py +279 -0
- ccproxy/llms/formatters/__init__.py +7 -0
- ccproxy/llms/formatters/anthropic_to_openai/__init__.py +55 -0
- ccproxy/llms/formatters/anthropic_to_openai/errors.py +65 -0
- ccproxy/llms/formatters/anthropic_to_openai/requests.py +356 -0
- ccproxy/llms/formatters/anthropic_to_openai/responses.py +153 -0
- ccproxy/llms/formatters/anthropic_to_openai/streams.py +1546 -0
- ccproxy/llms/formatters/base.py +140 -0
- ccproxy/llms/formatters/base_model.py +33 -0
- ccproxy/llms/formatters/common/__init__.py +51 -0
- ccproxy/llms/formatters/common/identifiers.py +48 -0
- ccproxy/llms/formatters/common/streams.py +254 -0
- ccproxy/llms/formatters/common/thinking.py +74 -0
- ccproxy/llms/formatters/common/usage.py +135 -0
- ccproxy/llms/formatters/constants.py +55 -0
- ccproxy/llms/formatters/context.py +116 -0
- ccproxy/llms/formatters/mapping.py +33 -0
- ccproxy/llms/formatters/openai_to_anthropic/__init__.py +55 -0
- ccproxy/llms/formatters/openai_to_anthropic/_helpers.py +141 -0
- ccproxy/llms/formatters/openai_to_anthropic/errors.py +53 -0
- ccproxy/llms/formatters/openai_to_anthropic/requests.py +674 -0
- ccproxy/llms/formatters/openai_to_anthropic/responses.py +285 -0
- ccproxy/llms/formatters/openai_to_anthropic/streams.py +530 -0
- ccproxy/llms/formatters/openai_to_openai/__init__.py +53 -0
- ccproxy/llms/formatters/openai_to_openai/_helpers.py +325 -0
- ccproxy/llms/formatters/openai_to_openai/errors.py +6 -0
- ccproxy/llms/formatters/openai_to_openai/requests.py +388 -0
- ccproxy/llms/formatters/openai_to_openai/responses.py +594 -0
- ccproxy/llms/formatters/openai_to_openai/streams.py +1832 -0
- ccproxy/llms/formatters/utils.py +306 -0
- ccproxy/llms/models/__init__.py +9 -0
- ccproxy/llms/models/anthropic.py +619 -0
- ccproxy/llms/models/openai.py +844 -0
- ccproxy/llms/streaming/__init__.py +26 -0
- ccproxy/llms/streaming/accumulators.py +1074 -0
- ccproxy/llms/streaming/formatters.py +251 -0
- ccproxy/{adapters/openai/streaming.py → llms/streaming/processors.py} +193 -240
- ccproxy/models/__init__.py +8 -159
- ccproxy/models/detection.py +92 -193
- ccproxy/models/provider.py +75 -0
- ccproxy/plugins/access_log/README.md +32 -0
- ccproxy/plugins/access_log/__init__.py +20 -0
- ccproxy/plugins/access_log/config.py +33 -0
- ccproxy/plugins/access_log/formatter.py +126 -0
- ccproxy/plugins/access_log/hook.py +763 -0
- ccproxy/plugins/access_log/logger.py +254 -0
- ccproxy/plugins/access_log/plugin.py +137 -0
- ccproxy/plugins/access_log/writer.py +109 -0
- ccproxy/plugins/analytics/README.md +24 -0
- ccproxy/plugins/analytics/__init__.py +1 -0
- ccproxy/plugins/analytics/config.py +5 -0
- ccproxy/plugins/analytics/ingest.py +85 -0
- ccproxy/plugins/analytics/models.py +97 -0
- ccproxy/plugins/analytics/plugin.py +121 -0
- ccproxy/plugins/analytics/routes.py +163 -0
- ccproxy/plugins/analytics/service.py +284 -0
- ccproxy/plugins/claude_api/README.md +29 -0
- ccproxy/plugins/claude_api/__init__.py +10 -0
- ccproxy/plugins/claude_api/adapter.py +829 -0
- ccproxy/plugins/claude_api/config.py +52 -0
- ccproxy/plugins/claude_api/detection_service.py +461 -0
- ccproxy/plugins/claude_api/health.py +175 -0
- ccproxy/plugins/claude_api/hooks.py +284 -0
- ccproxy/plugins/claude_api/models.py +256 -0
- ccproxy/plugins/claude_api/plugin.py +298 -0
- ccproxy/plugins/claude_api/routes.py +118 -0
- ccproxy/plugins/claude_api/streaming_metrics.py +68 -0
- ccproxy/plugins/claude_api/tasks.py +84 -0
- ccproxy/plugins/claude_sdk/README.md +35 -0
- ccproxy/plugins/claude_sdk/__init__.py +80 -0
- ccproxy/plugins/claude_sdk/adapter.py +749 -0
- ccproxy/plugins/claude_sdk/auth.py +57 -0
- ccproxy/{claude_sdk → plugins/claude_sdk}/client.py +63 -39
- ccproxy/plugins/claude_sdk/config.py +210 -0
- ccproxy/{claude_sdk → plugins/claude_sdk}/converter.py +6 -6
- ccproxy/plugins/claude_sdk/detection_service.py +163 -0
- ccproxy/{services/claude_sdk_service.py → plugins/claude_sdk/handler.py} +123 -304
- ccproxy/plugins/claude_sdk/health.py +113 -0
- ccproxy/plugins/claude_sdk/hooks.py +115 -0
- ccproxy/{claude_sdk → plugins/claude_sdk}/manager.py +42 -32
- ccproxy/{claude_sdk → plugins/claude_sdk}/message_queue.py +8 -8
- ccproxy/{models/claude_sdk.py → plugins/claude_sdk/models.py} +64 -16
- ccproxy/plugins/claude_sdk/options.py +154 -0
- ccproxy/{claude_sdk → plugins/claude_sdk}/parser.py +23 -5
- ccproxy/plugins/claude_sdk/plugin.py +269 -0
- ccproxy/plugins/claude_sdk/routes.py +104 -0
- ccproxy/{claude_sdk → plugins/claude_sdk}/session_client.py +124 -12
- ccproxy/plugins/claude_sdk/session_pool.py +700 -0
- ccproxy/{claude_sdk → plugins/claude_sdk}/stream_handle.py +48 -43
- ccproxy/{claude_sdk → plugins/claude_sdk}/stream_worker.py +22 -18
- ccproxy/{claude_sdk → plugins/claude_sdk}/streaming.py +50 -16
- ccproxy/plugins/claude_sdk/tasks.py +97 -0
- ccproxy/plugins/claude_shared/README.md +18 -0
- ccproxy/plugins/claude_shared/__init__.py +12 -0
- ccproxy/plugins/claude_shared/model_defaults.py +171 -0
- ccproxy/plugins/codex/README.md +35 -0
- ccproxy/plugins/codex/__init__.py +6 -0
- ccproxy/plugins/codex/adapter.py +635 -0
- ccproxy/{config/codex.py → plugins/codex/config.py} +78 -12
- ccproxy/plugins/codex/detection_service.py +544 -0
- ccproxy/plugins/codex/health.py +162 -0
- ccproxy/plugins/codex/hooks.py +263 -0
- ccproxy/plugins/codex/model_defaults.py +39 -0
- ccproxy/plugins/codex/models.py +263 -0
- ccproxy/plugins/codex/plugin.py +275 -0
- ccproxy/plugins/codex/routes.py +129 -0
- ccproxy/plugins/codex/streaming_metrics.py +324 -0
- ccproxy/plugins/codex/tasks.py +106 -0
- ccproxy/plugins/codex/utils/__init__.py +1 -0
- ccproxy/plugins/codex/utils/sse_parser.py +106 -0
- ccproxy/plugins/command_replay/README.md +34 -0
- ccproxy/plugins/command_replay/__init__.py +17 -0
- ccproxy/plugins/command_replay/config.py +133 -0
- ccproxy/plugins/command_replay/formatter.py +432 -0
- ccproxy/plugins/command_replay/hook.py +294 -0
- ccproxy/plugins/command_replay/plugin.py +161 -0
- ccproxy/plugins/copilot/README.md +39 -0
- ccproxy/plugins/copilot/__init__.py +11 -0
- ccproxy/plugins/copilot/adapter.py +465 -0
- ccproxy/plugins/copilot/config.py +155 -0
- ccproxy/plugins/copilot/data/copilot_fallback.json +41 -0
- ccproxy/plugins/copilot/detection_service.py +255 -0
- ccproxy/plugins/copilot/manager.py +275 -0
- ccproxy/plugins/copilot/model_defaults.py +284 -0
- ccproxy/plugins/copilot/models.py +148 -0
- ccproxy/plugins/copilot/oauth/__init__.py +16 -0
- ccproxy/plugins/copilot/oauth/client.py +494 -0
- ccproxy/plugins/copilot/oauth/models.py +385 -0
- ccproxy/plugins/copilot/oauth/provider.py +602 -0
- ccproxy/plugins/copilot/oauth/storage.py +170 -0
- ccproxy/plugins/copilot/plugin.py +360 -0
- ccproxy/plugins/copilot/routes.py +294 -0
- ccproxy/plugins/credential_balancer/README.md +124 -0
- ccproxy/plugins/credential_balancer/__init__.py +6 -0
- ccproxy/plugins/credential_balancer/config.py +270 -0
- ccproxy/plugins/credential_balancer/factory.py +415 -0
- ccproxy/plugins/credential_balancer/hook.py +51 -0
- ccproxy/plugins/credential_balancer/manager.py +587 -0
- ccproxy/plugins/credential_balancer/plugin.py +146 -0
- ccproxy/plugins/dashboard/README.md +25 -0
- ccproxy/plugins/dashboard/__init__.py +1 -0
- ccproxy/plugins/dashboard/config.py +8 -0
- ccproxy/plugins/dashboard/plugin.py +71 -0
- ccproxy/plugins/dashboard/routes.py +67 -0
- ccproxy/plugins/docker/README.md +32 -0
- ccproxy/{docker → plugins/docker}/__init__.py +3 -0
- ccproxy/{docker → plugins/docker}/adapter.py +108 -10
- ccproxy/plugins/docker/config.py +82 -0
- ccproxy/{docker → plugins/docker}/docker_path.py +4 -3
- ccproxy/{docker → plugins/docker}/middleware.py +2 -2
- ccproxy/plugins/docker/plugin.py +198 -0
- ccproxy/{docker → plugins/docker}/stream_process.py +3 -3
- ccproxy/plugins/duckdb_storage/README.md +26 -0
- ccproxy/plugins/duckdb_storage/__init__.py +1 -0
- ccproxy/plugins/duckdb_storage/config.py +22 -0
- ccproxy/plugins/duckdb_storage/plugin.py +128 -0
- ccproxy/plugins/duckdb_storage/routes.py +51 -0
- ccproxy/plugins/duckdb_storage/storage.py +633 -0
- ccproxy/plugins/max_tokens/README.md +38 -0
- ccproxy/plugins/max_tokens/__init__.py +12 -0
- ccproxy/plugins/max_tokens/adapter.py +235 -0
- ccproxy/plugins/max_tokens/config.py +86 -0
- ccproxy/plugins/max_tokens/models.py +53 -0
- ccproxy/plugins/max_tokens/plugin.py +200 -0
- ccproxy/plugins/max_tokens/service.py +271 -0
- ccproxy/plugins/max_tokens/token_limits.json +54 -0
- ccproxy/plugins/metrics/README.md +35 -0
- ccproxy/plugins/metrics/__init__.py +10 -0
- ccproxy/{observability/metrics.py → plugins/metrics/collector.py} +20 -153
- ccproxy/plugins/metrics/config.py +85 -0
- ccproxy/plugins/metrics/grafana/dashboards/ccproxy-dashboard.json +1720 -0
- ccproxy/plugins/metrics/hook.py +403 -0
- ccproxy/plugins/metrics/plugin.py +268 -0
- ccproxy/{observability → plugins/metrics}/pushgateway.py +57 -59
- ccproxy/plugins/metrics/routes.py +107 -0
- ccproxy/plugins/metrics/tasks.py +117 -0
- ccproxy/plugins/oauth_claude/README.md +35 -0
- ccproxy/plugins/oauth_claude/__init__.py +14 -0
- ccproxy/plugins/oauth_claude/client.py +270 -0
- ccproxy/plugins/oauth_claude/config.py +84 -0
- ccproxy/plugins/oauth_claude/manager.py +482 -0
- ccproxy/plugins/oauth_claude/models.py +266 -0
- ccproxy/plugins/oauth_claude/plugin.py +149 -0
- ccproxy/plugins/oauth_claude/provider.py +571 -0
- ccproxy/plugins/oauth_claude/storage.py +212 -0
- ccproxy/plugins/oauth_codex/README.md +38 -0
- ccproxy/plugins/oauth_codex/__init__.py +14 -0
- ccproxy/plugins/oauth_codex/client.py +224 -0
- ccproxy/plugins/oauth_codex/config.py +95 -0
- ccproxy/plugins/oauth_codex/manager.py +256 -0
- ccproxy/plugins/oauth_codex/models.py +239 -0
- ccproxy/plugins/oauth_codex/plugin.py +146 -0
- ccproxy/plugins/oauth_codex/provider.py +574 -0
- ccproxy/plugins/oauth_codex/storage.py +92 -0
- ccproxy/plugins/permissions/README.md +28 -0
- ccproxy/plugins/permissions/__init__.py +22 -0
- ccproxy/plugins/permissions/config.py +28 -0
- ccproxy/{cli/commands/permission_handler.py → plugins/permissions/handlers/cli.py} +49 -25
- ccproxy/plugins/permissions/handlers/protocol.py +33 -0
- ccproxy/plugins/permissions/handlers/terminal.py +675 -0
- ccproxy/{api/routes → plugins/permissions}/mcp.py +34 -7
- ccproxy/{models/permissions.py → plugins/permissions/models.py} +65 -1
- ccproxy/plugins/permissions/plugin.py +153 -0
- ccproxy/{api/routes/permissions.py → plugins/permissions/routes.py} +20 -16
- ccproxy/{api/services/permission_service.py → plugins/permissions/service.py} +65 -11
- ccproxy/{api → plugins/permissions}/ui/permission_handler_protocol.py +1 -1
- ccproxy/{api → plugins/permissions}/ui/terminal_permission_handler.py +66 -10
- ccproxy/plugins/pricing/README.md +34 -0
- ccproxy/plugins/pricing/__init__.py +6 -0
- ccproxy/{pricing → plugins/pricing}/cache.py +7 -6
- ccproxy/{config/pricing.py → plugins/pricing/config.py} +32 -6
- ccproxy/plugins/pricing/exceptions.py +35 -0
- ccproxy/plugins/pricing/loader.py +440 -0
- ccproxy/{pricing → plugins/pricing}/models.py +13 -23
- ccproxy/plugins/pricing/plugin.py +169 -0
- ccproxy/plugins/pricing/service.py +191 -0
- ccproxy/plugins/pricing/tasks.py +300 -0
- ccproxy/{pricing → plugins/pricing}/updater.py +86 -72
- ccproxy/plugins/pricing/utils.py +99 -0
- ccproxy/plugins/request_tracer/README.md +40 -0
- ccproxy/plugins/request_tracer/__init__.py +7 -0
- ccproxy/plugins/request_tracer/config.py +120 -0
- ccproxy/plugins/request_tracer/hook.py +415 -0
- ccproxy/plugins/request_tracer/plugin.py +255 -0
- ccproxy/scheduler/__init__.py +2 -14
- ccproxy/scheduler/core.py +26 -41
- ccproxy/scheduler/manager.py +63 -107
- ccproxy/scheduler/registry.py +6 -32
- ccproxy/scheduler/tasks.py +346 -314
- ccproxy/services/__init__.py +0 -1
- ccproxy/services/adapters/__init__.py +11 -0
- ccproxy/services/adapters/base.py +123 -0
- ccproxy/services/adapters/chain_composer.py +88 -0
- ccproxy/services/adapters/chain_validation.py +44 -0
- ccproxy/services/adapters/chat_accumulator.py +200 -0
- ccproxy/services/adapters/delta_utils.py +142 -0
- ccproxy/services/adapters/format_adapter.py +136 -0
- ccproxy/services/adapters/format_context.py +11 -0
- ccproxy/services/adapters/format_registry.py +158 -0
- ccproxy/services/adapters/http_adapter.py +1045 -0
- ccproxy/services/adapters/mock_adapter.py +118 -0
- ccproxy/services/adapters/protocols.py +35 -0
- ccproxy/services/adapters/simple_converters.py +571 -0
- ccproxy/services/auth_registry.py +180 -0
- ccproxy/services/cache/__init__.py +6 -0
- ccproxy/services/cache/response_cache.py +261 -0
- ccproxy/services/cli_detection.py +437 -0
- ccproxy/services/config/__init__.py +6 -0
- ccproxy/services/config/proxy_configuration.py +111 -0
- ccproxy/services/container.py +256 -0
- ccproxy/services/factories.py +380 -0
- ccproxy/services/handler_config.py +76 -0
- ccproxy/services/interfaces.py +298 -0
- ccproxy/services/mocking/__init__.py +6 -0
- ccproxy/services/mocking/mock_handler.py +291 -0
- ccproxy/services/tracing/__init__.py +7 -0
- ccproxy/services/tracing/interfaces.py +61 -0
- ccproxy/services/tracing/null_tracer.py +57 -0
- ccproxy/streaming/__init__.py +23 -0
- ccproxy/streaming/buffer.py +1056 -0
- ccproxy/streaming/deferred.py +897 -0
- ccproxy/streaming/handler.py +117 -0
- ccproxy/streaming/interfaces.py +77 -0
- ccproxy/streaming/simple_adapter.py +39 -0
- ccproxy/streaming/sse.py +109 -0
- ccproxy/streaming/sse_parser.py +127 -0
- ccproxy/templates/__init__.py +6 -0
- ccproxy/templates/plugin_scaffold.py +695 -0
- ccproxy/testing/endpoints/__init__.py +33 -0
- ccproxy/testing/endpoints/cli.py +215 -0
- ccproxy/testing/endpoints/config.py +874 -0
- ccproxy/testing/endpoints/console.py +57 -0
- ccproxy/testing/endpoints/models.py +100 -0
- ccproxy/testing/endpoints/runner.py +1903 -0
- ccproxy/testing/endpoints/tools.py +308 -0
- ccproxy/testing/mock_responses.py +70 -1
- ccproxy/testing/response_handlers.py +20 -0
- ccproxy/utils/__init__.py +0 -6
- ccproxy/utils/binary_resolver.py +476 -0
- ccproxy/utils/caching.py +327 -0
- ccproxy/utils/cli_logging.py +101 -0
- ccproxy/utils/command_line.py +251 -0
- ccproxy/utils/headers.py +228 -0
- ccproxy/utils/model_mapper.py +120 -0
- ccproxy/utils/startup_helpers.py +95 -342
- ccproxy/utils/version_checker.py +279 -6
- ccproxy_api-0.2.0.dist-info/METADATA +212 -0
- ccproxy_api-0.2.0.dist-info/RECORD +417 -0
- {ccproxy_api-0.1.6.dist-info → ccproxy_api-0.2.0.dist-info}/WHEEL +1 -1
- ccproxy_api-0.2.0.dist-info/entry_points.txt +24 -0
- ccproxy/__init__.py +0 -4
- ccproxy/adapters/__init__.py +0 -11
- ccproxy/adapters/base.py +0 -80
- ccproxy/adapters/codex/__init__.py +0 -11
- ccproxy/adapters/openai/__init__.py +0 -42
- ccproxy/adapters/openai/adapter.py +0 -953
- ccproxy/adapters/openai/models.py +0 -412
- ccproxy/adapters/openai/response_adapter.py +0 -355
- ccproxy/adapters/openai/response_models.py +0 -178
- ccproxy/api/middleware/headers.py +0 -49
- ccproxy/api/middleware/logging.py +0 -180
- ccproxy/api/middleware/request_content_logging.py +0 -297
- ccproxy/api/middleware/server_header.py +0 -58
- ccproxy/api/responses.py +0 -89
- ccproxy/api/routes/claude.py +0 -371
- ccproxy/api/routes/codex.py +0 -1231
- ccproxy/api/routes/metrics.py +0 -1029
- ccproxy/api/routes/proxy.py +0 -211
- ccproxy/api/services/__init__.py +0 -6
- ccproxy/auth/conditional.py +0 -84
- ccproxy/auth/credentials_adapter.py +0 -93
- ccproxy/auth/models.py +0 -118
- ccproxy/auth/oauth/models.py +0 -48
- ccproxy/auth/openai/__init__.py +0 -13
- ccproxy/auth/openai/credentials.py +0 -166
- ccproxy/auth/openai/oauth_client.py +0 -334
- ccproxy/auth/openai/storage.py +0 -184
- ccproxy/auth/storage/json_file.py +0 -158
- ccproxy/auth/storage/keyring.py +0 -189
- ccproxy/claude_sdk/__init__.py +0 -18
- ccproxy/claude_sdk/options.py +0 -194
- ccproxy/claude_sdk/session_pool.py +0 -550
- ccproxy/cli/docker/__init__.py +0 -34
- ccproxy/cli/docker/adapter_factory.py +0 -157
- ccproxy/cli/docker/params.py +0 -274
- ccproxy/config/auth.py +0 -153
- ccproxy/config/claude.py +0 -348
- ccproxy/config/cors.py +0 -79
- ccproxy/config/discovery.py +0 -95
- ccproxy/config/docker_settings.py +0 -264
- ccproxy/config/observability.py +0 -158
- ccproxy/config/reverse_proxy.py +0 -31
- ccproxy/config/scheduler.py +0 -108
- ccproxy/config/server.py +0 -86
- ccproxy/config/validators.py +0 -231
- ccproxy/core/codex_transformers.py +0 -389
- ccproxy/core/http.py +0 -328
- ccproxy/core/http_transformers.py +0 -812
- ccproxy/core/proxy.py +0 -143
- ccproxy/core/validators.py +0 -288
- ccproxy/models/errors.py +0 -42
- ccproxy/models/messages.py +0 -269
- ccproxy/models/requests.py +0 -107
- ccproxy/models/responses.py +0 -270
- ccproxy/models/types.py +0 -102
- ccproxy/observability/__init__.py +0 -51
- ccproxy/observability/access_logger.py +0 -457
- ccproxy/observability/sse_events.py +0 -303
- ccproxy/observability/stats_printer.py +0 -753
- ccproxy/observability/storage/__init__.py +0 -1
- ccproxy/observability/storage/duckdb_simple.py +0 -677
- ccproxy/observability/storage/models.py +0 -70
- ccproxy/observability/streaming_response.py +0 -107
- ccproxy/pricing/__init__.py +0 -19
- ccproxy/pricing/loader.py +0 -251
- ccproxy/services/claude_detection_service.py +0 -269
- ccproxy/services/codex_detection_service.py +0 -263
- ccproxy/services/credentials/__init__.py +0 -55
- ccproxy/services/credentials/config.py +0 -105
- ccproxy/services/credentials/manager.py +0 -561
- ccproxy/services/credentials/oauth_client.py +0 -481
- ccproxy/services/proxy_service.py +0 -1827
- ccproxy/static/.keep +0 -0
- ccproxy/utils/cost_calculator.py +0 -210
- ccproxy/utils/disconnection_monitor.py +0 -83
- ccproxy/utils/model_mapping.py +0 -199
- ccproxy/utils/models_provider.py +0 -150
- ccproxy/utils/simple_request_logger.py +0 -284
- ccproxy/utils/streaming_metrics.py +0 -199
- ccproxy_api-0.1.6.dist-info/METADATA +0 -615
- ccproxy_api-0.1.6.dist-info/RECORD +0 -189
- ccproxy_api-0.1.6.dist-info/entry_points.txt +0 -4
- /ccproxy/{api/middleware/auth.py → auth/models/__init__.py} +0 -0
- /ccproxy/{claude_sdk → plugins/claude_sdk}/exceptions.py +0 -0
- /ccproxy/{docker → plugins/docker}/models.py +0 -0
- /ccproxy/{docker → plugins/docker}/protocol.py +0 -0
- /ccproxy/{docker → plugins/docker}/validators.py +0 -0
- /ccproxy/{auth/oauth/storage.py → plugins/permissions/handlers/__init__.py} +0 -0
- /ccproxy/{api → plugins/permissions}/ui/__init__.py +0 -0
- {ccproxy_api-0.1.6.dist-info → ccproxy_api-0.2.0.dist-info}/licenses/LICENSE +0 -0
ccproxy/api/routes/claude.py
DELETED
|
@@ -1,371 +0,0 @@
|
|
|
1
|
-
"""Claude SDK endpoints for CCProxy API Server."""
|
|
2
|
-
|
|
3
|
-
import json
|
|
4
|
-
from collections.abc import AsyncIterator
|
|
5
|
-
|
|
6
|
-
import structlog
|
|
7
|
-
from fastapi import APIRouter, HTTPException, Request
|
|
8
|
-
from fastapi.responses import StreamingResponse
|
|
9
|
-
|
|
10
|
-
from ccproxy.adapters.openai.adapter import (
|
|
11
|
-
OpenAIAdapter,
|
|
12
|
-
OpenAIChatCompletionRequest,
|
|
13
|
-
OpenAIChatCompletionResponse,
|
|
14
|
-
)
|
|
15
|
-
from ccproxy.api.dependencies import ClaudeServiceDep
|
|
16
|
-
from ccproxy.models.messages import MessageCreateParams, MessageResponse
|
|
17
|
-
from ccproxy.observability.streaming_response import StreamingResponseWithLogging
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
# Create the router for Claude SDK endpoints
|
|
21
|
-
router = APIRouter(tags=["claude-sdk"])
|
|
22
|
-
|
|
23
|
-
logger = structlog.get_logger(__name__)
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
@router.post("/v1/chat/completions", response_model=None)
|
|
27
|
-
async def create_openai_chat_completion(
|
|
28
|
-
openai_request: OpenAIChatCompletionRequest,
|
|
29
|
-
claude_service: ClaudeServiceDep,
|
|
30
|
-
request: Request,
|
|
31
|
-
) -> StreamingResponse | OpenAIChatCompletionResponse:
|
|
32
|
-
"""Create a chat completion using Claude SDK with OpenAI-compatible format.
|
|
33
|
-
|
|
34
|
-
This endpoint handles OpenAI API format requests and converts them
|
|
35
|
-
to Anthropic format before using the Claude SDK directly.
|
|
36
|
-
"""
|
|
37
|
-
try:
|
|
38
|
-
# Create adapter instance
|
|
39
|
-
adapter = OpenAIAdapter()
|
|
40
|
-
|
|
41
|
-
# Convert entire OpenAI request to Anthropic format using adapter
|
|
42
|
-
anthropic_request = adapter.adapt_request(openai_request.model_dump())
|
|
43
|
-
|
|
44
|
-
# Extract stream parameter
|
|
45
|
-
stream = openai_request.stream or False
|
|
46
|
-
|
|
47
|
-
# Get request context from middleware
|
|
48
|
-
request_context = getattr(request.state, "context", None)
|
|
49
|
-
|
|
50
|
-
if request_context is None:
|
|
51
|
-
raise HTTPException(
|
|
52
|
-
status_code=500, detail="Internal server error: no request context"
|
|
53
|
-
)
|
|
54
|
-
|
|
55
|
-
# Call Claude SDK service with adapted request
|
|
56
|
-
response = await claude_service.create_completion(
|
|
57
|
-
messages=anthropic_request["messages"],
|
|
58
|
-
model=anthropic_request["model"],
|
|
59
|
-
temperature=anthropic_request.get("temperature"),
|
|
60
|
-
max_tokens=anthropic_request.get("max_tokens"),
|
|
61
|
-
stream=stream,
|
|
62
|
-
user_id=getattr(openai_request, "user", None),
|
|
63
|
-
request_context=request_context,
|
|
64
|
-
)
|
|
65
|
-
|
|
66
|
-
if stream:
|
|
67
|
-
# Handle streaming response
|
|
68
|
-
async def openai_stream_generator() -> AsyncIterator[bytes]:
|
|
69
|
-
# Use adapt_stream for streaming responses
|
|
70
|
-
async for openai_chunk in adapter.adapt_stream(response): # type: ignore[arg-type]
|
|
71
|
-
yield f"data: {json.dumps(openai_chunk)}\n\n".encode()
|
|
72
|
-
# Send final chunk
|
|
73
|
-
yield b"data: [DONE]\n\n"
|
|
74
|
-
|
|
75
|
-
# Use unified streaming wrapper with logging
|
|
76
|
-
return StreamingResponseWithLogging(
|
|
77
|
-
content=openai_stream_generator(),
|
|
78
|
-
request_context=request_context,
|
|
79
|
-
metrics=getattr(claude_service, "metrics", None),
|
|
80
|
-
status_code=200,
|
|
81
|
-
media_type="text/event-stream",
|
|
82
|
-
headers={
|
|
83
|
-
"Cache-Control": "no-cache",
|
|
84
|
-
"Connection": "keep-alive",
|
|
85
|
-
},
|
|
86
|
-
)
|
|
87
|
-
else:
|
|
88
|
-
# Convert non-streaming response to OpenAI format using adapter
|
|
89
|
-
# Convert MessageResponse model to dict for adapter
|
|
90
|
-
# In non-streaming mode, response should always be MessageResponse
|
|
91
|
-
assert isinstance(response, MessageResponse), (
|
|
92
|
-
"Non-streaming response must be MessageResponse"
|
|
93
|
-
)
|
|
94
|
-
response_dict = response.model_dump()
|
|
95
|
-
openai_response = adapter.adapt_response(response_dict)
|
|
96
|
-
return OpenAIChatCompletionResponse.model_validate(openai_response)
|
|
97
|
-
|
|
98
|
-
except Exception as e:
|
|
99
|
-
# Re-raise specific proxy errors to be handled by the error handler
|
|
100
|
-
from ccproxy.core.errors import ClaudeProxyError
|
|
101
|
-
|
|
102
|
-
if isinstance(e, ClaudeProxyError):
|
|
103
|
-
raise
|
|
104
|
-
raise HTTPException(
|
|
105
|
-
status_code=500, detail=f"Internal server error: {str(e)}"
|
|
106
|
-
) from e
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
@router.post(
|
|
110
|
-
"/{session_id}/v1/chat/completions",
|
|
111
|
-
response_model=None,
|
|
112
|
-
)
|
|
113
|
-
async def create_openai_chat_completion_with_session(
|
|
114
|
-
session_id: str,
|
|
115
|
-
openai_request: OpenAIChatCompletionRequest,
|
|
116
|
-
claude_service: ClaudeServiceDep,
|
|
117
|
-
request: Request,
|
|
118
|
-
) -> StreamingResponse | OpenAIChatCompletionResponse:
|
|
119
|
-
"""Create a chat completion using Claude SDK with OpenAI-compatible format and session ID.
|
|
120
|
-
|
|
121
|
-
This endpoint handles OpenAI API format requests with session ID and converts them
|
|
122
|
-
to Anthropic format before using the Claude SDK directly.
|
|
123
|
-
"""
|
|
124
|
-
try:
|
|
125
|
-
# Create adapter instance
|
|
126
|
-
adapter = OpenAIAdapter()
|
|
127
|
-
|
|
128
|
-
# Convert entire OpenAI request to Anthropic format using adapter
|
|
129
|
-
anthropic_request = adapter.adapt_request(openai_request.model_dump())
|
|
130
|
-
|
|
131
|
-
# Extract stream parameter
|
|
132
|
-
stream = openai_request.stream or False
|
|
133
|
-
|
|
134
|
-
# Get request context from middleware
|
|
135
|
-
request_context = getattr(request.state, "context", None)
|
|
136
|
-
|
|
137
|
-
if request_context is None:
|
|
138
|
-
raise HTTPException(
|
|
139
|
-
status_code=500, detail="Internal server error: no request context"
|
|
140
|
-
)
|
|
141
|
-
|
|
142
|
-
# Call Claude SDK service with adapted request and session_id
|
|
143
|
-
response = await claude_service.create_completion(
|
|
144
|
-
messages=anthropic_request["messages"],
|
|
145
|
-
model=anthropic_request["model"],
|
|
146
|
-
temperature=anthropic_request.get("temperature"),
|
|
147
|
-
max_tokens=anthropic_request.get("max_tokens"),
|
|
148
|
-
stream=stream,
|
|
149
|
-
user_id=getattr(openai_request, "user", None),
|
|
150
|
-
session_id=session_id,
|
|
151
|
-
request_context=request_context,
|
|
152
|
-
)
|
|
153
|
-
|
|
154
|
-
if stream:
|
|
155
|
-
# Handle streaming response
|
|
156
|
-
async def openai_stream_generator() -> AsyncIterator[bytes]:
|
|
157
|
-
# Use adapt_stream for streaming responses
|
|
158
|
-
async for openai_chunk in adapter.adapt_stream(response): # type: ignore[arg-type]
|
|
159
|
-
yield f"data: {json.dumps(openai_chunk)}\n\n".encode()
|
|
160
|
-
# Send final chunk
|
|
161
|
-
yield b"data: [DONE]\n\n"
|
|
162
|
-
|
|
163
|
-
# Use unified streaming wrapper with logging
|
|
164
|
-
# Session interrupts are now handled directly by the StreamHandle
|
|
165
|
-
return StreamingResponseWithLogging(
|
|
166
|
-
content=openai_stream_generator(),
|
|
167
|
-
request_context=request_context,
|
|
168
|
-
metrics=getattr(claude_service, "metrics", None),
|
|
169
|
-
status_code=200,
|
|
170
|
-
media_type="text/event-stream",
|
|
171
|
-
headers={
|
|
172
|
-
"Cache-Control": "no-cache",
|
|
173
|
-
"Connection": "keep-alive",
|
|
174
|
-
},
|
|
175
|
-
)
|
|
176
|
-
else:
|
|
177
|
-
# Convert non-streaming response to OpenAI format using adapter
|
|
178
|
-
# Convert MessageResponse model to dict for adapter
|
|
179
|
-
# In non-streaming mode, response should always be MessageResponse
|
|
180
|
-
assert isinstance(response, MessageResponse), (
|
|
181
|
-
"Non-streaming response must be MessageResponse"
|
|
182
|
-
)
|
|
183
|
-
response_dict = response.model_dump()
|
|
184
|
-
openai_response = adapter.adapt_response(response_dict)
|
|
185
|
-
return OpenAIChatCompletionResponse.model_validate(openai_response)
|
|
186
|
-
|
|
187
|
-
except Exception as e:
|
|
188
|
-
# Re-raise specific proxy errors to be handled by the error handler
|
|
189
|
-
from ccproxy.core.errors import ClaudeProxyError
|
|
190
|
-
|
|
191
|
-
if isinstance(e, ClaudeProxyError):
|
|
192
|
-
raise
|
|
193
|
-
raise HTTPException(
|
|
194
|
-
status_code=500, detail=f"Internal server error: {str(e)}"
|
|
195
|
-
) from e
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
@router.post(
|
|
199
|
-
"/{session_id}/v1/messages",
|
|
200
|
-
response_model=None,
|
|
201
|
-
)
|
|
202
|
-
async def create_anthropic_message_with_session(
|
|
203
|
-
session_id: str,
|
|
204
|
-
message_request: MessageCreateParams,
|
|
205
|
-
claude_service: ClaudeServiceDep,
|
|
206
|
-
request: Request,
|
|
207
|
-
) -> StreamingResponse | MessageResponse:
|
|
208
|
-
"""Create a message using Claude SDK with Anthropic format and session ID.
|
|
209
|
-
|
|
210
|
-
This endpoint handles Anthropic API format requests with session ID directly
|
|
211
|
-
using the Claude SDK without any format conversion.
|
|
212
|
-
"""
|
|
213
|
-
try:
|
|
214
|
-
# Extract parameters from Anthropic request
|
|
215
|
-
messages = [msg.model_dump() for msg in message_request.messages]
|
|
216
|
-
model = message_request.model
|
|
217
|
-
temperature = message_request.temperature
|
|
218
|
-
max_tokens = message_request.max_tokens
|
|
219
|
-
stream = message_request.stream or False
|
|
220
|
-
|
|
221
|
-
# Get request context from middleware
|
|
222
|
-
request_context = getattr(request.state, "context", None)
|
|
223
|
-
if request_context is None:
|
|
224
|
-
raise HTTPException(
|
|
225
|
-
status_code=500, detail="Internal server error: no request context"
|
|
226
|
-
)
|
|
227
|
-
|
|
228
|
-
# Call Claude SDK service directly with Anthropic format and session_id
|
|
229
|
-
response = await claude_service.create_completion(
|
|
230
|
-
messages=messages,
|
|
231
|
-
model=model,
|
|
232
|
-
temperature=temperature,
|
|
233
|
-
max_tokens=max_tokens,
|
|
234
|
-
stream=stream,
|
|
235
|
-
user_id=getattr(message_request, "user_id", None),
|
|
236
|
-
session_id=session_id,
|
|
237
|
-
request_context=request_context,
|
|
238
|
-
)
|
|
239
|
-
|
|
240
|
-
if stream:
|
|
241
|
-
# Handle streaming response
|
|
242
|
-
async def anthropic_stream_generator() -> AsyncIterator[bytes]:
|
|
243
|
-
async for chunk in response: # type: ignore[union-attr]
|
|
244
|
-
if chunk:
|
|
245
|
-
# All chunks from Claude SDK streaming should be dict format
|
|
246
|
-
# and need proper SSE event formatting
|
|
247
|
-
if isinstance(chunk, dict):
|
|
248
|
-
# Determine event type from chunk type
|
|
249
|
-
event_type = chunk.get("type", "message_delta")
|
|
250
|
-
yield f"event: {event_type}\n".encode()
|
|
251
|
-
yield f"data: {json.dumps(chunk)}\n\n".encode()
|
|
252
|
-
else:
|
|
253
|
-
# Fallback for unexpected format
|
|
254
|
-
yield f"data: {json.dumps(chunk)}\n\n".encode()
|
|
255
|
-
# No final [DONE] chunk for Anthropic format
|
|
256
|
-
|
|
257
|
-
# Use unified streaming wrapper with logging
|
|
258
|
-
# Session interrupts are now handled directly by the StreamHandle
|
|
259
|
-
return StreamingResponseWithLogging(
|
|
260
|
-
content=anthropic_stream_generator(),
|
|
261
|
-
request_context=request_context,
|
|
262
|
-
metrics=getattr(claude_service, "metrics", None),
|
|
263
|
-
status_code=200,
|
|
264
|
-
media_type="text/event-stream",
|
|
265
|
-
headers={
|
|
266
|
-
"Cache-Control": "no-cache",
|
|
267
|
-
"Connection": "keep-alive",
|
|
268
|
-
},
|
|
269
|
-
)
|
|
270
|
-
else:
|
|
271
|
-
# Return Anthropic format response directly
|
|
272
|
-
return MessageResponse.model_validate(response)
|
|
273
|
-
|
|
274
|
-
except Exception as e:
|
|
275
|
-
# Re-raise specific proxy errors to be handled by the error handler
|
|
276
|
-
from ccproxy.core.errors import ClaudeProxyError
|
|
277
|
-
|
|
278
|
-
if isinstance(e, ClaudeProxyError):
|
|
279
|
-
raise e
|
|
280
|
-
raise HTTPException(
|
|
281
|
-
status_code=500, detail=f"Internal server error: {str(e)}"
|
|
282
|
-
) from e
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
@router.post("/v1/messages", response_model=None)
|
|
286
|
-
async def create_anthropic_message(
|
|
287
|
-
message_request: MessageCreateParams,
|
|
288
|
-
claude_service: ClaudeServiceDep,
|
|
289
|
-
request: Request,
|
|
290
|
-
) -> StreamingResponse | MessageResponse:
|
|
291
|
-
"""Create a message using Claude SDK with Anthropic format.
|
|
292
|
-
|
|
293
|
-
This endpoint handles Anthropic API format requests directly
|
|
294
|
-
using the Claude SDK without any format conversion.
|
|
295
|
-
"""
|
|
296
|
-
try:
|
|
297
|
-
# Extract parameters from Anthropic request
|
|
298
|
-
messages = [msg.model_dump() for msg in message_request.messages]
|
|
299
|
-
model = message_request.model
|
|
300
|
-
temperature = message_request.temperature
|
|
301
|
-
max_tokens = message_request.max_tokens
|
|
302
|
-
stream = message_request.stream or False
|
|
303
|
-
|
|
304
|
-
# Get request context from middleware
|
|
305
|
-
request_context = getattr(request.state, "context", None)
|
|
306
|
-
if request_context is None:
|
|
307
|
-
raise HTTPException(
|
|
308
|
-
status_code=500, detail="Internal server error: no request context"
|
|
309
|
-
)
|
|
310
|
-
|
|
311
|
-
# Extract session_id from metadata if present
|
|
312
|
-
session_id = None
|
|
313
|
-
if message_request.metadata:
|
|
314
|
-
metadata_dict = message_request.metadata.model_dump()
|
|
315
|
-
session_id = metadata_dict.get("session_id")
|
|
316
|
-
|
|
317
|
-
# Call Claude SDK service directly with Anthropic format
|
|
318
|
-
response = await claude_service.create_completion(
|
|
319
|
-
messages=messages,
|
|
320
|
-
model=model,
|
|
321
|
-
temperature=temperature,
|
|
322
|
-
max_tokens=max_tokens,
|
|
323
|
-
stream=stream,
|
|
324
|
-
user_id=getattr(message_request, "user_id", None),
|
|
325
|
-
session_id=session_id,
|
|
326
|
-
request_context=request_context,
|
|
327
|
-
)
|
|
328
|
-
|
|
329
|
-
if stream:
|
|
330
|
-
# Handle streaming response
|
|
331
|
-
async def anthropic_stream_generator() -> AsyncIterator[bytes]:
|
|
332
|
-
async for chunk in response: # type: ignore[union-attr]
|
|
333
|
-
if chunk:
|
|
334
|
-
# All chunks from Claude SDK streaming should be dict format
|
|
335
|
-
# and need proper SSE event formatting
|
|
336
|
-
if isinstance(chunk, dict):
|
|
337
|
-
# Determine event type from chunk type
|
|
338
|
-
event_type = chunk.get("type", "message_delta")
|
|
339
|
-
yield f"event: {event_type}\n".encode()
|
|
340
|
-
yield f"data: {json.dumps(chunk)}\n\n".encode()
|
|
341
|
-
else:
|
|
342
|
-
# Fallback for unexpected format
|
|
343
|
-
yield f"data: {json.dumps(chunk)}\n\n".encode()
|
|
344
|
-
# No final [DONE] chunk for Anthropic format
|
|
345
|
-
|
|
346
|
-
# Use unified streaming wrapper with logging for all requests
|
|
347
|
-
# Session interrupts are now handled directly by the StreamHandle
|
|
348
|
-
return StreamingResponseWithLogging(
|
|
349
|
-
content=anthropic_stream_generator(),
|
|
350
|
-
request_context=request_context,
|
|
351
|
-
metrics=getattr(claude_service, "metrics", None),
|
|
352
|
-
status_code=200,
|
|
353
|
-
media_type="text/event-stream",
|
|
354
|
-
headers={
|
|
355
|
-
"Cache-Control": "no-cache",
|
|
356
|
-
"Connection": "keep-alive",
|
|
357
|
-
},
|
|
358
|
-
)
|
|
359
|
-
else:
|
|
360
|
-
# Return Anthropic format response directly
|
|
361
|
-
return MessageResponse.model_validate(response)
|
|
362
|
-
|
|
363
|
-
except Exception as e:
|
|
364
|
-
# Re-raise specific proxy errors to be handled by the error handler
|
|
365
|
-
from ccproxy.core.errors import ClaudeProxyError
|
|
366
|
-
|
|
367
|
-
if isinstance(e, ClaudeProxyError):
|
|
368
|
-
raise e
|
|
369
|
-
raise HTTPException(
|
|
370
|
-
status_code=500, detail=f"Internal server error: {str(e)}"
|
|
371
|
-
) from e
|