ccproxy-api 0.1.7__py3-none-any.whl → 0.2.0a4__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.0a4.dist-info/METADATA +212 -0
- ccproxy_api-0.2.0a4.dist-info/RECORD +417 -0
- {ccproxy_api-0.1.7.dist-info → ccproxy_api-0.2.0a4.dist-info}/WHEEL +1 -1
- ccproxy_api-0.2.0a4.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.0a4.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
"""Docker plugin with CLI extensions."""
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
import ccproxy.core.logging
|
|
6
|
+
from ccproxy.core.plugins import (
|
|
7
|
+
BaseProviderPluginFactory,
|
|
8
|
+
PluginContext,
|
|
9
|
+
PluginManifest,
|
|
10
|
+
ProviderPluginRuntime,
|
|
11
|
+
)
|
|
12
|
+
from ccproxy.core.plugins.declaration import CliArgumentSpec
|
|
13
|
+
|
|
14
|
+
from .adapter import DockerAdapter
|
|
15
|
+
from .config import DockerConfig
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
logger = ccproxy.core.logging.get_plugin_logger(__name__)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class DockerRuntime(ProviderPluginRuntime):
|
|
22
|
+
"""Runtime for Docker plugin."""
|
|
23
|
+
|
|
24
|
+
def __init__(self, manifest: PluginManifest):
|
|
25
|
+
"""Initialize runtime."""
|
|
26
|
+
super().__init__(manifest)
|
|
27
|
+
|
|
28
|
+
async def _on_initialize(self) -> None:
|
|
29
|
+
"""Initialize the Docker plugin."""
|
|
30
|
+
await super()._on_initialize()
|
|
31
|
+
|
|
32
|
+
if not self.context:
|
|
33
|
+
raise RuntimeError("Context not set")
|
|
34
|
+
|
|
35
|
+
# Get CLI arguments from context
|
|
36
|
+
settings = self.context.get("settings")
|
|
37
|
+
if settings:
|
|
38
|
+
cli_context = settings.get_cli_context()
|
|
39
|
+
|
|
40
|
+
# Process Docker CLI flags and update config
|
|
41
|
+
config = self.context.get("config")
|
|
42
|
+
if config and isinstance(config, DockerConfig):
|
|
43
|
+
self._apply_cli_overrides(cli_context, config)
|
|
44
|
+
|
|
45
|
+
config = self.context.get("config")
|
|
46
|
+
docker_image = (
|
|
47
|
+
config.docker_image if config and isinstance(config, DockerConfig) else None
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
logger.debug(
|
|
51
|
+
"plugin_initialized",
|
|
52
|
+
plugin="docker",
|
|
53
|
+
version="0.1.0",
|
|
54
|
+
status="initialized",
|
|
55
|
+
docker_image=docker_image,
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
def _apply_cli_overrides(
|
|
59
|
+
self, cli_context: dict[str, Any], config: DockerConfig
|
|
60
|
+
) -> None:
|
|
61
|
+
"""Apply CLI flag overrides to Docker config."""
|
|
62
|
+
# Apply CLI overrides to config
|
|
63
|
+
if cli_context.get("docker_image"):
|
|
64
|
+
config.docker_image = cli_context["docker_image"]
|
|
65
|
+
|
|
66
|
+
if cli_context.get("docker_home"):
|
|
67
|
+
config.docker_home_directory = cli_context["docker_home"]
|
|
68
|
+
|
|
69
|
+
if cli_context.get("docker_workspace"):
|
|
70
|
+
config.docker_workspace_directory = cli_context["docker_workspace"]
|
|
71
|
+
|
|
72
|
+
if cli_context.get("docker_env"):
|
|
73
|
+
config.docker_environment.extend(cli_context["docker_env"])
|
|
74
|
+
|
|
75
|
+
if cli_context.get("docker_volume"):
|
|
76
|
+
config.docker_volumes.extend(cli_context["docker_volume"])
|
|
77
|
+
|
|
78
|
+
if cli_context.get("user_mapping_enabled") is not None:
|
|
79
|
+
config.user_mapping_enabled = cli_context["user_mapping_enabled"]
|
|
80
|
+
|
|
81
|
+
if cli_context.get("user_uid"):
|
|
82
|
+
config.user_uid = cli_context["user_uid"]
|
|
83
|
+
|
|
84
|
+
if cli_context.get("user_gid"):
|
|
85
|
+
config.user_gid = cli_context["user_gid"]
|
|
86
|
+
|
|
87
|
+
logger.debug("docker_cli_overrides_applied", cli_overrides=cli_context)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class DockerFactory(BaseProviderPluginFactory):
|
|
91
|
+
"""Factory for Docker plugin."""
|
|
92
|
+
|
|
93
|
+
# Plugin configuration via class attributes
|
|
94
|
+
plugin_name = "docker"
|
|
95
|
+
plugin_description = "Docker container management for CCProxy"
|
|
96
|
+
runtime_class = DockerRuntime
|
|
97
|
+
adapter_class = DockerAdapter
|
|
98
|
+
config_class = DockerConfig
|
|
99
|
+
|
|
100
|
+
# CLI extension declarations - all Docker-related CLI arguments
|
|
101
|
+
cli_arguments = [
|
|
102
|
+
CliArgumentSpec(
|
|
103
|
+
target_command="serve",
|
|
104
|
+
argument_name="docker",
|
|
105
|
+
argument_type=bool,
|
|
106
|
+
help_text="Run using Docker instead of local execution",
|
|
107
|
+
default=False,
|
|
108
|
+
typer_kwargs={
|
|
109
|
+
"is_flag": True,
|
|
110
|
+
"flag_value": True,
|
|
111
|
+
"option": ["--docker", "-d"],
|
|
112
|
+
},
|
|
113
|
+
),
|
|
114
|
+
CliArgumentSpec(
|
|
115
|
+
target_command="serve",
|
|
116
|
+
argument_name="docker_image",
|
|
117
|
+
argument_type=str,
|
|
118
|
+
help_text="Docker image to use (overrides configuration)",
|
|
119
|
+
typer_kwargs={"rich_help_panel": "Docker Settings"},
|
|
120
|
+
),
|
|
121
|
+
CliArgumentSpec(
|
|
122
|
+
target_command="serve",
|
|
123
|
+
argument_name="docker_env",
|
|
124
|
+
argument_type=list[str],
|
|
125
|
+
help_text="Environment variables to pass to Docker container",
|
|
126
|
+
typer_kwargs={
|
|
127
|
+
"rich_help_panel": "Docker Settings",
|
|
128
|
+
"option": ["--docker-env", "-e"],
|
|
129
|
+
},
|
|
130
|
+
),
|
|
131
|
+
CliArgumentSpec(
|
|
132
|
+
target_command="serve",
|
|
133
|
+
argument_name="docker_volume",
|
|
134
|
+
argument_type=list[str],
|
|
135
|
+
help_text="Volume mounts for Docker container",
|
|
136
|
+
typer_kwargs={
|
|
137
|
+
"rich_help_panel": "Docker Settings",
|
|
138
|
+
"option": ["--docker-volume", "-v"],
|
|
139
|
+
},
|
|
140
|
+
),
|
|
141
|
+
CliArgumentSpec(
|
|
142
|
+
target_command="serve",
|
|
143
|
+
argument_name="docker_arg",
|
|
144
|
+
argument_type=list[str],
|
|
145
|
+
help_text="Additional arguments to pass to docker run",
|
|
146
|
+
typer_kwargs={"rich_help_panel": "Docker Settings"},
|
|
147
|
+
),
|
|
148
|
+
CliArgumentSpec(
|
|
149
|
+
target_command="serve",
|
|
150
|
+
argument_name="docker_home",
|
|
151
|
+
argument_type=str,
|
|
152
|
+
help_text="Override the home directory for Docker",
|
|
153
|
+
typer_kwargs={"rich_help_panel": "Docker Settings"},
|
|
154
|
+
),
|
|
155
|
+
CliArgumentSpec(
|
|
156
|
+
target_command="serve",
|
|
157
|
+
argument_name="docker_workspace",
|
|
158
|
+
argument_type=str,
|
|
159
|
+
help_text="Override the workspace directory for Docker",
|
|
160
|
+
typer_kwargs={"rich_help_panel": "Docker Settings"},
|
|
161
|
+
),
|
|
162
|
+
CliArgumentSpec(
|
|
163
|
+
target_command="serve",
|
|
164
|
+
argument_name="user_mapping_enabled",
|
|
165
|
+
argument_type=bool,
|
|
166
|
+
help_text="Enable user mapping for Docker",
|
|
167
|
+
typer_kwargs={
|
|
168
|
+
"rich_help_panel": "Docker Settings",
|
|
169
|
+
"option": ["--user-mapping/--no-user-mapping"],
|
|
170
|
+
},
|
|
171
|
+
),
|
|
172
|
+
CliArgumentSpec(
|
|
173
|
+
target_command="serve",
|
|
174
|
+
argument_name="user_uid",
|
|
175
|
+
argument_type=int,
|
|
176
|
+
help_text="User UID for Docker user mapping",
|
|
177
|
+
typer_kwargs={"rich_help_panel": "Docker Settings"},
|
|
178
|
+
),
|
|
179
|
+
CliArgumentSpec(
|
|
180
|
+
target_command="serve",
|
|
181
|
+
argument_name="user_gid",
|
|
182
|
+
argument_type=int,
|
|
183
|
+
help_text="User GID for Docker user mapping",
|
|
184
|
+
typer_kwargs={"rich_help_panel": "Docker Settings"},
|
|
185
|
+
),
|
|
186
|
+
]
|
|
187
|
+
|
|
188
|
+
async def create_adapter(self, context: PluginContext) -> DockerAdapter:
|
|
189
|
+
"""Create Docker adapter instance."""
|
|
190
|
+
config = context.get("config")
|
|
191
|
+
if not isinstance(config, DockerConfig):
|
|
192
|
+
config = DockerConfig()
|
|
193
|
+
|
|
194
|
+
return DockerAdapter(config=config)
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
# Export factory instance
|
|
198
|
+
factory = DockerFactory()
|
|
@@ -6,7 +6,7 @@ for real-time output handling in CLI applications.
|
|
|
6
6
|
|
|
7
7
|
Example:
|
|
8
8
|
```python
|
|
9
|
-
from ccproxy.docker.stream_process import run_command, DefaultOutputMiddleware
|
|
9
|
+
from ccproxy.plugins.docker.stream_process import run_command, DefaultOutputMiddleware
|
|
10
10
|
|
|
11
11
|
# Create custom middleware to add timestamps
|
|
12
12
|
from datetime import datetime
|
|
@@ -162,8 +162,8 @@ def create_chained_middleware(
|
|
|
162
162
|
|
|
163
163
|
Example:
|
|
164
164
|
```python
|
|
165
|
-
from ccproxy.docker.stream_process import create_chained_middleware
|
|
166
|
-
from ccproxy.docker.adapter import LoggerOutputMiddleware
|
|
165
|
+
from ccproxy.plugins.docker.stream_process import create_chained_middleware
|
|
166
|
+
from ccproxy.plugins.docker.adapter import LoggerOutputMiddleware
|
|
167
167
|
|
|
168
168
|
# Create individual middleware components
|
|
169
169
|
logger_middleware = LoggerOutputMiddleware(logger)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# DuckDB Storage Plugin
|
|
2
|
+
|
|
3
|
+
Provides DuckDB-backed storage for analytics and request logging data.
|
|
4
|
+
|
|
5
|
+
## Highlights
|
|
6
|
+
- Initializes a DuckDB database and exposes it via the plugin registry
|
|
7
|
+
- Creates directories automatically and reuses the configured database path
|
|
8
|
+
- Optionally runs VACUUM/OPTIMIZE on shutdown for compactness
|
|
9
|
+
|
|
10
|
+
## Configuration
|
|
11
|
+
- `DuckDBStorageConfig` toggles enablement, database path, and optimizations
|
|
12
|
+
- Other plugins reference the exposed `log_storage` service by name
|
|
13
|
+
- Generate defaults with `python3 scripts/generate_config_from_model.py \
|
|
14
|
+
--format toml --plugin duckdb_storage --config-class DuckDBStorageConfig`
|
|
15
|
+
|
|
16
|
+
```toml
|
|
17
|
+
[plugins.duckdb_storage]
|
|
18
|
+
# enabled = true
|
|
19
|
+
# database_path = "~/.local/share/ccproxy/metrics.duckdb"
|
|
20
|
+
# optimize_on_shutdown = false
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Related Components
|
|
24
|
+
- `plugin.py`: runtime lifecycle and service registration
|
|
25
|
+
- `storage.py`: `SimpleDuckDBStorage` helper for connections
|
|
26
|
+
- `routes.py`: FastAPI router under `/duckdb` for simple diagnostics
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""DuckDB storage plugin package."""
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from pydantic import BaseModel, Field
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class DuckDBStorageConfig(BaseModel):
|
|
5
|
+
"""Config for the DuckDB storage plugin.
|
|
6
|
+
|
|
7
|
+
Notes:
|
|
8
|
+
- By default this plugin mirrors core Observability settings and path.
|
|
9
|
+
- You can override the database path if needed via plugin config.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
enabled: bool = Field(
|
|
13
|
+
default=True,
|
|
14
|
+
description="Enable DuckDB storage plugin",
|
|
15
|
+
)
|
|
16
|
+
database_path: str | None = Field(
|
|
17
|
+
default=None, description="Optional override for DuckDB database path"
|
|
18
|
+
)
|
|
19
|
+
optimize_on_shutdown: bool = Field(
|
|
20
|
+
default=False,
|
|
21
|
+
description="Run PRAGMA optimize on shutdown (file-backed DB only)",
|
|
22
|
+
)
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from ccproxy.core.logging import get_plugin_logger
|
|
7
|
+
from ccproxy.core.plugins import (
|
|
8
|
+
PluginManifest,
|
|
9
|
+
RouteSpec,
|
|
10
|
+
SystemPluginFactory,
|
|
11
|
+
SystemPluginRuntime,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
from .config import DuckDBStorageConfig
|
|
15
|
+
from .storage import SimpleDuckDBStorage
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
logger = get_plugin_logger()
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _default_db_path() -> str:
|
|
22
|
+
# Mirrors previous default: XDG_DATA_HOME/ccproxy/metrics.duckdb
|
|
23
|
+
import os
|
|
24
|
+
|
|
25
|
+
return str(
|
|
26
|
+
Path(os.environ.get("XDG_DATA_HOME", Path.home() / ".local" / "share"))
|
|
27
|
+
/ "ccproxy"
|
|
28
|
+
/ "metrics.duckdb"
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class DuckDBStorageRuntime(SystemPluginRuntime):
|
|
33
|
+
"""Runtime for DuckDB storage plugin."""
|
|
34
|
+
|
|
35
|
+
def __init__(self, manifest: PluginManifest):
|
|
36
|
+
super().__init__(manifest)
|
|
37
|
+
self.config: DuckDBStorageConfig | None = None
|
|
38
|
+
self.storage: SimpleDuckDBStorage | None = None
|
|
39
|
+
|
|
40
|
+
async def _on_initialize(self) -> None:
|
|
41
|
+
if not self.context:
|
|
42
|
+
raise RuntimeError("Context not set")
|
|
43
|
+
|
|
44
|
+
# Resolve config
|
|
45
|
+
cfg = self.context.get("config")
|
|
46
|
+
if not isinstance(cfg, DuckDBStorageConfig):
|
|
47
|
+
logger.warning("plugin_no_config_using_defaults")
|
|
48
|
+
cfg = DuckDBStorageConfig()
|
|
49
|
+
self.config = cfg
|
|
50
|
+
|
|
51
|
+
# Determine if storage should be enabled: respect plugin flag and any
|
|
52
|
+
# app-wide observability needs (logs endpoints/collection) if present.
|
|
53
|
+
# Enable only if plugin config enables it
|
|
54
|
+
enabled = bool(cfg.enabled)
|
|
55
|
+
if not enabled:
|
|
56
|
+
logger.debug("duckdb_plugin_disabled", category="plugin")
|
|
57
|
+
return
|
|
58
|
+
|
|
59
|
+
# Resolve DB path
|
|
60
|
+
db_path = cfg.database_path or _default_db_path()
|
|
61
|
+
Path(db_path).parent.mkdir(parents=True, exist_ok=True)
|
|
62
|
+
|
|
63
|
+
# Initialize storage
|
|
64
|
+
self.storage = SimpleDuckDBStorage(database_path=db_path)
|
|
65
|
+
await self.storage.initialize()
|
|
66
|
+
|
|
67
|
+
# Expose storage via plugin registry and app.state
|
|
68
|
+
registry = self.context.get("plugin_registry")
|
|
69
|
+
if registry:
|
|
70
|
+
registry.register_service("log_storage", self.storage, self.manifest.name)
|
|
71
|
+
logger.debug(
|
|
72
|
+
"duckdb_storage_service_registered", path=db_path, category="plugin"
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
logger.info("duckdb_storage_initialized", path=db_path, category="plugin")
|
|
76
|
+
|
|
77
|
+
async def _on_shutdown(self) -> None:
|
|
78
|
+
if self.storage:
|
|
79
|
+
# Optional optimize on shutdown
|
|
80
|
+
if self.config and self.config.optimize_on_shutdown:
|
|
81
|
+
try:
|
|
82
|
+
self.storage.optimize()
|
|
83
|
+
except Exception as e: # pragma: no cover - best-effort
|
|
84
|
+
logger.warning("duckdb_optimize_on_shutdown_failed", error=str(e))
|
|
85
|
+
try:
|
|
86
|
+
await self.storage.close()
|
|
87
|
+
except Exception as e:
|
|
88
|
+
logger.warning("duckdb_storage_close_error", error=str(e))
|
|
89
|
+
self.storage = None
|
|
90
|
+
|
|
91
|
+
async def _get_health_details(self) -> dict[str, Any]:
|
|
92
|
+
has_service = False
|
|
93
|
+
if self.context:
|
|
94
|
+
reg = self.context.get("plugin_registry")
|
|
95
|
+
if reg is not None:
|
|
96
|
+
try:
|
|
97
|
+
has_service = reg.has_service("log_storage")
|
|
98
|
+
except Exception:
|
|
99
|
+
has_service = False
|
|
100
|
+
return {
|
|
101
|
+
"type": "system",
|
|
102
|
+
"initialized": self.initialized,
|
|
103
|
+
"enabled": bool(self.storage),
|
|
104
|
+
"has_service": has_service,
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
class DuckDBStorageFactory(SystemPluginFactory):
|
|
109
|
+
def __init__(self) -> None:
|
|
110
|
+
from .routes import router as duckdb_router
|
|
111
|
+
|
|
112
|
+
manifest = PluginManifest(
|
|
113
|
+
name="duckdb_storage",
|
|
114
|
+
version="0.1.0",
|
|
115
|
+
description="Provides DuckDB-backed request log storage",
|
|
116
|
+
is_provider=False,
|
|
117
|
+
provides=["log_storage"],
|
|
118
|
+
config_class=DuckDBStorageConfig,
|
|
119
|
+
routes=[RouteSpec(router=duckdb_router, prefix="/duckdb", tags=["duckdb"])],
|
|
120
|
+
)
|
|
121
|
+
super().__init__(manifest)
|
|
122
|
+
|
|
123
|
+
def create_runtime(self) -> DuckDBStorageRuntime:
|
|
124
|
+
return DuckDBStorageRuntime(self.manifest)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
# Export the factory instance for entry points
|
|
128
|
+
factory = DuckDBStorageFactory()
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any, cast
|
|
4
|
+
|
|
5
|
+
from fastapi import APIRouter, HTTPException, Request
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
router = APIRouter()
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _get_storage(request: Request) -> Any:
|
|
12
|
+
storage = getattr(request.app.state, "log_storage", None)
|
|
13
|
+
if not storage:
|
|
14
|
+
# Backward-compat alias
|
|
15
|
+
storage = getattr(request.app.state, "duckdb_storage", None)
|
|
16
|
+
return storage
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@router.get("/health")
|
|
20
|
+
async def health(request: Request) -> dict[str, Any]:
|
|
21
|
+
storage = _get_storage(request)
|
|
22
|
+
if not storage:
|
|
23
|
+
raise HTTPException(status_code=503, detail="Storage not initialized")
|
|
24
|
+
return cast(dict[str, Any], await storage.health_check())
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@router.get("/status")
|
|
28
|
+
async def status(request: Request) -> dict[str, Any]:
|
|
29
|
+
storage = _get_storage(request)
|
|
30
|
+
if not storage:
|
|
31
|
+
raise HTTPException(status_code=503, detail="Storage not initialized")
|
|
32
|
+
|
|
33
|
+
health = cast(dict[str, Any], await storage.health_check())
|
|
34
|
+
|
|
35
|
+
# Include basic plugin/service context when available
|
|
36
|
+
plugin_info: dict[str, Any] = {
|
|
37
|
+
"plugin": "duckdb_storage",
|
|
38
|
+
"service_registered": False,
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
try:
|
|
42
|
+
if hasattr(request.app.state, "plugin_registry"):
|
|
43
|
+
registry = request.app.state.plugin_registry
|
|
44
|
+
plugin_info["service_registered"] = registry.has_service("log_storage")
|
|
45
|
+
except Exception:
|
|
46
|
+
pass
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
"health": health,
|
|
50
|
+
**plugin_info,
|
|
51
|
+
}
|