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,233 @@
|
|
|
1
|
+
"""Middleware management and ordering for the plugin system.
|
|
2
|
+
|
|
3
|
+
This module provides utilities for managing middleware registration
|
|
4
|
+
and ensuring proper ordering across core and plugin middleware.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
from typing import TYPE_CHECKING, Any
|
|
9
|
+
|
|
10
|
+
from fastapi import FastAPI
|
|
11
|
+
|
|
12
|
+
from ccproxy.core.logging import TraceBoundLogger, get_logger
|
|
13
|
+
|
|
14
|
+
from .declaration import MiddlewareLayer, MiddlewareSpec
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
if TYPE_CHECKING:
|
|
18
|
+
from starlette.middleware.base import BaseHTTPMiddleware
|
|
19
|
+
else:
|
|
20
|
+
from starlette.middleware.base import BaseHTTPMiddleware
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
logger: TraceBoundLogger = get_logger()
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@dataclass
|
|
27
|
+
class CoreMiddlewareSpec(MiddlewareSpec):
|
|
28
|
+
"""Specification for core application middleware.
|
|
29
|
+
|
|
30
|
+
Extends MiddlewareSpec with a source field to distinguish
|
|
31
|
+
between core and plugin middleware.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
source: str = "core" # "core" or plugin name
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class MiddlewareManager:
|
|
38
|
+
"""Manages middleware registration and ordering."""
|
|
39
|
+
|
|
40
|
+
def __init__(self) -> None:
|
|
41
|
+
"""Initialize middleware manager."""
|
|
42
|
+
self.middleware_specs: list[CoreMiddlewareSpec] = []
|
|
43
|
+
|
|
44
|
+
def add_core_middleware(
|
|
45
|
+
self,
|
|
46
|
+
middleware_class: type[BaseHTTPMiddleware],
|
|
47
|
+
priority: int = MiddlewareLayer.APPLICATION,
|
|
48
|
+
**kwargs: Any,
|
|
49
|
+
) -> None:
|
|
50
|
+
"""Add core application middleware.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
middleware_class: Middleware class
|
|
54
|
+
priority: Priority for ordering
|
|
55
|
+
**kwargs: Additional middleware arguments
|
|
56
|
+
"""
|
|
57
|
+
spec = CoreMiddlewareSpec(
|
|
58
|
+
middleware_class=middleware_class,
|
|
59
|
+
priority=priority,
|
|
60
|
+
kwargs=kwargs,
|
|
61
|
+
source="core",
|
|
62
|
+
)
|
|
63
|
+
self.middleware_specs.append(spec)
|
|
64
|
+
|
|
65
|
+
def add_plugin_middleware(
|
|
66
|
+
self, plugin_name: str, specs: list[MiddlewareSpec]
|
|
67
|
+
) -> None:
|
|
68
|
+
"""Add middleware from a plugin.
|
|
69
|
+
|
|
70
|
+
Args:
|
|
71
|
+
plugin_name: Name of the plugin
|
|
72
|
+
specs: List of middleware specifications
|
|
73
|
+
"""
|
|
74
|
+
for spec in specs:
|
|
75
|
+
core_spec = CoreMiddlewareSpec(
|
|
76
|
+
middleware_class=spec.middleware_class,
|
|
77
|
+
priority=spec.priority,
|
|
78
|
+
kwargs=spec.kwargs,
|
|
79
|
+
source=plugin_name,
|
|
80
|
+
)
|
|
81
|
+
self.middleware_specs.append(core_spec)
|
|
82
|
+
logger.trace(
|
|
83
|
+
"plugin_middleware_added",
|
|
84
|
+
plugin=plugin_name,
|
|
85
|
+
middleware=spec.middleware_class.__name__,
|
|
86
|
+
priority=spec.priority,
|
|
87
|
+
category="middleware",
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
def get_ordered_middleware(self) -> list[CoreMiddlewareSpec]:
|
|
91
|
+
"""Get all middleware sorted by priority.
|
|
92
|
+
|
|
93
|
+
Returns:
|
|
94
|
+
List of middleware specs sorted by priority (lower first)
|
|
95
|
+
"""
|
|
96
|
+
# Sort by priority (lower values first)
|
|
97
|
+
# Secondary sort by source (core before plugins) for same priority
|
|
98
|
+
return sorted(
|
|
99
|
+
self.middleware_specs,
|
|
100
|
+
key=lambda x: (x.priority, x.source != "core", x.source),
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
def apply_to_app(self, app: FastAPI) -> None:
|
|
104
|
+
"""Apply all middleware to the FastAPI app in correct order.
|
|
105
|
+
|
|
106
|
+
Note: Middleware in FastAPI/Starlette is applied in reverse order
|
|
107
|
+
(last added runs first), so we add them in reverse priority order.
|
|
108
|
+
|
|
109
|
+
Args:
|
|
110
|
+
app: FastAPI application
|
|
111
|
+
"""
|
|
112
|
+
ordered = self.get_ordered_middleware()
|
|
113
|
+
applied_middleware = []
|
|
114
|
+
failed_middleware = []
|
|
115
|
+
|
|
116
|
+
# Apply in reverse order (highest priority last so it runs first)
|
|
117
|
+
for spec in reversed(ordered):
|
|
118
|
+
try:
|
|
119
|
+
app.add_middleware(spec.middleware_class, **spec.kwargs) # type: ignore[arg-type]
|
|
120
|
+
applied_middleware.append(
|
|
121
|
+
{
|
|
122
|
+
"name": spec.middleware_class.__name__,
|
|
123
|
+
"priority": spec.priority,
|
|
124
|
+
"source": spec.source,
|
|
125
|
+
}
|
|
126
|
+
)
|
|
127
|
+
except Exception as e:
|
|
128
|
+
failed_middleware.append(
|
|
129
|
+
{
|
|
130
|
+
"name": spec.middleware_class.__name__,
|
|
131
|
+
"source": spec.source,
|
|
132
|
+
"error": str(e),
|
|
133
|
+
}
|
|
134
|
+
)
|
|
135
|
+
logger.error(
|
|
136
|
+
"middleware_application_failed",
|
|
137
|
+
middleware=spec.middleware_class.__name__,
|
|
138
|
+
source=spec.source,
|
|
139
|
+
error=str(e),
|
|
140
|
+
exc_info=e,
|
|
141
|
+
category="middleware",
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
# Log aggregated success
|
|
145
|
+
if applied_middleware:
|
|
146
|
+
logger.info(
|
|
147
|
+
"middleware_stack_configured",
|
|
148
|
+
applied=len(applied_middleware),
|
|
149
|
+
failed=len(failed_middleware),
|
|
150
|
+
middleware=[m["name"] for m in applied_middleware],
|
|
151
|
+
category="middleware",
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
def get_middleware_summary(self) -> dict[str, Any]:
|
|
155
|
+
"""Get a summary of registered middleware.
|
|
156
|
+
|
|
157
|
+
Returns:
|
|
158
|
+
Dictionary with middleware statistics and order
|
|
159
|
+
"""
|
|
160
|
+
ordered = self.get_ordered_middleware()
|
|
161
|
+
|
|
162
|
+
summary = {
|
|
163
|
+
"total": len(ordered),
|
|
164
|
+
"core": len([m for m in ordered if m.source == "core"]),
|
|
165
|
+
"plugins": len([m for m in ordered if m.source != "core"]),
|
|
166
|
+
"order": [
|
|
167
|
+
{
|
|
168
|
+
"name": spec.middleware_class.__name__,
|
|
169
|
+
"priority": spec.priority,
|
|
170
|
+
"layer": self._get_layer_name(spec.priority),
|
|
171
|
+
"source": spec.source,
|
|
172
|
+
}
|
|
173
|
+
for spec in ordered
|
|
174
|
+
],
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return summary
|
|
178
|
+
|
|
179
|
+
def _get_layer_name(self, priority: int) -> str:
|
|
180
|
+
"""Get the layer name for a priority value.
|
|
181
|
+
|
|
182
|
+
Args:
|
|
183
|
+
priority: Priority value
|
|
184
|
+
|
|
185
|
+
Returns:
|
|
186
|
+
Layer name
|
|
187
|
+
"""
|
|
188
|
+
# Find the closest layer
|
|
189
|
+
for layer in MiddlewareLayer:
|
|
190
|
+
if priority < layer:
|
|
191
|
+
return f"before_{layer.name.lower()}"
|
|
192
|
+
elif priority == layer:
|
|
193
|
+
return layer.name.lower()
|
|
194
|
+
|
|
195
|
+
# If higher than all layers
|
|
196
|
+
return "after_application"
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def setup_default_middleware(manager: MiddlewareManager) -> None:
|
|
200
|
+
"""Setup default core middleware.
|
|
201
|
+
|
|
202
|
+
Args:
|
|
203
|
+
manager: Middleware manager
|
|
204
|
+
"""
|
|
205
|
+
from ccproxy.api.middleware.hooks import HooksMiddleware
|
|
206
|
+
from ccproxy.api.middleware.normalize_headers import NormalizeHeadersMiddleware
|
|
207
|
+
from ccproxy.api.middleware.request_id import RequestIDMiddleware
|
|
208
|
+
|
|
209
|
+
# Request ID should be first (lowest priority) to set context for all others
|
|
210
|
+
manager.add_core_middleware(
|
|
211
|
+
RequestIDMiddleware,
|
|
212
|
+
priority=MiddlewareLayer.SECURITY - 50, # Before security layer
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
# Hooks middleware should be early to capture all requests
|
|
216
|
+
manager.add_core_middleware(
|
|
217
|
+
HooksMiddleware,
|
|
218
|
+
priority=MiddlewareLayer.SECURITY
|
|
219
|
+
- 40, # After request ID, before other middleware
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
# # Access logging in observability layer
|
|
223
|
+
# manager.add_core_middleware(
|
|
224
|
+
# AccessLogMiddleware, priority=MiddlewareLayer.OBSERVABILITY
|
|
225
|
+
# )
|
|
226
|
+
#
|
|
227
|
+
# Normalize headers: strip unsafe and ensure server header
|
|
228
|
+
manager.add_core_middleware(
|
|
229
|
+
NormalizeHeadersMiddleware, # type: ignore[arg-type]
|
|
230
|
+
priority=MiddlewareLayer.ROUTING, # after routing layer
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
logger.debug("default_middleware_configured", category="middleware")
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""Common provider plugin health detail models.
|
|
2
|
+
|
|
3
|
+
These models standardize the `details` payload returned by provider plugins
|
|
4
|
+
in their health checks, enabling consistent inspection across plugins.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
from pydantic import BaseModel, Field
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class CLIHealth(BaseModel):
|
|
15
|
+
"""Standardized CLI health information for a provider plugin."""
|
|
16
|
+
|
|
17
|
+
available: bool = Field(description="Whether the CLI is available")
|
|
18
|
+
status: str = Field(description="CLI status string from plugin detector")
|
|
19
|
+
version: str | None = Field(default=None, description="Detected CLI version")
|
|
20
|
+
path: str | None = Field(default=None, description="Resolved CLI binary path")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class AuthHealth(BaseModel):
|
|
24
|
+
"""Standardized authentication health information."""
|
|
25
|
+
|
|
26
|
+
configured: bool = Field(description="Whether auth is configured for this plugin")
|
|
27
|
+
token_available: bool | None = Field(
|
|
28
|
+
default=None, description="Valid, non-expired token is available"
|
|
29
|
+
)
|
|
30
|
+
token_expired: bool | None = Field(default=None, description="Token is expired")
|
|
31
|
+
account_id: str | None = Field(default=None, description="Associated account id")
|
|
32
|
+
expires_at: str | None = Field(default=None, description="Token expiry ISO time")
|
|
33
|
+
error: str | None = Field(default=None, description="Auth error or reason text")
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class ConfigHealth(BaseModel):
|
|
37
|
+
"""Standardized configuration summary for a provider plugin."""
|
|
38
|
+
|
|
39
|
+
model_count: int | None = Field(default=None, description="Configured model count")
|
|
40
|
+
supports_openai_format: bool | None = Field(
|
|
41
|
+
default=None, description="Whether OpenAI-compatible format is supported"
|
|
42
|
+
)
|
|
43
|
+
verbose_logging: bool | None = Field(
|
|
44
|
+
default=None, description="Whether plugin verbose logging is enabled"
|
|
45
|
+
)
|
|
46
|
+
extra: dict[str, Any] | None = Field(
|
|
47
|
+
default=None, description="Additional provider-specific configuration"
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class ProviderHealthDetails(BaseModel):
|
|
52
|
+
"""Top-level standardized provider health details payload."""
|
|
53
|
+
|
|
54
|
+
provider: str = Field(description="Provider plugin name")
|
|
55
|
+
enabled: bool = Field(description="Whether this plugin is enabled")
|
|
56
|
+
base_url: str | None = Field(default=None, description="Provider base URL")
|
|
57
|
+
cli: CLIHealth | None = Field(default=None, description="CLI health")
|
|
58
|
+
auth: AuthHealth | None = Field(default=None, description="Auth health")
|
|
59
|
+
config: ConfigHealth | None = Field(default=None, description="Config summary")
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
"""Plugin protocol for provider plugins."""
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, Any, Literal, Protocol, runtime_checkable
|
|
4
|
+
|
|
5
|
+
from fastapi import APIRouter
|
|
6
|
+
from pydantic import BaseModel
|
|
7
|
+
from typing_extensions import TypedDict
|
|
8
|
+
|
|
9
|
+
from ccproxy.core.plugins.hooks.base import Hook
|
|
10
|
+
from ccproxy.models.provider import ProviderConfig
|
|
11
|
+
from ccproxy.services.adapters.base import BaseAdapter
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from ccproxy.scheduler.tasks import BaseScheduledTask
|
|
16
|
+
from ccproxy.services.container import ServiceContainer
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@runtime_checkable
|
|
20
|
+
class OAuthClientProtocol(Protocol):
|
|
21
|
+
"""Protocol for OAuth client implementations."""
|
|
22
|
+
|
|
23
|
+
async def authenticate(self, open_browser: bool = True) -> Any:
|
|
24
|
+
"""Perform OAuth authentication flow.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
open_browser: Whether to automatically open browser
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
Provider-specific credentials object
|
|
31
|
+
"""
|
|
32
|
+
...
|
|
33
|
+
|
|
34
|
+
async def refresh_access_token(self, refresh_token: str) -> Any:
|
|
35
|
+
"""Refresh access token using refresh token.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
refresh_token: Refresh token
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
New token response
|
|
42
|
+
"""
|
|
43
|
+
...
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class AuthCommandDefinition(TypedDict, total=False):
|
|
47
|
+
"""Definition for provider-specific auth command extensions."""
|
|
48
|
+
|
|
49
|
+
command_name: str # Required: Command name (e.g., 'validate', 'profile')
|
|
50
|
+
description: str # Required: Command description
|
|
51
|
+
handler: Any # Required: Async command handler function
|
|
52
|
+
options: dict[str, Any] # Optional: Additional command options
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class HealthCheckResult(BaseModel):
|
|
56
|
+
"""Standardized health check result following IETF format."""
|
|
57
|
+
|
|
58
|
+
status: Literal["pass", "warn", "fail"]
|
|
59
|
+
componentId: str # noqa: N815
|
|
60
|
+
componentType: str = "provider_plugin" # noqa: N815
|
|
61
|
+
output: str | None = None
|
|
62
|
+
version: str | None = None
|
|
63
|
+
details: dict[str, Any] | None = None
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class ScheduledTaskDefinition(TypedDict, total=False):
|
|
67
|
+
"""Definition for a scheduled task from a plugin."""
|
|
68
|
+
|
|
69
|
+
task_name: str # Required: Unique name for the task instance
|
|
70
|
+
task_type: str # Required: Type identifier for task registry
|
|
71
|
+
task_class: type["BaseScheduledTask"] # Required: Task class
|
|
72
|
+
interval_seconds: float # Required: Interval between executions
|
|
73
|
+
enabled: bool # Optional: Whether task is enabled (default: True)
|
|
74
|
+
# Additional kwargs can be passed for task initialization
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
@runtime_checkable
|
|
78
|
+
class BasePlugin(Protocol):
|
|
79
|
+
"""Base protocol for all plugins."""
|
|
80
|
+
|
|
81
|
+
@property
|
|
82
|
+
def name(self) -> str:
|
|
83
|
+
"""Plugin name."""
|
|
84
|
+
...
|
|
85
|
+
|
|
86
|
+
@property
|
|
87
|
+
def version(self) -> str:
|
|
88
|
+
"""Plugin version."""
|
|
89
|
+
...
|
|
90
|
+
|
|
91
|
+
@property
|
|
92
|
+
def dependencies(self) -> list[str]:
|
|
93
|
+
"""List of plugin names this plugin depends on."""
|
|
94
|
+
...
|
|
95
|
+
|
|
96
|
+
@property
|
|
97
|
+
def router_prefix(self) -> str:
|
|
98
|
+
"""Unique route prefix for this plugin."""
|
|
99
|
+
...
|
|
100
|
+
|
|
101
|
+
async def initialize(self, services: "ServiceContainer") -> None:
|
|
102
|
+
"""Initialize plugin with shared services. Called once on startup."""
|
|
103
|
+
...
|
|
104
|
+
|
|
105
|
+
async def shutdown(self) -> None:
|
|
106
|
+
"""Perform graceful shutdown. Called once on app shutdown."""
|
|
107
|
+
...
|
|
108
|
+
|
|
109
|
+
async def validate(self) -> bool:
|
|
110
|
+
"""Validate plugin is ready."""
|
|
111
|
+
...
|
|
112
|
+
|
|
113
|
+
def get_routes(self) -> APIRouter | dict[str, APIRouter] | None:
|
|
114
|
+
"""Get plugin-specific routes (optional)."""
|
|
115
|
+
...
|
|
116
|
+
|
|
117
|
+
async def health_check(self) -> HealthCheckResult:
|
|
118
|
+
"""Perform health check following IETF format."""
|
|
119
|
+
...
|
|
120
|
+
|
|
121
|
+
def get_scheduled_tasks(self) -> list[ScheduledTaskDefinition] | None:
|
|
122
|
+
"""Get scheduled task definitions for this plugin (optional).
|
|
123
|
+
|
|
124
|
+
Returns:
|
|
125
|
+
List of task definitions or None if no scheduled tasks needed
|
|
126
|
+
"""
|
|
127
|
+
...
|
|
128
|
+
|
|
129
|
+
def get_config_class(self) -> type[BaseModel] | None:
|
|
130
|
+
"""Get the Pydantic configuration model for this plugin.
|
|
131
|
+
|
|
132
|
+
Returns:
|
|
133
|
+
Pydantic BaseModel class for plugin configuration or None if no configuration needed
|
|
134
|
+
"""
|
|
135
|
+
...
|
|
136
|
+
|
|
137
|
+
def get_hooks(self) -> list[Hook] | None:
|
|
138
|
+
"""Get hooks provided by this plugin (optional).
|
|
139
|
+
|
|
140
|
+
Returns:
|
|
141
|
+
List of hook instances or None if no hooks
|
|
142
|
+
"""
|
|
143
|
+
...
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
@runtime_checkable
|
|
147
|
+
class SystemPlugin(BasePlugin, Protocol):
|
|
148
|
+
"""Protocol for system plugins (non-provider plugins).
|
|
149
|
+
|
|
150
|
+
System plugins inherit all methods from BasePlugin and don't add
|
|
151
|
+
any additional requirements. They don't proxy to external providers
|
|
152
|
+
and therefore don't need adapters or provider configurations.
|
|
153
|
+
"""
|
|
154
|
+
|
|
155
|
+
# SystemPlugin has no additional methods beyond BasePlugin
|
|
156
|
+
pass
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
@runtime_checkable
|
|
160
|
+
class ProviderPlugin(BasePlugin, Protocol):
|
|
161
|
+
"""Enhanced protocol for provider plugins.
|
|
162
|
+
|
|
163
|
+
Provider plugins proxy requests to external API providers and therefore
|
|
164
|
+
need additional methods for creating adapters and configurations.
|
|
165
|
+
"""
|
|
166
|
+
|
|
167
|
+
def create_adapter(self) -> BaseAdapter:
|
|
168
|
+
"""Create adapter instance for handling provider requests."""
|
|
169
|
+
...
|
|
170
|
+
|
|
171
|
+
def create_config(self) -> ProviderConfig:
|
|
172
|
+
"""Create provider configuration from settings."""
|
|
173
|
+
...
|
|
174
|
+
|
|
175
|
+
async def get_oauth_client(self) -> OAuthClientProtocol | None:
|
|
176
|
+
"""Get OAuth client for this plugin if it supports OAuth authentication.
|
|
177
|
+
|
|
178
|
+
Returns:
|
|
179
|
+
OAuth client instance or None if plugin doesn't support OAuth
|
|
180
|
+
"""
|