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,170 @@
|
|
|
1
|
+
"""Storage implementation for GitHub Copilot OAuth credentials."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from ccproxy.auth.storage.base import BaseJsonStorage
|
|
6
|
+
from ccproxy.core.logging import get_plugin_logger
|
|
7
|
+
|
|
8
|
+
from .models import CopilotCredentials, CopilotOAuthToken, CopilotTokenResponse
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
logger = get_plugin_logger()
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class CopilotOAuthStorage(BaseJsonStorage[CopilotCredentials]):
|
|
15
|
+
"""Storage implementation for Copilot OAuth credentials."""
|
|
16
|
+
|
|
17
|
+
def __init__(self, credentials_path: Path | None = None) -> None:
|
|
18
|
+
"""Initialize storage with credentials path.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
credentials_path: Path to credentials file (uses default if None)
|
|
22
|
+
"""
|
|
23
|
+
if credentials_path is None:
|
|
24
|
+
# Use standard GitHub Copilot storage location
|
|
25
|
+
credentials_path = Path.home() / ".config" / "copilot" / "credentials.json"
|
|
26
|
+
|
|
27
|
+
super().__init__(credentials_path)
|
|
28
|
+
|
|
29
|
+
async def save(self, credentials: CopilotCredentials) -> bool:
|
|
30
|
+
"""Store Copilot credentials to file.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
credentials: Credentials to store
|
|
34
|
+
"""
|
|
35
|
+
try:
|
|
36
|
+
# Update timestamp
|
|
37
|
+
credentials.refresh_updated_at()
|
|
38
|
+
|
|
39
|
+
# Convert to dict for storage
|
|
40
|
+
data = credentials.model_dump(mode="json", exclude_none=True)
|
|
41
|
+
|
|
42
|
+
# Use parent class's atomic write with backup
|
|
43
|
+
await self._write_json(data)
|
|
44
|
+
|
|
45
|
+
logger.debug(
|
|
46
|
+
"credentials_stored",
|
|
47
|
+
path=str(self.file_path),
|
|
48
|
+
account_type=credentials.account_type,
|
|
49
|
+
)
|
|
50
|
+
return True
|
|
51
|
+
except Exception as e:
|
|
52
|
+
logger.error("credentials_save_failed", error=str(e), exc_info=e)
|
|
53
|
+
return False
|
|
54
|
+
|
|
55
|
+
async def load(self) -> CopilotCredentials | None:
|
|
56
|
+
"""Load Copilot credentials from file.
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
Credentials if found and valid, None otherwise
|
|
60
|
+
"""
|
|
61
|
+
try:
|
|
62
|
+
# Use parent class's read method
|
|
63
|
+
data = await self._read_json()
|
|
64
|
+
if not data:
|
|
65
|
+
logger.debug(
|
|
66
|
+
"credentials_not_found",
|
|
67
|
+
path=str(self.file_path),
|
|
68
|
+
)
|
|
69
|
+
return None
|
|
70
|
+
|
|
71
|
+
credentials = CopilotCredentials.model_validate(data)
|
|
72
|
+
logger.debug(
|
|
73
|
+
"credentials_loaded",
|
|
74
|
+
path=str(self.file_path),
|
|
75
|
+
account_type=credentials.account_type,
|
|
76
|
+
is_expired=credentials.is_expired(),
|
|
77
|
+
)
|
|
78
|
+
return credentials
|
|
79
|
+
except Exception as e:
|
|
80
|
+
logger.error(
|
|
81
|
+
"credentials_load_failed",
|
|
82
|
+
error=str(e),
|
|
83
|
+
exc_info=e,
|
|
84
|
+
)
|
|
85
|
+
return None
|
|
86
|
+
|
|
87
|
+
async def delete(self) -> bool:
|
|
88
|
+
"""Clear stored credentials."""
|
|
89
|
+
result = await super().delete()
|
|
90
|
+
|
|
91
|
+
logger.debug(
|
|
92
|
+
"credentials_cleared",
|
|
93
|
+
path=str(self.file_path),
|
|
94
|
+
)
|
|
95
|
+
return result
|
|
96
|
+
|
|
97
|
+
async def update_oauth_token(self, oauth_token: CopilotOAuthToken) -> None:
|
|
98
|
+
"""Update OAuth token in stored credentials.
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
oauth_token: New OAuth token to store
|
|
102
|
+
"""
|
|
103
|
+
credentials = await self.load()
|
|
104
|
+
if not credentials:
|
|
105
|
+
# Create new credentials with just the OAuth token
|
|
106
|
+
credentials = CopilotCredentials(
|
|
107
|
+
oauth_token=oauth_token, copilot_token=None
|
|
108
|
+
)
|
|
109
|
+
else:
|
|
110
|
+
# Update existing credentials
|
|
111
|
+
credentials.oauth_token = oauth_token
|
|
112
|
+
|
|
113
|
+
await self.save(credentials)
|
|
114
|
+
|
|
115
|
+
async def update_copilot_token(self, copilot_token: CopilotTokenResponse) -> None:
|
|
116
|
+
"""Update Copilot service token in stored credentials.
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
copilot_token: New Copilot token to store
|
|
120
|
+
"""
|
|
121
|
+
credentials = await self.load()
|
|
122
|
+
if not credentials:
|
|
123
|
+
logger.warning(
|
|
124
|
+
"no_oauth_credentials_for_copilot_token",
|
|
125
|
+
message="Cannot store Copilot token without OAuth credentials",
|
|
126
|
+
)
|
|
127
|
+
raise ValueError(
|
|
128
|
+
"OAuth credentials must exist before storing Copilot token"
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
credentials.copilot_token = copilot_token
|
|
132
|
+
await self.save(credentials)
|
|
133
|
+
|
|
134
|
+
async def get_oauth_token(self) -> CopilotOAuthToken | None:
|
|
135
|
+
"""Get OAuth token from stored credentials.
|
|
136
|
+
|
|
137
|
+
Returns:
|
|
138
|
+
OAuth token if available, None otherwise
|
|
139
|
+
"""
|
|
140
|
+
credentials = await self.load()
|
|
141
|
+
return credentials.oauth_token if credentials else None
|
|
142
|
+
|
|
143
|
+
async def get_copilot_token(self) -> CopilotTokenResponse | None:
|
|
144
|
+
"""Get Copilot service token from stored credentials.
|
|
145
|
+
|
|
146
|
+
Returns:
|
|
147
|
+
Copilot token if available, None otherwise
|
|
148
|
+
"""
|
|
149
|
+
credentials = await self.load()
|
|
150
|
+
return credentials.copilot_token if credentials else None
|
|
151
|
+
|
|
152
|
+
# BaseOAuthStorage protocol methods
|
|
153
|
+
|
|
154
|
+
# Additional convenience methods for Copilot-specific functionality
|
|
155
|
+
|
|
156
|
+
async def load_credentials(self) -> CopilotCredentials | None:
|
|
157
|
+
"""Legacy method name for backward compatibility."""
|
|
158
|
+
return await self.load()
|
|
159
|
+
|
|
160
|
+
async def store_credentials(self, credentials: CopilotCredentials) -> None:
|
|
161
|
+
"""Legacy method name for backward compatibility."""
|
|
162
|
+
await self.save(credentials)
|
|
163
|
+
|
|
164
|
+
async def save_credentials(self, credentials: CopilotCredentials) -> None:
|
|
165
|
+
"""Save credentials method for OAuth provider compatibility."""
|
|
166
|
+
await self.save(credentials)
|
|
167
|
+
|
|
168
|
+
async def clear_credentials(self) -> None:
|
|
169
|
+
"""Legacy method name for backward compatibility."""
|
|
170
|
+
await self.delete()
|
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
"""GitHub Copilot plugin factory and runtime implementation."""
|
|
2
|
+
|
|
3
|
+
import contextlib
|
|
4
|
+
from typing import Any, cast
|
|
5
|
+
|
|
6
|
+
from ccproxy.auth.oauth import OAuthProviderProtocol
|
|
7
|
+
from ccproxy.core.constants import (
|
|
8
|
+
FORMAT_ANTHROPIC_MESSAGES,
|
|
9
|
+
FORMAT_OPENAI_CHAT,
|
|
10
|
+
FORMAT_OPENAI_RESPONSES,
|
|
11
|
+
)
|
|
12
|
+
from ccproxy.core.logging import get_plugin_logger
|
|
13
|
+
from ccproxy.core.plugins import (
|
|
14
|
+
AuthProviderPluginFactory,
|
|
15
|
+
AuthProviderPluginRuntime,
|
|
16
|
+
BaseProviderPluginFactory,
|
|
17
|
+
PluginContext,
|
|
18
|
+
PluginManifest,
|
|
19
|
+
ProviderPluginRuntime,
|
|
20
|
+
)
|
|
21
|
+
from ccproxy.core.plugins.declaration import FormatPair, RouterSpec
|
|
22
|
+
from ccproxy.core.plugins.interfaces import DetectionServiceProtocol
|
|
23
|
+
from ccproxy.llms.streaming.accumulators import OpenAIAccumulator
|
|
24
|
+
from ccproxy.services.adapters.base import BaseAdapter
|
|
25
|
+
from ccproxy.services.interfaces import (
|
|
26
|
+
NullMetricsCollector,
|
|
27
|
+
NullRequestTracer,
|
|
28
|
+
NullStreamingHandler,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
from .adapter import CopilotAdapter
|
|
32
|
+
from .config import CopilotConfig
|
|
33
|
+
from .detection_service import CopilotDetectionService
|
|
34
|
+
from .manager import CopilotTokenManager
|
|
35
|
+
from .oauth.provider import CopilotOAuthProvider
|
|
36
|
+
from .routes import router_github, router_v1
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
logger = get_plugin_logger()
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class CopilotPluginRuntime(ProviderPluginRuntime, AuthProviderPluginRuntime):
|
|
43
|
+
"""Runtime for GitHub Copilot plugin."""
|
|
44
|
+
|
|
45
|
+
def __init__(self, manifest: PluginManifest):
|
|
46
|
+
"""Initialize runtime."""
|
|
47
|
+
super().__init__(manifest)
|
|
48
|
+
self.config: CopilotConfig | None = None
|
|
49
|
+
self.adapter: CopilotAdapter | None = None
|
|
50
|
+
self.credential_manager: CopilotTokenManager | None = None
|
|
51
|
+
self.oauth_provider: CopilotOAuthProvider | None = None
|
|
52
|
+
self.detection_service: CopilotDetectionService | None = None
|
|
53
|
+
|
|
54
|
+
async def _on_initialize(self) -> None:
|
|
55
|
+
"""Initialize the Copilot plugin."""
|
|
56
|
+
logger.debug(
|
|
57
|
+
"copilot_initializing",
|
|
58
|
+
context_keys=list(self.context.keys()) if self.context else [],
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
# Get configuration
|
|
62
|
+
if self.context:
|
|
63
|
+
config = self.context.get("config")
|
|
64
|
+
if not isinstance(config, CopilotConfig):
|
|
65
|
+
config = CopilotConfig()
|
|
66
|
+
logger.info("copilot_using_default_config")
|
|
67
|
+
self.config = config
|
|
68
|
+
|
|
69
|
+
# Get services from context
|
|
70
|
+
self.oauth_provider = self.context.get("oauth_provider")
|
|
71
|
+
self.detection_service = self.context.get("detection_service")
|
|
72
|
+
self.adapter = self.context.get("adapter")
|
|
73
|
+
with contextlib.suppress(Exception):
|
|
74
|
+
self.credential_manager = self.context.get("credentials_manager")
|
|
75
|
+
|
|
76
|
+
# Call parent initialization - explicitly call both parent classes
|
|
77
|
+
await ProviderPluginRuntime._on_initialize(self)
|
|
78
|
+
await AuthProviderPluginRuntime._on_initialize(self)
|
|
79
|
+
|
|
80
|
+
# Note: BaseHTTPAdapter doesn't have an initialize() method
|
|
81
|
+
# Initialization is handled through dependency injection
|
|
82
|
+
|
|
83
|
+
logger.debug(
|
|
84
|
+
"copilot_plugin_initialized",
|
|
85
|
+
status="initialized",
|
|
86
|
+
has_oauth=bool(self.oauth_provider),
|
|
87
|
+
has_detection=bool(self.detection_service),
|
|
88
|
+
has_adapter=bool(self.adapter),
|
|
89
|
+
category="plugin",
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
async def cleanup(self) -> None:
|
|
93
|
+
"""Cleanup plugin resources."""
|
|
94
|
+
errors = []
|
|
95
|
+
|
|
96
|
+
# Cleanup adapter
|
|
97
|
+
if self.adapter:
|
|
98
|
+
try:
|
|
99
|
+
await self.adapter.cleanup()
|
|
100
|
+
except Exception as e:
|
|
101
|
+
errors.append(f"Adapter cleanup failed: {e}")
|
|
102
|
+
finally:
|
|
103
|
+
self.adapter = None
|
|
104
|
+
|
|
105
|
+
# Cleanup OAuth provider
|
|
106
|
+
if self.oauth_provider:
|
|
107
|
+
try:
|
|
108
|
+
await self.oauth_provider.cleanup()
|
|
109
|
+
except Exception as e:
|
|
110
|
+
errors.append(f"OAuth provider cleanup failed: {e}")
|
|
111
|
+
finally:
|
|
112
|
+
self.oauth_provider = None
|
|
113
|
+
|
|
114
|
+
if self.credential_manager:
|
|
115
|
+
try:
|
|
116
|
+
await self.credential_manager.aclose()
|
|
117
|
+
except Exception as e:
|
|
118
|
+
errors.append(f"Token manager cleanup failed: {e}")
|
|
119
|
+
finally:
|
|
120
|
+
self.credential_manager = None
|
|
121
|
+
|
|
122
|
+
if errors:
|
|
123
|
+
logger.error(
|
|
124
|
+
"copilot_plugin_cleanup_failed",
|
|
125
|
+
errors=errors,
|
|
126
|
+
)
|
|
127
|
+
else:
|
|
128
|
+
logger.debug("copilot_plugin_cleanup_completed")
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
class CopilotPluginFactory(BaseProviderPluginFactory, AuthProviderPluginFactory):
|
|
132
|
+
"""Factory for GitHub Copilot plugin."""
|
|
133
|
+
|
|
134
|
+
cli_safe = False # Heavy provider - not for CLI use
|
|
135
|
+
|
|
136
|
+
# Plugin configuration via class attributes
|
|
137
|
+
plugin_name = "copilot"
|
|
138
|
+
plugin_description = "GitHub Copilot provider plugin with OAuth authentication"
|
|
139
|
+
runtime_class = CopilotPluginRuntime
|
|
140
|
+
adapter_class = CopilotAdapter
|
|
141
|
+
detection_service_class = CopilotDetectionService
|
|
142
|
+
config_class = CopilotConfig
|
|
143
|
+
auth_manager_name = "oauth_copilot"
|
|
144
|
+
# credentials_manager_class = CopilotTokenManager
|
|
145
|
+
routers = [
|
|
146
|
+
RouterSpec(router=router_v1, prefix="/copilot/v1", tags=["copilot-api-v1"]),
|
|
147
|
+
RouterSpec(router=router_github, prefix="/copilot", tags=["copilot-github"]),
|
|
148
|
+
]
|
|
149
|
+
dependencies = []
|
|
150
|
+
optional_requires = []
|
|
151
|
+
|
|
152
|
+
# # Define format adapter dependencies (Anthropic ↔ OpenAI provided by core)
|
|
153
|
+
# requires_format_adapters: list[FormatPair] = [
|
|
154
|
+
# (
|
|
155
|
+
# "anthropic",
|
|
156
|
+
# "openai",
|
|
157
|
+
# ), # Provided by core OpenAI adapter for /v1/messages endpoint
|
|
158
|
+
# ]
|
|
159
|
+
|
|
160
|
+
# Define format adapter requirements (all provided by core)
|
|
161
|
+
requires_format_adapters: list[FormatPair] = [
|
|
162
|
+
# Primary format conversion for Copilot endpoints
|
|
163
|
+
(FORMAT_ANTHROPIC_MESSAGES, FORMAT_OPENAI_CHAT),
|
|
164
|
+
(FORMAT_OPENAI_CHAT, FORMAT_ANTHROPIC_MESSAGES),
|
|
165
|
+
# OpenAI Responses API support
|
|
166
|
+
(FORMAT_OPENAI_RESPONSES, FORMAT_ANTHROPIC_MESSAGES),
|
|
167
|
+
(FORMAT_ANTHROPIC_MESSAGES, FORMAT_OPENAI_RESPONSES),
|
|
168
|
+
(FORMAT_OPENAI_RESPONSES, FORMAT_OPENAI_CHAT),
|
|
169
|
+
(FORMAT_OPENAI_CHAT, FORMAT_OPENAI_RESPONSES),
|
|
170
|
+
]
|
|
171
|
+
tool_accumulator_class = OpenAIAccumulator
|
|
172
|
+
|
|
173
|
+
def create_context(self, core_services: Any) -> PluginContext:
|
|
174
|
+
"""Create context with all plugin components.
|
|
175
|
+
|
|
176
|
+
Args:
|
|
177
|
+
core_services: Core services container
|
|
178
|
+
|
|
179
|
+
Returns:
|
|
180
|
+
Plugin context with all components
|
|
181
|
+
"""
|
|
182
|
+
# Start with base context
|
|
183
|
+
context = super().create_context(core_services)
|
|
184
|
+
|
|
185
|
+
# Get or create configuration
|
|
186
|
+
config = context.get("config")
|
|
187
|
+
if not isinstance(config, CopilotConfig):
|
|
188
|
+
config = CopilotConfig()
|
|
189
|
+
context["config"] = config
|
|
190
|
+
|
|
191
|
+
# Create OAuth provider
|
|
192
|
+
oauth_provider = self.create_oauth_provider(context)
|
|
193
|
+
context["oauth_provider"] = oauth_provider
|
|
194
|
+
# Also set as auth_provider for AuthProviderPluginRuntime compatibility
|
|
195
|
+
context["auth_provider"] = oauth_provider
|
|
196
|
+
|
|
197
|
+
# Create detection service
|
|
198
|
+
detection_service = self.create_detection_service(context)
|
|
199
|
+
context["detection_service"] = detection_service
|
|
200
|
+
|
|
201
|
+
# Note: adapter creation is handled asynchronously by create_runtime
|
|
202
|
+
# in factories.py, so we don't create it here in the synchronous context creation
|
|
203
|
+
|
|
204
|
+
return context
|
|
205
|
+
|
|
206
|
+
def create_runtime(self) -> CopilotPluginRuntime:
|
|
207
|
+
"""Create runtime instance."""
|
|
208
|
+
return CopilotPluginRuntime(self.manifest)
|
|
209
|
+
|
|
210
|
+
def create_oauth_provider(
|
|
211
|
+
self, context: PluginContext | None = None
|
|
212
|
+
) -> CopilotOAuthProvider:
|
|
213
|
+
"""Create OAuth provider instance.
|
|
214
|
+
|
|
215
|
+
Args:
|
|
216
|
+
context: Plugin context containing shared resources
|
|
217
|
+
|
|
218
|
+
Returns:
|
|
219
|
+
CopilotOAuthProvider instance
|
|
220
|
+
"""
|
|
221
|
+
if context and isinstance(context.get("config"), CopilotConfig):
|
|
222
|
+
cfg = cast(CopilotConfig, context.get("config"))
|
|
223
|
+
else:
|
|
224
|
+
cfg = CopilotConfig()
|
|
225
|
+
|
|
226
|
+
config: CopilotConfig = cfg
|
|
227
|
+
http_client = context.get("http_client") if context else None
|
|
228
|
+
hook_manager = context.get("hook_manager") if context else None
|
|
229
|
+
cli_detection_service = (
|
|
230
|
+
context.get("cli_detection_service") if context else None
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
return CopilotOAuthProvider(
|
|
234
|
+
config.oauth,
|
|
235
|
+
http_client=http_client,
|
|
236
|
+
hook_manager=hook_manager,
|
|
237
|
+
detection_service=cli_detection_service,
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
def create_detection_service(
|
|
241
|
+
self, context: PluginContext
|
|
242
|
+
) -> DetectionServiceProtocol:
|
|
243
|
+
"""Create detection service instance.
|
|
244
|
+
|
|
245
|
+
Args:
|
|
246
|
+
context: Plugin context
|
|
247
|
+
|
|
248
|
+
Returns:
|
|
249
|
+
CopilotDetectionService instance
|
|
250
|
+
"""
|
|
251
|
+
settings = context.get("settings")
|
|
252
|
+
cli_service = context.get("cli_detection_service")
|
|
253
|
+
|
|
254
|
+
if not settings or not cli_service:
|
|
255
|
+
raise ValueError("Settings and CLI detection service required")
|
|
256
|
+
|
|
257
|
+
service = CopilotDetectionService(settings, cli_service)
|
|
258
|
+
return cast(DetectionServiceProtocol, service)
|
|
259
|
+
|
|
260
|
+
async def create_adapter(self, context: PluginContext) -> BaseAdapter:
|
|
261
|
+
"""Create main adapter instance.
|
|
262
|
+
|
|
263
|
+
Args:
|
|
264
|
+
context: Plugin context
|
|
265
|
+
|
|
266
|
+
Returns:
|
|
267
|
+
CopilotAdapter instance
|
|
268
|
+
"""
|
|
269
|
+
if not context:
|
|
270
|
+
raise ValueError("Context required for adapter")
|
|
271
|
+
|
|
272
|
+
config = context.get("config")
|
|
273
|
+
if not isinstance(config, CopilotConfig):
|
|
274
|
+
config = CopilotConfig()
|
|
275
|
+
|
|
276
|
+
# Get required dependencies following BaseHTTPAdapter pattern
|
|
277
|
+
oauth_provider = context.get("oauth_provider")
|
|
278
|
+
detection_service = context.get("detection_service")
|
|
279
|
+
http_pool_manager = context.get("http_pool_manager")
|
|
280
|
+
auth_manager = context.get("credentials_manager")
|
|
281
|
+
|
|
282
|
+
# Optional dependencies
|
|
283
|
+
request_tracer = context.get("request_tracer") or NullRequestTracer()
|
|
284
|
+
metrics = context.get("metrics") or NullMetricsCollector()
|
|
285
|
+
streaming_handler = context.get("streaming_handler") or NullStreamingHandler()
|
|
286
|
+
hook_manager = context.get("hook_manager")
|
|
287
|
+
|
|
288
|
+
# Get format_registry from service container
|
|
289
|
+
service_container = context.get("service_container")
|
|
290
|
+
format_registry = None
|
|
291
|
+
if service_container:
|
|
292
|
+
format_registry = service_container.get_format_registry()
|
|
293
|
+
|
|
294
|
+
# Debug: Log what we actually have in the context
|
|
295
|
+
logger.debug(
|
|
296
|
+
"copilot_adapter_dependencies_debug",
|
|
297
|
+
context_keys=list(context.keys()) if context else [],
|
|
298
|
+
has_auth_manager=bool(auth_manager),
|
|
299
|
+
has_detection_service=bool(detection_service),
|
|
300
|
+
has_http_pool_manager=bool(http_pool_manager),
|
|
301
|
+
has_oauth_provider=bool(oauth_provider),
|
|
302
|
+
has_format_registry=bool(format_registry),
|
|
303
|
+
)
|
|
304
|
+
|
|
305
|
+
if not all([detection_service, http_pool_manager, oauth_provider]):
|
|
306
|
+
missing = []
|
|
307
|
+
if not detection_service:
|
|
308
|
+
missing.append("detection_service")
|
|
309
|
+
if not http_pool_manager:
|
|
310
|
+
missing.append("http_pool_manager")
|
|
311
|
+
if not oauth_provider:
|
|
312
|
+
missing.append("oauth_provider")
|
|
313
|
+
|
|
314
|
+
raise ValueError(
|
|
315
|
+
f"Required dependencies missing for CopilotAdapter: {missing}"
|
|
316
|
+
)
|
|
317
|
+
|
|
318
|
+
if auth_manager is None:
|
|
319
|
+
configured_override = None
|
|
320
|
+
if hasattr(context, "config") and context.config is not None:
|
|
321
|
+
with contextlib.suppress(AttributeError):
|
|
322
|
+
configured_override = getattr(context.config, "auth_manager", None)
|
|
323
|
+
|
|
324
|
+
logger.debug(
|
|
325
|
+
"copilot_adapter_missing_auth_manager",
|
|
326
|
+
reason="unresolved_override",
|
|
327
|
+
configured_override=configured_override,
|
|
328
|
+
)
|
|
329
|
+
|
|
330
|
+
return CopilotAdapter(
|
|
331
|
+
config=config,
|
|
332
|
+
auth_manager=auth_manager,
|
|
333
|
+
detection_service=detection_service,
|
|
334
|
+
http_pool_manager=http_pool_manager,
|
|
335
|
+
oauth_provider=oauth_provider,
|
|
336
|
+
request_tracer=request_tracer,
|
|
337
|
+
metrics=metrics,
|
|
338
|
+
streaming_handler=streaming_handler,
|
|
339
|
+
hook_manager=hook_manager,
|
|
340
|
+
format_registry=format_registry,
|
|
341
|
+
context=context,
|
|
342
|
+
)
|
|
343
|
+
|
|
344
|
+
def create_auth_provider(
|
|
345
|
+
self, context: PluginContext | None = None
|
|
346
|
+
) -> OAuthProviderProtocol:
|
|
347
|
+
"""Create OAuth provider instance for AuthProviderPluginFactory interface.
|
|
348
|
+
|
|
349
|
+
Args:
|
|
350
|
+
context: Plugin context containing shared resources
|
|
351
|
+
|
|
352
|
+
Returns:
|
|
353
|
+
CopilotOAuthProvider instance
|
|
354
|
+
"""
|
|
355
|
+
provider = self.create_oauth_provider(context)
|
|
356
|
+
return cast(OAuthProviderProtocol, provider)
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
# Export the factory instance
|
|
360
|
+
factory = CopilotPluginFactory()
|