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
|
@@ -1,16 +1,18 @@
|
|
|
1
|
-
"""Prometheus Pushgateway integration for
|
|
1
|
+
"""Prometheus Pushgateway integration for the metrics plugin."""
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import time
|
|
6
6
|
from typing import Any
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
import httpx
|
|
9
9
|
|
|
10
|
-
from ccproxy.
|
|
10
|
+
from ccproxy.core.logging import get_plugin_logger
|
|
11
11
|
|
|
12
|
+
from .config import MetricsConfig
|
|
12
13
|
|
|
13
|
-
|
|
14
|
+
|
|
15
|
+
logger = get_plugin_logger(__name__)
|
|
14
16
|
|
|
15
17
|
|
|
16
18
|
# Import prometheus_client with graceful degradation (matching existing metrics.py pattern)
|
|
@@ -92,22 +94,30 @@ class PushgatewayClient:
|
|
|
92
94
|
Also supports VictoriaMetrics remote write protocol for compatibility.
|
|
93
95
|
"""
|
|
94
96
|
|
|
95
|
-
def __init__(self,
|
|
97
|
+
def __init__(self, config: MetricsConfig) -> None:
|
|
96
98
|
"""Initialize Pushgateway client.
|
|
97
99
|
|
|
98
100
|
Args:
|
|
99
|
-
|
|
101
|
+
config: Metrics plugin configuration
|
|
100
102
|
"""
|
|
101
|
-
self.
|
|
103
|
+
self.config = config
|
|
102
104
|
# Pushgateway is enabled if URL is configured and prometheus_client is available
|
|
103
|
-
self._enabled =
|
|
105
|
+
self._enabled = (
|
|
106
|
+
PROMETHEUS_AVAILABLE
|
|
107
|
+
and bool(config.pushgateway_url)
|
|
108
|
+
and config.pushgateway_enabled
|
|
109
|
+
)
|
|
104
110
|
self._circuit_breaker = CircuitBreaker(
|
|
105
111
|
failure_threshold=5,
|
|
106
112
|
recovery_timeout=60.0,
|
|
107
113
|
)
|
|
108
114
|
|
|
109
115
|
# Only log if pushgateway URL is configured but prometheus is not available
|
|
110
|
-
if
|
|
116
|
+
if (
|
|
117
|
+
config.pushgateway_url
|
|
118
|
+
and config.pushgateway_enabled
|
|
119
|
+
and not PROMETHEUS_AVAILABLE
|
|
120
|
+
):
|
|
111
121
|
logger.warning(
|
|
112
122
|
"prometheus_client not available. Pushgateway will be disabled. "
|
|
113
123
|
"Install with: pip install prometheus-client"
|
|
@@ -124,7 +134,7 @@ class PushgatewayClient:
|
|
|
124
134
|
True if push succeeded, False otherwise
|
|
125
135
|
"""
|
|
126
136
|
|
|
127
|
-
if not self._enabled or not self.
|
|
137
|
+
if not self._enabled or not self.config.pushgateway_url:
|
|
128
138
|
return False
|
|
129
139
|
|
|
130
140
|
# Check circuit breaker before attempting operation
|
|
@@ -138,7 +148,7 @@ class PushgatewayClient:
|
|
|
138
148
|
|
|
139
149
|
try:
|
|
140
150
|
# Check if URL looks like VictoriaMetrics remote write endpoint
|
|
141
|
-
if "/api/v1/write" in self.
|
|
151
|
+
if "/api/v1/write" in self.config.pushgateway_url:
|
|
142
152
|
success = self._push_remote_write(registry)
|
|
143
153
|
else:
|
|
144
154
|
success = self._push_standard(registry, method)
|
|
@@ -154,11 +164,12 @@ class PushgatewayClient:
|
|
|
154
164
|
self._circuit_breaker.record_failure()
|
|
155
165
|
logger.error(
|
|
156
166
|
"pushgateway_push_failed",
|
|
157
|
-
url=self.
|
|
158
|
-
job=self.
|
|
167
|
+
url=self.config.pushgateway_url,
|
|
168
|
+
job=self.config.pushgateway_job,
|
|
159
169
|
method=method,
|
|
160
170
|
error=str(e),
|
|
161
171
|
error_type=type(e).__name__,
|
|
172
|
+
exc_info=e,
|
|
162
173
|
)
|
|
163
174
|
return False
|
|
164
175
|
|
|
@@ -169,27 +180,27 @@ class PushgatewayClient:
|
|
|
169
180
|
registry: Prometheus metrics registry
|
|
170
181
|
method: Push method - "push" (replace), "pushadd" (add), or "delete"
|
|
171
182
|
"""
|
|
172
|
-
if not self.
|
|
183
|
+
if not self.config.pushgateway_url:
|
|
173
184
|
return False
|
|
174
185
|
|
|
175
186
|
try:
|
|
176
187
|
# Use the appropriate prometheus_client function based on method
|
|
177
188
|
if method == "push":
|
|
178
189
|
push_to_gateway(
|
|
179
|
-
gateway=self.
|
|
180
|
-
job=self.
|
|
190
|
+
gateway=self.config.pushgateway_url,
|
|
191
|
+
job=self.config.pushgateway_job,
|
|
181
192
|
registry=registry,
|
|
182
193
|
)
|
|
183
194
|
elif method == "pushadd":
|
|
184
195
|
pushadd_to_gateway(
|
|
185
|
-
gateway=self.
|
|
186
|
-
job=self.
|
|
196
|
+
gateway=self.config.pushgateway_url,
|
|
197
|
+
job=self.config.pushgateway_job,
|
|
187
198
|
registry=registry,
|
|
188
199
|
)
|
|
189
200
|
elif method == "delete":
|
|
190
201
|
delete_from_gateway(
|
|
191
|
-
gateway=self.
|
|
192
|
-
job=self.
|
|
202
|
+
gateway=self.config.pushgateway_url,
|
|
203
|
+
job=self.config.pushgateway_job,
|
|
193
204
|
)
|
|
194
205
|
else:
|
|
195
206
|
logger.error("pushgateway_invalid_method", method=method)
|
|
@@ -197,8 +208,8 @@ class PushgatewayClient:
|
|
|
197
208
|
|
|
198
209
|
logger.debug(
|
|
199
210
|
"pushgateway_push_success",
|
|
200
|
-
url=self.
|
|
201
|
-
job=self.
|
|
211
|
+
url=self.config.pushgateway_url,
|
|
212
|
+
job=self.config.pushgateway_job,
|
|
202
213
|
protocol="standard",
|
|
203
214
|
method=method,
|
|
204
215
|
)
|
|
@@ -207,11 +218,12 @@ class PushgatewayClient:
|
|
|
207
218
|
except Exception as e:
|
|
208
219
|
logger.error(
|
|
209
220
|
"pushgateway_standard_push_failed",
|
|
210
|
-
url=self.
|
|
211
|
-
job=self.
|
|
221
|
+
url=self.config.pushgateway_url,
|
|
222
|
+
job=self.config.pushgateway_job,
|
|
212
223
|
method=method,
|
|
213
224
|
error=str(e),
|
|
214
225
|
error_type=type(e).__name__,
|
|
226
|
+
exc_info=e,
|
|
215
227
|
)
|
|
216
228
|
return False
|
|
217
229
|
|
|
@@ -222,10 +234,9 @@ class PushgatewayClient:
|
|
|
222
234
|
via the /api/v1/import/prometheus endpoint, which is simpler than
|
|
223
235
|
the full remote write protocol that requires protobuf encoding.
|
|
224
236
|
"""
|
|
225
|
-
import httpx
|
|
226
237
|
from prometheus_client.exposition import generate_latest
|
|
227
238
|
|
|
228
|
-
if not self.
|
|
239
|
+
if not self.config.pushgateway_url:
|
|
229
240
|
return False
|
|
230
241
|
|
|
231
242
|
# Generate metrics in Prometheus exposition format
|
|
@@ -233,13 +244,13 @@ class PushgatewayClient:
|
|
|
233
244
|
|
|
234
245
|
# Convert /api/v1/write URL to /api/v1/import/prometheus for VictoriaMetrics
|
|
235
246
|
# This endpoint accepts Prometheus exposition format directly
|
|
236
|
-
if "/api/v1/write" in self.
|
|
237
|
-
import_url = self.
|
|
247
|
+
if "/api/v1/write" in self.config.pushgateway_url:
|
|
248
|
+
import_url = self.config.pushgateway_url.replace(
|
|
238
249
|
"/api/v1/write", "/api/v1/import/prometheus"
|
|
239
250
|
)
|
|
240
251
|
else:
|
|
241
252
|
# Fallback - assume it's already the correct import URL
|
|
242
|
-
import_url = self.
|
|
253
|
+
import_url = self.config.pushgateway_url
|
|
243
254
|
|
|
244
255
|
try:
|
|
245
256
|
# VictoriaMetrics import endpoint accepts text/plain exposition format
|
|
@@ -257,7 +268,7 @@ class PushgatewayClient:
|
|
|
257
268
|
logger.debug(
|
|
258
269
|
"pushgateway_import_success",
|
|
259
270
|
url=import_url,
|
|
260
|
-
job=self.
|
|
271
|
+
job=self.config.pushgateway_job,
|
|
261
272
|
protocol="victoriametrics_import",
|
|
262
273
|
status=response.status_code,
|
|
263
274
|
)
|
|
@@ -276,6 +287,16 @@ class PushgatewayClient:
|
|
|
276
287
|
url=import_url,
|
|
277
288
|
error=str(e),
|
|
278
289
|
error_type=type(e).__name__,
|
|
290
|
+
exc_info=e,
|
|
291
|
+
)
|
|
292
|
+
return False
|
|
293
|
+
except Exception as e:
|
|
294
|
+
logger.error(
|
|
295
|
+
"pushgateway_import_unexpected_error",
|
|
296
|
+
url=import_url,
|
|
297
|
+
error=str(e),
|
|
298
|
+
error_type=type(e).__name__,
|
|
299
|
+
exc_info=e,
|
|
279
300
|
)
|
|
280
301
|
return False
|
|
281
302
|
|
|
@@ -297,7 +318,7 @@ class PushgatewayClient:
|
|
|
297
318
|
True if delete succeeded, False otherwise
|
|
298
319
|
"""
|
|
299
320
|
|
|
300
|
-
if not self._enabled or not self.
|
|
321
|
+
if not self._enabled or not self.config.pushgateway_url:
|
|
301
322
|
return False
|
|
302
323
|
|
|
303
324
|
# Check circuit breaker before attempting operation
|
|
@@ -311,7 +332,7 @@ class PushgatewayClient:
|
|
|
311
332
|
|
|
312
333
|
try:
|
|
313
334
|
# Only standard pushgateway supports delete operation
|
|
314
|
-
if "/api/v1/write" in self.
|
|
335
|
+
if "/api/v1/write" in self.config.pushgateway_url:
|
|
315
336
|
logger.warning("pushgateway_delete_not_supported_for_remote_write")
|
|
316
337
|
return False
|
|
317
338
|
else:
|
|
@@ -328,37 +349,14 @@ class PushgatewayClient:
|
|
|
328
349
|
self._circuit_breaker.record_failure()
|
|
329
350
|
logger.error(
|
|
330
351
|
"pushgateway_delete_failed",
|
|
331
|
-
url=self.
|
|
332
|
-
job=self.
|
|
352
|
+
url=self.config.pushgateway_url,
|
|
353
|
+
job=self.config.pushgateway_job,
|
|
333
354
|
error=str(e),
|
|
334
355
|
error_type=type(e).__name__,
|
|
356
|
+
exc_info=e,
|
|
335
357
|
)
|
|
336
358
|
return False
|
|
337
359
|
|
|
338
360
|
def is_enabled(self) -> bool:
|
|
339
361
|
"""Check if Pushgateway client is enabled and configured."""
|
|
340
|
-
return self._enabled and bool(self.
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
# Global pushgateway client instance
|
|
344
|
-
_global_pushgateway_client: PushgatewayClient | None = None
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
def get_pushgateway_client() -> PushgatewayClient:
|
|
348
|
-
"""Get or create global pushgateway client instance."""
|
|
349
|
-
global _global_pushgateway_client
|
|
350
|
-
|
|
351
|
-
if _global_pushgateway_client is None:
|
|
352
|
-
# Import here to avoid circular imports
|
|
353
|
-
from ccproxy.config.settings import get_settings
|
|
354
|
-
|
|
355
|
-
settings = get_settings()
|
|
356
|
-
_global_pushgateway_client = PushgatewayClient(settings.observability)
|
|
357
|
-
|
|
358
|
-
return _global_pushgateway_client
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
def reset_pushgateway_client() -> None:
|
|
362
|
-
"""Reset global pushgateway client instance (mainly for testing)."""
|
|
363
|
-
global _global_pushgateway_client
|
|
364
|
-
_global_pushgateway_client = None
|
|
362
|
+
return self._enabled and bool(self.config.pushgateway_url)
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"""Metrics endpoints for the metrics plugin."""
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from fastapi import APIRouter, HTTPException, Response
|
|
6
|
+
|
|
7
|
+
from ccproxy.core.logging import get_plugin_logger
|
|
8
|
+
|
|
9
|
+
from .collector import PrometheusMetrics
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
logger = get_plugin_logger(__name__)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def create_metrics_router(collector: PrometheusMetrics | None) -> APIRouter:
|
|
16
|
+
"""Create metrics router with the given collector.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
collector: Prometheus metrics collector instance
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
FastAPI router with metrics endpoints
|
|
23
|
+
"""
|
|
24
|
+
router = APIRouter(tags=["metrics"])
|
|
25
|
+
|
|
26
|
+
@router.get("/metrics")
|
|
27
|
+
async def get_prometheus_metrics() -> Response:
|
|
28
|
+
"""Export metrics in Prometheus format.
|
|
29
|
+
|
|
30
|
+
This endpoint exposes operational metrics collected by the metrics plugin
|
|
31
|
+
for Prometheus scraping.
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
Prometheus-formatted metrics text
|
|
35
|
+
"""
|
|
36
|
+
if not collector or not collector.is_enabled():
|
|
37
|
+
raise HTTPException(
|
|
38
|
+
status_code=503,
|
|
39
|
+
detail="Metrics collection not enabled. Ensure prometheus-client is installed.",
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
try:
|
|
43
|
+
# Check if prometheus_client is available
|
|
44
|
+
try:
|
|
45
|
+
from prometheus_client import CONTENT_TYPE_LATEST, generate_latest
|
|
46
|
+
except ImportError as err:
|
|
47
|
+
raise HTTPException(
|
|
48
|
+
status_code=503,
|
|
49
|
+
detail="Prometheus client not available. Install with: pip install prometheus-client",
|
|
50
|
+
) from err
|
|
51
|
+
|
|
52
|
+
# Generate prometheus format using the registry
|
|
53
|
+
from prometheus_client import REGISTRY
|
|
54
|
+
|
|
55
|
+
# Use the collector's registry or fall back to global
|
|
56
|
+
registry = (
|
|
57
|
+
collector.registry if collector.registry is not None else REGISTRY
|
|
58
|
+
)
|
|
59
|
+
prometheus_data = generate_latest(registry)
|
|
60
|
+
|
|
61
|
+
# Return the metrics data with proper content type
|
|
62
|
+
return Response(
|
|
63
|
+
content=prometheus_data,
|
|
64
|
+
media_type=CONTENT_TYPE_LATEST,
|
|
65
|
+
headers={
|
|
66
|
+
"Cache-Control": "no-cache, no-store, must-revalidate",
|
|
67
|
+
"Pragma": "no-cache",
|
|
68
|
+
"Expires": "0",
|
|
69
|
+
},
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
except HTTPException:
|
|
73
|
+
raise
|
|
74
|
+
except ImportError as e:
|
|
75
|
+
logger.error(
|
|
76
|
+
"prometheus_import_error",
|
|
77
|
+
error=str(e),
|
|
78
|
+
exc_info=e,
|
|
79
|
+
)
|
|
80
|
+
raise HTTPException(
|
|
81
|
+
status_code=503, detail=f"Prometheus dependencies missing: {str(e)}"
|
|
82
|
+
) from e
|
|
83
|
+
except Exception as e:
|
|
84
|
+
logger.error(
|
|
85
|
+
"metrics_generation_error",
|
|
86
|
+
error=str(e),
|
|
87
|
+
exc_info=e,
|
|
88
|
+
)
|
|
89
|
+
raise HTTPException(
|
|
90
|
+
status_code=500,
|
|
91
|
+
detail=f"Failed to generate Prometheus metrics: {str(e)}",
|
|
92
|
+
) from e
|
|
93
|
+
|
|
94
|
+
@router.get("/metrics/health")
|
|
95
|
+
async def metrics_health() -> dict[str, Any]:
|
|
96
|
+
"""Get metrics system health status.
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
Health status of the metrics collection system
|
|
100
|
+
"""
|
|
101
|
+
return {
|
|
102
|
+
"status": "healthy" if collector and collector.is_enabled() else "disabled",
|
|
103
|
+
"prometheus_enabled": collector.is_enabled() if collector else False,
|
|
104
|
+
"namespace": collector.namespace if collector else None,
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return router
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"""Scheduled tasks for the metrics plugin."""
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from ccproxy.core.logging import get_plugin_logger
|
|
6
|
+
from ccproxy.scheduler.tasks import BaseScheduledTask
|
|
7
|
+
|
|
8
|
+
from .pushgateway import PushgatewayClient
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
logger = get_plugin_logger(__name__)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class PushgatewayTask(BaseScheduledTask):
|
|
15
|
+
"""Task for pushing metrics to Pushgateway periodically."""
|
|
16
|
+
|
|
17
|
+
def __init__(
|
|
18
|
+
self,
|
|
19
|
+
name: str,
|
|
20
|
+
interval_seconds: float,
|
|
21
|
+
enabled: bool = True,
|
|
22
|
+
max_backoff_seconds: float = 300.0,
|
|
23
|
+
metrics_config: Any | None = None,
|
|
24
|
+
metrics_hook: Any | None = None,
|
|
25
|
+
):
|
|
26
|
+
"""
|
|
27
|
+
Initialize pushgateway task.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
name: Task name
|
|
31
|
+
interval_seconds: Interval between pushgateway operations
|
|
32
|
+
enabled: Whether task is enabled
|
|
33
|
+
max_backoff_seconds: Maximum backoff delay for failures
|
|
34
|
+
metrics_config: Metrics plugin configuration
|
|
35
|
+
metrics_hook: Metrics hook instance for getting collector
|
|
36
|
+
"""
|
|
37
|
+
super().__init__(
|
|
38
|
+
name=name,
|
|
39
|
+
interval_seconds=interval_seconds,
|
|
40
|
+
enabled=enabled,
|
|
41
|
+
max_backoff_seconds=max_backoff_seconds,
|
|
42
|
+
)
|
|
43
|
+
self._metrics_config = metrics_config
|
|
44
|
+
self._metrics_hook = metrics_hook
|
|
45
|
+
self._pushgateway_client: PushgatewayClient | None = None
|
|
46
|
+
|
|
47
|
+
async def setup(self) -> None:
|
|
48
|
+
"""Initialize pushgateway client for operations."""
|
|
49
|
+
try:
|
|
50
|
+
if self._metrics_config and self._metrics_hook:
|
|
51
|
+
self._pushgateway_client = PushgatewayClient(self._metrics_config)
|
|
52
|
+
logger.debug(
|
|
53
|
+
"pushgateway_task_setup_complete",
|
|
54
|
+
task_name=self.name,
|
|
55
|
+
url=self._metrics_config.pushgateway_url,
|
|
56
|
+
job=self._metrics_config.pushgateway_job,
|
|
57
|
+
)
|
|
58
|
+
else:
|
|
59
|
+
logger.warning(
|
|
60
|
+
"pushgateway_task_setup_missing_config",
|
|
61
|
+
task_name=self.name,
|
|
62
|
+
has_config=self._metrics_config is not None,
|
|
63
|
+
has_hook=self._metrics_hook is not None,
|
|
64
|
+
)
|
|
65
|
+
except Exception as e:
|
|
66
|
+
logger.error(
|
|
67
|
+
"pushgateway_task_setup_failed",
|
|
68
|
+
task_name=self.name,
|
|
69
|
+
error=str(e),
|
|
70
|
+
error_type=type(e).__name__,
|
|
71
|
+
exc_info=e,
|
|
72
|
+
)
|
|
73
|
+
raise
|
|
74
|
+
|
|
75
|
+
async def run(self) -> bool:
|
|
76
|
+
"""Execute pushgateway metrics push."""
|
|
77
|
+
try:
|
|
78
|
+
if not self._pushgateway_client or not self._metrics_hook:
|
|
79
|
+
logger.warning(
|
|
80
|
+
"pushgateway_no_client_or_hook",
|
|
81
|
+
task_name=self.name,
|
|
82
|
+
has_client=self._pushgateway_client is not None,
|
|
83
|
+
has_hook=self._metrics_hook is not None,
|
|
84
|
+
)
|
|
85
|
+
return False
|
|
86
|
+
|
|
87
|
+
if not self._pushgateway_client.is_enabled():
|
|
88
|
+
logger.debug("pushgateway_disabled", task_name=self.name)
|
|
89
|
+
return True # Not an error, just disabled
|
|
90
|
+
|
|
91
|
+
# Get the metrics collector and push metrics
|
|
92
|
+
collector = self._metrics_hook.get_collector()
|
|
93
|
+
if not collector:
|
|
94
|
+
logger.warning("pushgateway_no_collector", task_name=self.name)
|
|
95
|
+
return False
|
|
96
|
+
|
|
97
|
+
# Push metrics using the client
|
|
98
|
+
success = self._pushgateway_client.push_metrics(
|
|
99
|
+
collector.get_registry(), method="push"
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
if success:
|
|
103
|
+
logger.debug("pushgateway_push_success", task_name=self.name)
|
|
104
|
+
else:
|
|
105
|
+
logger.warning("pushgateway_push_failed", task_name=self.name)
|
|
106
|
+
|
|
107
|
+
return success
|
|
108
|
+
|
|
109
|
+
except Exception as e:
|
|
110
|
+
logger.error(
|
|
111
|
+
"pushgateway_task_error",
|
|
112
|
+
task_name=self.name,
|
|
113
|
+
error=str(e),
|
|
114
|
+
error_type=type(e).__name__,
|
|
115
|
+
exc_info=e,
|
|
116
|
+
)
|
|
117
|
+
return False
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# OAuth Claude Plugin
|
|
2
|
+
|
|
3
|
+
Standalone OAuth provider for managing Claude API access tokens.
|
|
4
|
+
|
|
5
|
+
## Highlights
|
|
6
|
+
- Implements `ClaudeOAuthProvider` for authorization-code and refresh flows
|
|
7
|
+
- Integrates with the auth runtime to expose a reusable auth manager
|
|
8
|
+
- Shares detection utilities to diagnose CLI and token availability
|
|
9
|
+
|
|
10
|
+
## Configuration
|
|
11
|
+
- `ClaudeOAuthConfig` sets client credentials, scopes, and storage paths
|
|
12
|
+
- Works alongside `claude_api` or credential balancer powered providers
|
|
13
|
+
- Generate defaults with `python3 scripts/generate_config_from_model.py \
|
|
14
|
+
--format toml --plugin oauth_claude --config-class ClaudeOAuthConfig`
|
|
15
|
+
|
|
16
|
+
```toml
|
|
17
|
+
[plugins.oauth_claude]
|
|
18
|
+
# enabled = true
|
|
19
|
+
# base_url = "https://console.anthropic.com"
|
|
20
|
+
# token_url = "https://console.anthropic.com/v1/oauth/token"
|
|
21
|
+
# authorize_url = "https://claude.ai/oauth/authorize"
|
|
22
|
+
# profile_url = "https://api.anthropic.com/api/oauth/profile"
|
|
23
|
+
# client_id = "9d1c250a-e61b-44d9-88ed-5944d1962f5e"
|
|
24
|
+
# redirect_uri = "http://localhost:35593/callback"
|
|
25
|
+
# scopes = ["org:create_api_key", "user:profile", "user:inference"]
|
|
26
|
+
# request_timeout = 30
|
|
27
|
+
# callback_timeout = 300
|
|
28
|
+
# callback_port = 35593
|
|
29
|
+
# use_pkce = true
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Related Components
|
|
33
|
+
- `provider.py`: OAuth implementation and token storage helpers
|
|
34
|
+
- `plugin.py`: runtime wiring for auth-only plugin
|
|
35
|
+
- `config.py`: settings model for Claude OAuth parameters
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""OAuth Claude plugin for standalone Claude OAuth authentication."""
|
|
2
|
+
|
|
3
|
+
from .client import ClaudeOAuthClient
|
|
4
|
+
from .config import ClaudeOAuthConfig
|
|
5
|
+
from .provider import ClaudeOAuthProvider
|
|
6
|
+
from .storage import ClaudeOAuthStorage
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"ClaudeOAuthClient",
|
|
11
|
+
"ClaudeOAuthConfig",
|
|
12
|
+
"ClaudeOAuthProvider",
|
|
13
|
+
"ClaudeOAuthStorage",
|
|
14
|
+
]
|