ccproxy-api 0.1.7__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 +434 -219
- ccproxy/api/bootstrap.py +30 -0
- ccproxy/api/decorators.py +85 -0
- ccproxy/api/dependencies.py +144 -168
- ccproxy/api/format_validation.py +54 -0
- ccproxy/api/middleware/cors.py +6 -3
- ccproxy/api/middleware/errors.py +388 -524
- 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 +540 -19
- ccproxy/data/codex_headers_fallback.json +114 -7
- 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 +61 -105
- ccproxy/scheduler/registry.py +6 -32
- ccproxy/scheduler/tasks.py +268 -276
- 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 +68 -446
- ccproxy/utils/version_checker.py +273 -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.7.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 -1251
- 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 -243
- ccproxy/services/codex_detection_service.py +0 -252
- 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.7.dist-info/METADATA +0 -615
- ccproxy_api-0.1.7.dist-info/RECORD +0 -191
- ccproxy_api-0.1.7.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.7.dist-info → ccproxy_api-0.2.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
"""Utility functions for generating TOML configuration from Pydantic models."""
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Any, TextIO, TypeVar
|
|
6
|
+
|
|
7
|
+
from pydantic import BaseModel
|
|
8
|
+
from pydantic.fields import FieldInfo
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
T = TypeVar("T", bound=BaseModel)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def is_hidden_in_example(field_info: FieldInfo) -> bool:
|
|
15
|
+
"""Determine if a field should be omitted from generated example configs."""
|
|
16
|
+
if bool(field_info.exclude):
|
|
17
|
+
return True
|
|
18
|
+
|
|
19
|
+
extra = getattr(field_info, "json_schema_extra", None) or {}
|
|
20
|
+
return bool(extra.get("config_example_hidden"))
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def get_field_description(field_info: FieldInfo) -> str:
|
|
24
|
+
"""Get a human-readable description from a Pydantic field."""
|
|
25
|
+
if field_info.description:
|
|
26
|
+
return field_info.description
|
|
27
|
+
return "Configuration setting"
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def generate_config_from_model(
|
|
31
|
+
model_class: type[T], include_hidden: bool = False
|
|
32
|
+
) -> dict[str, Any]:
|
|
33
|
+
"""Generate a default configuration dictionary from a Pydantic model class.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
model_class: The Pydantic model class to generate config from
|
|
37
|
+
include_hidden: Whether to include fields marked as hidden in examples
|
|
38
|
+
|
|
39
|
+
Returns:
|
|
40
|
+
Dictionary containing the configuration data
|
|
41
|
+
"""
|
|
42
|
+
default_instance = model_class()
|
|
43
|
+
config_data: dict[str, Any] = {}
|
|
44
|
+
|
|
45
|
+
for field_name, field_info in model_class.model_fields.items():
|
|
46
|
+
if not include_hidden and is_hidden_in_example(field_info):
|
|
47
|
+
continue
|
|
48
|
+
|
|
49
|
+
field_value = getattr(default_instance, field_name)
|
|
50
|
+
|
|
51
|
+
if isinstance(field_value, BaseModel):
|
|
52
|
+
nested_config = generate_nested_config(field_value, include_hidden)
|
|
53
|
+
if nested_config:
|
|
54
|
+
config_data[field_name] = nested_config
|
|
55
|
+
else:
|
|
56
|
+
if isinstance(field_value, Path):
|
|
57
|
+
config_data[field_name] = str(field_value)
|
|
58
|
+
else:
|
|
59
|
+
config_data[field_name] = field_value
|
|
60
|
+
|
|
61
|
+
return config_data
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def generate_nested_config(
|
|
65
|
+
model: BaseModel, include_hidden: bool = False
|
|
66
|
+
) -> dict[str, Any]:
|
|
67
|
+
"""Generate configuration for nested Pydantic models.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
model: The Pydantic model instance to generate config from
|
|
71
|
+
include_hidden: Whether to include fields marked as hidden in examples
|
|
72
|
+
|
|
73
|
+
Returns:
|
|
74
|
+
Dictionary containing the nested configuration data
|
|
75
|
+
"""
|
|
76
|
+
config_data: dict[str, Any] = {}
|
|
77
|
+
|
|
78
|
+
# Access model_fields from the class, not the instance
|
|
79
|
+
for field_name, field_info in model.__class__.model_fields.items():
|
|
80
|
+
if not include_hidden and is_hidden_in_example(field_info):
|
|
81
|
+
continue
|
|
82
|
+
|
|
83
|
+
field_value = getattr(model, field_name)
|
|
84
|
+
|
|
85
|
+
if isinstance(field_value, BaseModel):
|
|
86
|
+
nested_config = generate_nested_config(field_value, include_hidden)
|
|
87
|
+
if nested_config:
|
|
88
|
+
config_data[field_name] = nested_config
|
|
89
|
+
else:
|
|
90
|
+
if isinstance(field_value, Path):
|
|
91
|
+
config_data[field_name] = str(field_value)
|
|
92
|
+
else:
|
|
93
|
+
config_data[field_name] = field_value
|
|
94
|
+
|
|
95
|
+
return config_data
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def format_value_for_toml(value: Any) -> str:
|
|
99
|
+
"""Format a configuration value for TOML output.
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
value: The value to format
|
|
103
|
+
|
|
104
|
+
Returns:
|
|
105
|
+
String representation suitable for TOML
|
|
106
|
+
"""
|
|
107
|
+
if value is None:
|
|
108
|
+
return "null"
|
|
109
|
+
elif isinstance(value, bool):
|
|
110
|
+
return "true" if value else "false"
|
|
111
|
+
elif isinstance(value, str):
|
|
112
|
+
# Escape quotes in strings
|
|
113
|
+
escaped = value.replace('"', '\\"')
|
|
114
|
+
return f'"{escaped}"'
|
|
115
|
+
elif isinstance(value, int | float):
|
|
116
|
+
return str(value)
|
|
117
|
+
elif isinstance(value, list):
|
|
118
|
+
if not value:
|
|
119
|
+
return "[]"
|
|
120
|
+
formatted_items = []
|
|
121
|
+
for item in value:
|
|
122
|
+
if isinstance(item, str):
|
|
123
|
+
escaped = item.replace('"', '\\"')
|
|
124
|
+
formatted_items.append(f'"{escaped}"')
|
|
125
|
+
else:
|
|
126
|
+
formatted_items.append(str(item))
|
|
127
|
+
return f"[{', '.join(formatted_items)}]"
|
|
128
|
+
elif isinstance(value, dict):
|
|
129
|
+
if not value:
|
|
130
|
+
return "{}"
|
|
131
|
+
formatted_items = []
|
|
132
|
+
for k, v in value.items():
|
|
133
|
+
if isinstance(v, str):
|
|
134
|
+
escaped = v.replace('"', '\\"')
|
|
135
|
+
formatted_items.append(f'{k} = "{escaped}"')
|
|
136
|
+
else:
|
|
137
|
+
formatted_items.append(f"{k} = {v}")
|
|
138
|
+
return f"{{{', '.join(formatted_items)}}}"
|
|
139
|
+
else:
|
|
140
|
+
return str(value)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def generate_toml_section(
|
|
144
|
+
data: dict[str, Any], prefix: str = "", level: int = 0
|
|
145
|
+
) -> str:
|
|
146
|
+
"""Generate a TOML section string with proper indentation and commenting.
|
|
147
|
+
|
|
148
|
+
Args:
|
|
149
|
+
data: Dictionary of configuration data
|
|
150
|
+
prefix: Comment prefix (e.g., "# " for commented sections)
|
|
151
|
+
level: Nesting level for proper formatting
|
|
152
|
+
|
|
153
|
+
Returns:
|
|
154
|
+
TOML section as a string
|
|
155
|
+
"""
|
|
156
|
+
lines = []
|
|
157
|
+
for key, value in data.items():
|
|
158
|
+
if isinstance(value, dict):
|
|
159
|
+
lines.append(f"{prefix}[{key}]")
|
|
160
|
+
lines.append(generate_toml_section(value, prefix, level + 1))
|
|
161
|
+
else:
|
|
162
|
+
formatted_value = format_value_for_toml(value)
|
|
163
|
+
lines.append(f"{prefix}{key} = {formatted_value}")
|
|
164
|
+
return "\n".join(lines)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def generate_toml_config(
|
|
168
|
+
config_data: dict[str, Any],
|
|
169
|
+
model_class: type[BaseModel],
|
|
170
|
+
header_comment: str | None = None,
|
|
171
|
+
commented: bool = True,
|
|
172
|
+
root_field: str | None = None,
|
|
173
|
+
) -> str:
|
|
174
|
+
"""Generate TOML configuration string from config data and model class.
|
|
175
|
+
|
|
176
|
+
Args:
|
|
177
|
+
config_data: Configuration dictionary to convert to TOML
|
|
178
|
+
model_class: The Pydantic model class (used for field descriptions)
|
|
179
|
+
header_comment: Optional custom header comment
|
|
180
|
+
commented: Whether to comment out all settings (default True)
|
|
181
|
+
root_field: Optional root section path (e.g., "plugins.max_tokens")
|
|
182
|
+
to nest all fields under
|
|
183
|
+
|
|
184
|
+
Returns:
|
|
185
|
+
TOML configuration as a string
|
|
186
|
+
"""
|
|
187
|
+
lines = []
|
|
188
|
+
|
|
189
|
+
# Write header
|
|
190
|
+
if header_comment:
|
|
191
|
+
for line in header_comment.split("\n"):
|
|
192
|
+
lines.append(f"# {line}" if line else "#")
|
|
193
|
+
else:
|
|
194
|
+
lines.append("# Configuration File")
|
|
195
|
+
lines.append("# This file configures the settings for the application")
|
|
196
|
+
if commented:
|
|
197
|
+
lines.append("# Most settings are commented out with their default values")
|
|
198
|
+
lines.append("# Uncomment and modify as needed")
|
|
199
|
+
lines.append("")
|
|
200
|
+
|
|
201
|
+
prefix = "# " if commented else ""
|
|
202
|
+
|
|
203
|
+
# If root_field is specified, write it as a section header
|
|
204
|
+
if root_field:
|
|
205
|
+
lines.append(f"{prefix}[{root_field}]")
|
|
206
|
+
|
|
207
|
+
# Write fields with descriptions
|
|
208
|
+
for field_name, field_info in model_class.model_fields.items():
|
|
209
|
+
if is_hidden_in_example(field_info):
|
|
210
|
+
continue
|
|
211
|
+
|
|
212
|
+
field_value = config_data.get(field_name)
|
|
213
|
+
if field_value is None:
|
|
214
|
+
continue
|
|
215
|
+
|
|
216
|
+
description = get_field_description(field_info)
|
|
217
|
+
|
|
218
|
+
# Write description as comment
|
|
219
|
+
lines.append(f"# {description}")
|
|
220
|
+
|
|
221
|
+
if isinstance(field_value, dict):
|
|
222
|
+
# For nested dicts under root_field, use subsection notation
|
|
223
|
+
section_name = f"{root_field}.{field_name}" if root_field else field_name
|
|
224
|
+
lines.append(f"{prefix}[{section_name}]")
|
|
225
|
+
lines.append(generate_toml_section(field_value, prefix=prefix, level=0))
|
|
226
|
+
else:
|
|
227
|
+
formatted_value = format_value_for_toml(field_value)
|
|
228
|
+
lines.append(f"{prefix}{field_name} = {formatted_value}")
|
|
229
|
+
|
|
230
|
+
lines.append("")
|
|
231
|
+
|
|
232
|
+
return "\n".join(lines)
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def write_toml_config(
|
|
236
|
+
output: TextIO | Path | str,
|
|
237
|
+
model_class: type[BaseModel],
|
|
238
|
+
config_data: dict[str, Any] | None = None,
|
|
239
|
+
header_comment: str | None = None,
|
|
240
|
+
commented: bool = True,
|
|
241
|
+
include_hidden: bool = False,
|
|
242
|
+
root_field: str | None = None,
|
|
243
|
+
) -> None:
|
|
244
|
+
"""Write TOML configuration directly to a stream or file.
|
|
245
|
+
|
|
246
|
+
Args:
|
|
247
|
+
output: Output destination - can be a TextIO stream (file, StringIO, stdout),
|
|
248
|
+
a Path object, or a string path to a file
|
|
249
|
+
model_class: The Pydantic model class to generate config from
|
|
250
|
+
config_data: Optional config dictionary. If None, generates from model defaults
|
|
251
|
+
header_comment: Optional custom header comment
|
|
252
|
+
commented: Whether to comment out all settings (default True)
|
|
253
|
+
include_hidden: Whether to include fields marked as hidden in examples
|
|
254
|
+
root_field: Optional root section path (e.g., "plugins.max_tokens")
|
|
255
|
+
|
|
256
|
+
Examples:
|
|
257
|
+
# Write to stdout
|
|
258
|
+
write_toml_config(sys.stdout, Settings)
|
|
259
|
+
|
|
260
|
+
# Write to file
|
|
261
|
+
write_toml_config("config.toml", Settings)
|
|
262
|
+
write_toml_config(Path("config.toml"), Settings)
|
|
263
|
+
|
|
264
|
+
# Write to StringIO
|
|
265
|
+
buffer = StringIO()
|
|
266
|
+
write_toml_config(buffer, Settings)
|
|
267
|
+
content = buffer.getvalue()
|
|
268
|
+
|
|
269
|
+
# Write to file object
|
|
270
|
+
with open("config.toml", "w") as f:
|
|
271
|
+
write_toml_config(f, Settings)
|
|
272
|
+
|
|
273
|
+
# Write with root field
|
|
274
|
+
write_toml_config(sys.stdout, MaxTokensConfig, root_field="plugins.max_tokens")
|
|
275
|
+
"""
|
|
276
|
+
# Generate config data if not provided
|
|
277
|
+
if config_data is None:
|
|
278
|
+
config_data = generate_config_from_model(model_class, include_hidden)
|
|
279
|
+
|
|
280
|
+
# Generate TOML string
|
|
281
|
+
toml_string = generate_toml_config(
|
|
282
|
+
config_data=config_data,
|
|
283
|
+
model_class=model_class,
|
|
284
|
+
header_comment=header_comment,
|
|
285
|
+
commented=commented,
|
|
286
|
+
root_field=root_field,
|
|
287
|
+
)
|
|
288
|
+
|
|
289
|
+
# Determine output type and write
|
|
290
|
+
if isinstance(output, str | Path):
|
|
291
|
+
# Write to file path
|
|
292
|
+
Path(output).write_text(toml_string, encoding="utf-8")
|
|
293
|
+
else:
|
|
294
|
+
# Write to stream (TextIO, stdout, StringIO, etc.)
|
|
295
|
+
output.write(toml_string)
|
|
296
|
+
if output not in (sys.stdout, sys.stderr):
|
|
297
|
+
# Ensure trailing newline for files (not needed for stdout/stderr)
|
|
298
|
+
if not toml_string.endswith("\n"):
|
|
299
|
+
output.write("\n")
|