ccproxy-api 0.2.4__tar.gz → 0.2.5__tar.gz
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-0.2.4 → ccproxy_api-0.2.5}/PKG-INFO +19 -19
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/core/_version.py +2 -2
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/core/plugins/factories.py +25 -1
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/llms/formatters/context.py +24 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/llms/formatters/openai_to_openai/responses.py +6 -1
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/llms/formatters/openai_to_openai/streams.py +7 -5
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/llms/models/anthropic.py +9 -1
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/claude_api/adapter.py +4 -5
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/codex/adapter.py +140 -27
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/codex/config.py +7 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/codex/detection_service.py +61 -6
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/codex/plugin.py +1 -0
- ccproxy_api-0.2.5/ccproxy/plugins/codex/routes.py +604 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/services/adapters/base.py +1 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/services/adapters/format_adapter.py +8 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/services/adapters/mock_adapter.py +59 -11
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/services/factories.py +18 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/services/mocking/mock_handler.py +227 -18
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/pyproject.toml +27 -27
- ccproxy_api-0.2.4/ccproxy/plugins/codex/routes.py +0 -129
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/.gitignore +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/LICENSE +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/README.md +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/__main__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/api/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/api/app.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/api/bootstrap.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/api/decorators.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/api/dependencies.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/api/format_validation.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/api/middleware/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/api/middleware/cors.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/api/middleware/errors.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/api/middleware/hooks.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/api/middleware/normalize_headers.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/api/middleware/request_id.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/api/middleware/streaming_hooks.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/api/routes/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/api/routes/health.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/api/routes/plugins.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/auth/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/auth/bearer.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/auth/dependencies.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/auth/exceptions.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/auth/manager.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/auth/managers/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/auth/managers/base.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/auth/managers/base_enhanced.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/auth/managers/token_snapshot.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/auth/models/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/auth/models/base.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/auth/models/credentials.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/auth/oauth/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/auth/oauth/base.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/auth/oauth/cli_errors.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/auth/oauth/flows.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/auth/oauth/protocol.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/auth/oauth/registry.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/auth/oauth/router.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/auth/oauth/routes.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/auth/oauth/session.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/auth/oauth/templates.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/auth/storage/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/auth/storage/base.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/auth/storage/generic.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/cli/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/cli/_settings_help.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/cli/commands/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/cli/commands/auth.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/cli/commands/config/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/cli/commands/config/commands.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/cli/commands/config/schema_commands.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/cli/commands/plugins.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/cli/commands/serve.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/cli/commands/status.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/cli/decorators.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/cli/helpers.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/cli/main.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/cli/options/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/cli/options/claude_options.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/cli/options/core_options.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/cli/options/security_options.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/cli/options/server_options.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/config/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/config/core.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/config/env_generator.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/config/runtime.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/config/security.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/config/settings.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/config/toml_generator.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/config/utils.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/core/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/core/async_task_manager.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/core/async_utils.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/core/auth/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/core/constants.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/core/errors.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/core/id_utils.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/core/interfaces.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/core/logging.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/core/middleware.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/core/plugins/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/core/plugins/cli_discovery.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/core/plugins/declaration.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/core/plugins/discovery.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/core/plugins/hooks/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/core/plugins/hooks/base.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/core/plugins/hooks/events.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/core/plugins/hooks/implementations/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/core/plugins/hooks/implementations/formatters/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/core/plugins/hooks/implementations/formatters/json.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/core/plugins/hooks/implementations/formatters/raw.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/core/plugins/hooks/implementations/http_tracer.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/core/plugins/hooks/layers.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/core/plugins/hooks/manager.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/core/plugins/hooks/registry.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/core/plugins/hooks/thread_manager.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/core/plugins/hooks/types.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/core/plugins/interfaces.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/core/plugins/loader.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/core/plugins/middleware.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/core/plugins/models.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/core/plugins/protocol.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/core/plugins/runtime.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/core/request_context.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/core/status_report.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/core/system.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/core/transformers.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/core/types.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/data/claude_headers_fallback.json +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/data/codex_headers_fallback.json +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/http/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/http/base.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/http/client.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/http/hooks.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/http/pool.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/llms/formatters/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/llms/formatters/anthropic_to_openai/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/llms/formatters/anthropic_to_openai/_helpers.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/llms/formatters/anthropic_to_openai/errors.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/llms/formatters/anthropic_to_openai/requests.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/llms/formatters/anthropic_to_openai/responses.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/llms/formatters/anthropic_to_openai/streams.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/llms/formatters/base.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/llms/formatters/base_model.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/llms/formatters/common/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/llms/formatters/common/identifiers.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/llms/formatters/common/streams.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/llms/formatters/common/thinking.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/llms/formatters/common/usage.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/llms/formatters/constants.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/llms/formatters/mapping.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/llms/formatters/openai_to_anthropic/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/llms/formatters/openai_to_anthropic/_helpers.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/llms/formatters/openai_to_anthropic/errors.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/llms/formatters/openai_to_anthropic/requests.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/llms/formatters/openai_to_anthropic/responses.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/llms/formatters/openai_to_anthropic/streams.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/llms/formatters/openai_to_openai/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/llms/formatters/openai_to_openai/_helpers.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/llms/formatters/openai_to_openai/errors.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/llms/formatters/openai_to_openai/requests.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/llms/formatters/utils.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/llms/models/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/llms/models/openai.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/llms/streaming/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/llms/streaming/accumulators.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/llms/streaming/formatters.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/llms/streaming/processors.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/models/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/models/detection.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/models/provider.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/access_log/README.md +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/access_log/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/access_log/config.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/access_log/formatter.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/access_log/hook.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/access_log/logger.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/access_log/plugin.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/access_log/writer.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/analytics/README.md +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/analytics/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/analytics/config.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/analytics/ingest.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/analytics/models.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/analytics/plugin.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/analytics/routes.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/analytics/service.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/claude_api/README.md +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/claude_api/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/claude_api/config.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/claude_api/detection_service.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/claude_api/health.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/claude_api/hooks.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/claude_api/models.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/claude_api/plugin.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/claude_api/routes.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/claude_api/streaming_metrics.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/claude_api/tasks.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/claude_sdk/README.md +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/claude_sdk/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/claude_sdk/adapter.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/claude_sdk/auth.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/claude_sdk/client.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/claude_sdk/config.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/claude_sdk/converter.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/claude_sdk/detection_service.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/claude_sdk/exceptions.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/claude_sdk/handler.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/claude_sdk/health.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/claude_sdk/hooks.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/claude_sdk/manager.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/claude_sdk/message_queue.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/claude_sdk/models.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/claude_sdk/options.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/claude_sdk/parser.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/claude_sdk/plugin.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/claude_sdk/routes.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/claude_sdk/session_client.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/claude_sdk/session_pool.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/claude_sdk/stream_handle.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/claude_sdk/stream_worker.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/claude_sdk/streaming.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/claude_sdk/tasks.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/claude_shared/README.md +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/claude_shared/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/claude_shared/model_defaults.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/codex/README.md +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/codex/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/codex/health.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/codex/hooks.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/codex/model_defaults.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/codex/models.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/codex/streaming_metrics.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/codex/tasks.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/codex/utils/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/codex/utils/sse_parser.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/command_replay/README.md +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/command_replay/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/command_replay/config.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/command_replay/formatter.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/command_replay/hook.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/command_replay/plugin.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/copilot/README.md +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/copilot/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/copilot/adapter.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/copilot/config.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/copilot/data/copilot_fallback.json +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/copilot/detection_service.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/copilot/manager.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/copilot/model_defaults.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/copilot/models.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/copilot/oauth/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/copilot/oauth/client.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/copilot/oauth/models.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/copilot/oauth/provider.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/copilot/oauth/storage.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/copilot/plugin.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/copilot/routes.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/credential_balancer/README.md +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/credential_balancer/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/credential_balancer/config.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/credential_balancer/factory.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/credential_balancer/hook.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/credential_balancer/manager.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/credential_balancer/plugin.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/dashboard/README.md +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/dashboard/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/dashboard/config.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/dashboard/plugin.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/dashboard/routes.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/docker/README.md +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/docker/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/docker/adapter.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/docker/config.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/docker/docker_path.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/docker/middleware.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/docker/models.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/docker/plugin.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/docker/protocol.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/docker/stream_process.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/docker/validators.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/duckdb_storage/README.md +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/duckdb_storage/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/duckdb_storage/config.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/duckdb_storage/plugin.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/duckdb_storage/routes.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/duckdb_storage/storage.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/max_tokens/README.md +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/max_tokens/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/max_tokens/adapter.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/max_tokens/config.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/max_tokens/models.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/max_tokens/plugin.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/max_tokens/service.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/max_tokens/token_limits.json +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/metrics/README.md +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/metrics/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/metrics/collector.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/metrics/config.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/metrics/grafana/dashboards/ccproxy-dashboard.json +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/metrics/hook.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/metrics/plugin.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/metrics/pushgateway.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/metrics/routes.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/metrics/tasks.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/oauth_claude/README.md +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/oauth_claude/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/oauth_claude/client.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/oauth_claude/config.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/oauth_claude/manager.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/oauth_claude/models.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/oauth_claude/plugin.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/oauth_claude/provider.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/oauth_claude/storage.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/oauth_codex/README.md +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/oauth_codex/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/oauth_codex/client.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/oauth_codex/config.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/oauth_codex/manager.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/oauth_codex/models.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/oauth_codex/plugin.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/oauth_codex/provider.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/oauth_codex/storage.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/permissions/README.md +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/permissions/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/permissions/config.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/permissions/handlers/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/permissions/handlers/cli.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/permissions/handlers/protocol.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/permissions/handlers/terminal.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/permissions/mcp.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/permissions/models.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/permissions/plugin.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/permissions/routes.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/permissions/service.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/permissions/ui/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/permissions/ui/permission_handler_protocol.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/permissions/ui/terminal_permission_handler.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/pricing/README.md +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/pricing/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/pricing/cache.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/pricing/config.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/pricing/exceptions.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/pricing/loader.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/pricing/models.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/pricing/plugin.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/pricing/service.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/pricing/tasks.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/pricing/updater.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/pricing/utils.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/request_tracer/README.md +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/request_tracer/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/request_tracer/config.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/request_tracer/hook.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/plugins/request_tracer/plugin.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/scheduler/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/scheduler/core.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/scheduler/errors.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/scheduler/manager.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/scheduler/registry.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/scheduler/tasks.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/services/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/services/adapters/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/services/adapters/chain_composer.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/services/adapters/chain_validation.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/services/adapters/chat_accumulator.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/services/adapters/delta_utils.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/services/adapters/format_context.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/services/adapters/format_registry.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/services/adapters/http_adapter.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/services/adapters/protocols.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/services/adapters/simple_converters.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/services/auth_registry.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/services/cache/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/services/cache/response_cache.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/services/cli_detection.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/services/config/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/services/config/proxy_configuration.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/services/container.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/services/handler_config.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/services/interfaces.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/services/mocking/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/services/tracing/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/services/tracing/interfaces.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/services/tracing/null_tracer.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/streaming/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/streaming/buffer.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/streaming/deferred.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/streaming/handler.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/streaming/interfaces.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/streaming/simple_adapter.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/streaming/sse.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/streaming/sse_parser.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/templates/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/templates/plugin_scaffold.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/testing/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/testing/config.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/testing/content_generation.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/testing/endpoints/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/testing/endpoints/cli.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/testing/endpoints/config.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/testing/endpoints/console.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/testing/endpoints/models.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/testing/endpoints/runner.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/testing/endpoints/tools.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/testing/mock_responses.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/testing/response_handlers.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/testing/scenarios.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/utils/__init__.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/utils/binary_resolver.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/utils/caching.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/utils/cli_logging.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/utils/command_line.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/utils/headers.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/utils/id_generator.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/utils/model_mapper.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/utils/startup_helpers.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/utils/version_checker.py +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/examples/README.md +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/tests/factories/README.md +0 -0
- {ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/tests/fixtures/README.md +0 -0
|
@@ -1,42 +1,42 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ccproxy-api
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.5
|
|
4
4
|
Summary: API server that provides an Anthropic and OpenAI compatible interface over Claude Code, allowing to use your Claude OAuth account or over the API.
|
|
5
5
|
License-File: LICENSE
|
|
6
6
|
Requires-Python: >=3.11
|
|
7
|
-
Requires-Dist: aiofiles>=
|
|
8
|
-
Requires-Dist: fastapi[standard]>=0.
|
|
7
|
+
Requires-Dist: aiofiles>=25.1.0
|
|
8
|
+
Requires-Dist: fastapi[standard]>=0.119.0
|
|
9
9
|
Requires-Dist: httpx[http2]>=0.28.1
|
|
10
10
|
Requires-Dist: packaging>=25.0
|
|
11
|
-
Requires-Dist: pydantic-settings>=2.
|
|
12
|
-
Requires-Dist: pydantic>=2.
|
|
11
|
+
Requires-Dist: pydantic-settings>=2.11.0
|
|
12
|
+
Requires-Dist: pydantic>=2.12.2
|
|
13
13
|
Requires-Dist: pyjwt>=2.10.1
|
|
14
|
-
Requires-Dist: rich-toolkit>=0.
|
|
15
|
-
Requires-Dist: rich>=
|
|
14
|
+
Requires-Dist: rich-toolkit>=0.15.1
|
|
15
|
+
Requires-Dist: rich>=14.2.0
|
|
16
16
|
Requires-Dist: sortedcontainers>=2.4.0
|
|
17
17
|
Requires-Dist: structlog>=25.4.0
|
|
18
|
-
Requires-Dist: typer>=0.
|
|
19
|
-
Requires-Dist: typing-extensions>=4.
|
|
20
|
-
Requires-Dist: uvicorn>=0.
|
|
18
|
+
Requires-Dist: typer>=0.19.2
|
|
19
|
+
Requires-Dist: typing-extensions>=4.15.0
|
|
20
|
+
Requires-Dist: uvicorn>=0.37.0
|
|
21
21
|
Provides-Extra: plugins-claude
|
|
22
|
-
Requires-Dist: claude-agent-sdk>=0.1.
|
|
23
|
-
Requires-Dist: keyring>=25.
|
|
22
|
+
Requires-Dist: claude-agent-sdk>=0.1.4; extra == 'plugins-claude'
|
|
23
|
+
Requires-Dist: keyring>=25.7.0; extra == 'plugins-claude'
|
|
24
24
|
Requires-Dist: qrcode>=8.2; extra == 'plugins-claude'
|
|
25
25
|
Provides-Extra: plugins-codex
|
|
26
26
|
Requires-Dist: pyjwt>=2.10.1; extra == 'plugins-codex'
|
|
27
27
|
Requires-Dist: qrcode>=8.2; extra == 'plugins-codex'
|
|
28
28
|
Provides-Extra: plugins-mcp
|
|
29
|
-
Requires-Dist: fastapi-mcp>=0.
|
|
29
|
+
Requires-Dist: fastapi-mcp>=0.4.0; extra == 'plugins-mcp'
|
|
30
30
|
Provides-Extra: plugins-metrics
|
|
31
|
-
Requires-Dist: prometheus-client>=0.
|
|
31
|
+
Requires-Dist: prometheus-client>=0.23.1; extra == 'plugins-metrics'
|
|
32
32
|
Provides-Extra: plugins-storage
|
|
33
33
|
Requires-Dist: duckdb-engine>=0.17.0; extra == 'plugins-storage'
|
|
34
|
-
Requires-Dist: duckdb
|
|
35
|
-
Requires-Dist: sqlalchemy>=2.0.
|
|
36
|
-
Requires-Dist: sqlmodel>=0.0.
|
|
34
|
+
Requires-Dist: duckdb>=1.3.2; extra == 'plugins-storage'
|
|
35
|
+
Requires-Dist: sqlalchemy>=2.0.44; extra == 'plugins-storage'
|
|
36
|
+
Requires-Dist: sqlmodel>=0.0.27; extra == 'plugins-storage'
|
|
37
37
|
Provides-Extra: plugins-tui
|
|
38
|
-
Requires-Dist: aioconsole>=0.8.
|
|
39
|
-
Requires-Dist: textual>=3.
|
|
38
|
+
Requires-Dist: aioconsole>=0.8.2; extra == 'plugins-tui'
|
|
39
|
+
Requires-Dist: textual>=6.3.0; extra == 'plugins-tui'
|
|
40
40
|
Description-Content-Type: text/markdown
|
|
41
41
|
|
|
42
42
|
# CCProxy API Server
|
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '0.2.
|
|
32
|
-
__version_tuple__ = version_tuple = (0, 2,
|
|
31
|
+
__version__ = version = '0.2.5'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 2, 5)
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
|
@@ -14,6 +14,7 @@ from fastapi import APIRouter
|
|
|
14
14
|
from ccproxy.models.provider import ProviderConfig
|
|
15
15
|
from ccproxy.services.adapters.base import BaseAdapter
|
|
16
16
|
from ccproxy.services.adapters.http_adapter import BaseHTTPAdapter
|
|
17
|
+
from ccproxy.services.adapters.mock_adapter import MockAdapter
|
|
17
18
|
from ccproxy.services.interfaces import (
|
|
18
19
|
IMetricsCollector,
|
|
19
20
|
IRequestTracer,
|
|
@@ -104,6 +105,7 @@ class BaseProviderPluginFactory(ProviderPluginFactory):
|
|
|
104
105
|
cli_commands: list[CliCommandSpec] = []
|
|
105
106
|
cli_arguments: list[CliArgumentSpec] = []
|
|
106
107
|
tool_accumulator_class: type | None = None
|
|
108
|
+
use_mock_adapter_in_bypass_mode: bool = True
|
|
107
109
|
|
|
108
110
|
def __init__(self) -> None:
|
|
109
111
|
"""Initialize factory with manifest built from class attributes."""
|
|
@@ -215,6 +217,24 @@ class BaseProviderPluginFactory(ProviderPluginFactory):
|
|
|
215
217
|
Returns:
|
|
216
218
|
Adapter instance
|
|
217
219
|
"""
|
|
220
|
+
settings = context.get("settings")
|
|
221
|
+
service_container = context.get("service_container")
|
|
222
|
+
if settings and getattr(settings.server, "bypass_mode", False):
|
|
223
|
+
if not service_container:
|
|
224
|
+
raise RuntimeError(
|
|
225
|
+
f"Cannot initialize plugin '{self.plugin_name}' in bypass mode: "
|
|
226
|
+
"service container is required to create mock adapter. "
|
|
227
|
+
"This is likely a configuration issue."
|
|
228
|
+
)
|
|
229
|
+
logger.warning(
|
|
230
|
+
"plugin_bypass_mode_enabled",
|
|
231
|
+
plugin=self.plugin_name,
|
|
232
|
+
adapter=self.adapter_class.__name__,
|
|
233
|
+
category="lifecycle",
|
|
234
|
+
)
|
|
235
|
+
if self.use_mock_adapter_in_bypass_mode:
|
|
236
|
+
return MockAdapter(service_container.get_mock_handler())
|
|
237
|
+
|
|
218
238
|
# Extract services from context (one-time extraction)
|
|
219
239
|
http_pool_manager: HTTPPoolManager | None = cast(
|
|
220
240
|
"HTTPPoolManager | None", context.get("http_pool_manager")
|
|
@@ -232,7 +252,6 @@ class BaseProviderPluginFactory(ProviderPluginFactory):
|
|
|
232
252
|
config = context.get("config")
|
|
233
253
|
|
|
234
254
|
# Get all adapter dependencies from service container
|
|
235
|
-
service_container = context.get("service_container")
|
|
236
255
|
if not service_container:
|
|
237
256
|
raise RuntimeError("Service container is required for adapter services")
|
|
238
257
|
|
|
@@ -268,6 +287,8 @@ class BaseProviderPluginFactory(ProviderPluginFactory):
|
|
|
268
287
|
if hasattr(context, "get")
|
|
269
288
|
else None,
|
|
270
289
|
}
|
|
290
|
+
if settings and getattr(settings.server, "bypass_mode", False):
|
|
291
|
+
adapter_kwargs["mock_handler"] = service_container.get_mock_handler()
|
|
271
292
|
if self.tool_accumulator_class:
|
|
272
293
|
adapter_kwargs["tool_accumulator_class"] = self.tool_accumulator_class
|
|
273
294
|
|
|
@@ -303,6 +324,9 @@ class BaseProviderPluginFactory(ProviderPluginFactory):
|
|
|
303
324
|
"model_mapper": context.get("model_mapper")
|
|
304
325
|
if hasattr(context, "get")
|
|
305
326
|
else None,
|
|
327
|
+
"mock_handler": service_container.get_mock_handler()
|
|
328
|
+
if settings and getattr(settings.server, "bypass_mode", False)
|
|
329
|
+
else None,
|
|
306
330
|
}
|
|
307
331
|
if self.tool_accumulator_class:
|
|
308
332
|
non_http_adapter_kwargs["tool_accumulator_class"] = (
|
|
@@ -11,6 +11,9 @@ _INSTRUCTIONS_VAR: ContextVar[str | None] = ContextVar(
|
|
|
11
11
|
"formatter_instructions", default=None
|
|
12
12
|
)
|
|
13
13
|
_TOOLS_VAR: ContextVar[list[Any] | None] = ContextVar("formatter_tools", default=None)
|
|
14
|
+
_OPENAI_THINKING_XML_VAR: ContextVar[bool | None] = ContextVar(
|
|
15
|
+
"formatter_openai_thinking_xml", default=None
|
|
16
|
+
)
|
|
14
17
|
|
|
15
18
|
|
|
16
19
|
def register_request(request: Any | None, instructions: str | None = None) -> None:
|
|
@@ -114,3 +117,24 @@ def get_last_request_tools() -> list[Any] | None:
|
|
|
114
117
|
|
|
115
118
|
cached = _TOOLS_VAR.get()
|
|
116
119
|
return list(cached) if cached else None
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def register_openai_thinking_xml(enabled: bool | None) -> None:
|
|
123
|
+
"""Cache OpenAI thinking serialization preference for active conversions.
|
|
124
|
+
|
|
125
|
+
Args:
|
|
126
|
+
enabled: Whether thinking blocks should be serialized with XML wrappers.
|
|
127
|
+
``None`` means downstream conversion logic should use its default.
|
|
128
|
+
|
|
129
|
+
Note:
|
|
130
|
+
The value is stored in a ``ContextVar``, so concurrent async requests
|
|
131
|
+
keep independent preferences without leaking into each other.
|
|
132
|
+
"""
|
|
133
|
+
|
|
134
|
+
_OPENAI_THINKING_XML_VAR.set(enabled)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def get_openai_thinking_xml() -> bool | None:
|
|
138
|
+
"""Return the OpenAI thinking serialization preference for active conversions."""
|
|
139
|
+
|
|
140
|
+
return _OPENAI_THINKING_XML_VAR.get()
|
{ccproxy_api-0.2.4 → ccproxy_api-0.2.5}/ccproxy/llms/formatters/openai_to_openai/responses.py
RENAMED
|
@@ -15,6 +15,7 @@ from ccproxy.llms.formatters.common import (
|
|
|
15
15
|
convert_openai_responses_usage_to_completion_usage,
|
|
16
16
|
merge_thinking_segments,
|
|
17
17
|
)
|
|
18
|
+
from ccproxy.llms.formatters.context import get_openai_thinking_xml
|
|
18
19
|
from ccproxy.llms.models import openai as openai_models
|
|
19
20
|
|
|
20
21
|
from ._helpers import (
|
|
@@ -333,6 +334,10 @@ def convert__openai_responses_to_openai_chat__response(
|
|
|
333
334
|
response: openai_models.ResponseObject,
|
|
334
335
|
) -> openai_models.ChatCompletionResponse:
|
|
335
336
|
"""Convert an OpenAI ResponseObject to a ChatCompletionResponse."""
|
|
337
|
+
include_thinking = get_openai_thinking_xml()
|
|
338
|
+
if include_thinking is None:
|
|
339
|
+
include_thinking = True
|
|
340
|
+
|
|
336
341
|
text_segments: list[str] = []
|
|
337
342
|
added_reasoning: set[tuple[str, str]] = set()
|
|
338
343
|
tool_calls: list[openai_models.ToolCall] = []
|
|
@@ -353,7 +358,7 @@ def convert__openai_responses_to_openai_chat__response(
|
|
|
353
358
|
if thinking_text and len(thinking_text) > 30
|
|
354
359
|
else thinking_text,
|
|
355
360
|
)
|
|
356
|
-
if thinking_text:
|
|
361
|
+
if include_thinking and thinking_text:
|
|
357
362
|
key = (signature or "", thinking_text)
|
|
358
363
|
if key not in added_reasoning:
|
|
359
364
|
text_segments.append(_wrap_thinking(signature, thinking_text))
|
|
@@ -27,16 +27,14 @@ from ccproxy.llms.formatters.context import (
|
|
|
27
27
|
get_last_instructions,
|
|
28
28
|
get_last_request,
|
|
29
29
|
get_last_request_tools,
|
|
30
|
+
get_openai_thinking_xml,
|
|
30
31
|
register_request,
|
|
31
32
|
register_request_tools,
|
|
32
33
|
)
|
|
33
34
|
from ccproxy.llms.models import openai as openai_models
|
|
34
35
|
from ccproxy.llms.streaming.accumulators import OpenAIAccumulator
|
|
35
36
|
|
|
36
|
-
from ._helpers import
|
|
37
|
-
_convert_tools_chat_to_responses,
|
|
38
|
-
_get_attr,
|
|
39
|
-
)
|
|
37
|
+
from ._helpers import _convert_tools_chat_to_responses, _get_attr
|
|
40
38
|
from .requests import _build_responses_payload_from_chat_request
|
|
41
39
|
from .responses import (
|
|
42
40
|
_collect_reasoning_segments,
|
|
@@ -61,6 +59,10 @@ class OpenAIResponsesToChatStreamAdapter:
|
|
|
61
59
|
async def generator() -> AsyncGenerator[
|
|
62
60
|
openai_models.ChatCompletionChunk, None
|
|
63
61
|
]:
|
|
62
|
+
include_thinking = get_openai_thinking_xml()
|
|
63
|
+
if include_thinking is None:
|
|
64
|
+
include_thinking = True
|
|
65
|
+
|
|
64
66
|
model_id = ""
|
|
65
67
|
role_sent = False
|
|
66
68
|
|
|
@@ -537,7 +539,7 @@ class OpenAIResponsesToChatStreamAdapter:
|
|
|
537
539
|
for entry in summary_list:
|
|
538
540
|
text = _get_attr(entry, "text")
|
|
539
541
|
signature = _get_attr(entry, "signature")
|
|
540
|
-
if isinstance(text, str) and text:
|
|
542
|
+
if include_thinking and isinstance(text, str) and text:
|
|
541
543
|
chunk_text = _wrap_thinking(signature, text)
|
|
542
544
|
sequence_counter += 1
|
|
543
545
|
yield openai_models.ChatCompletionChunk(
|
|
@@ -352,8 +352,16 @@ class ThinkingConfigDisabled(ThinkingConfigBase):
|
|
|
352
352
|
type: Literal["disabled"] = Field(default="disabled", alias="type")
|
|
353
353
|
|
|
354
354
|
|
|
355
|
+
class ThinkingConfigAdaptive(ThinkingConfigBase):
|
|
356
|
+
"""Configuration for adaptive thinking (Claude 4-6+)."""
|
|
357
|
+
|
|
358
|
+
type: Literal["adaptive"] = Field(default="adaptive", alias="type")
|
|
359
|
+
display: Literal["summarized", "omitted"] | None = None
|
|
360
|
+
|
|
361
|
+
|
|
355
362
|
ThinkingConfig = Annotated[
|
|
356
|
-
ThinkingConfigEnabled | ThinkingConfigDisabled,
|
|
363
|
+
ThinkingConfigEnabled | ThinkingConfigDisabled | ThinkingConfigAdaptive,
|
|
364
|
+
Field(discriminator="type"),
|
|
357
365
|
]
|
|
358
366
|
|
|
359
367
|
|
|
@@ -85,15 +85,14 @@ class ClaudeAPIAdapter(BaseHTTPAdapter):
|
|
|
85
85
|
# Always set Authorization from OAuth-managed access token
|
|
86
86
|
filtered_headers["authorization"] = f"Bearer {token_value}"
|
|
87
87
|
|
|
88
|
-
#
|
|
89
|
-
# These are required for browser automation tools to work
|
|
88
|
+
# Minimal beta tags required for OAuth-based Claude Code auth
|
|
90
89
|
filtered_headers["anthropic-version"] = "2023-06-01"
|
|
91
|
-
filtered_headers["anthropic-beta"] = "
|
|
90
|
+
filtered_headers["anthropic-beta"] = "claude-code-20250219,oauth-2025-04-20"
|
|
92
91
|
|
|
93
|
-
# Add CLI headers if available, but never allow overriding auth
|
|
92
|
+
# Add CLI headers if available, but never allow overriding auth or beta
|
|
94
93
|
cli_headers = self._collect_cli_headers()
|
|
95
94
|
if cli_headers:
|
|
96
|
-
blocked_overrides = {"authorization", "x-api-key"}
|
|
95
|
+
blocked_overrides = {"authorization", "x-api-key", "anthropic-beta"}
|
|
97
96
|
for key, value in cli_headers.items():
|
|
98
97
|
lk = key.lower()
|
|
99
98
|
if lk in blocked_overrides:
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import contextlib
|
|
2
|
+
import copy
|
|
2
3
|
import json
|
|
3
4
|
import uuid
|
|
4
5
|
from typing import Any, cast
|
|
@@ -16,6 +17,7 @@ from ccproxy.core.plugins.interfaces import (
|
|
|
16
17
|
)
|
|
17
18
|
from ccproxy.services.adapters.chain_composer import compose_from_chain
|
|
18
19
|
from ccproxy.services.adapters.http_adapter import BaseHTTPAdapter
|
|
20
|
+
from ccproxy.services.adapters.mock_adapter import MockAdapter
|
|
19
21
|
from ccproxy.services.handler_config import HandlerConfig
|
|
20
22
|
from ccproxy.streaming import DeferredStreaming, StreamingBufferService
|
|
21
23
|
from ccproxy.utils.headers import (
|
|
@@ -57,18 +59,16 @@ class CodexAdapter(BaseHTTPAdapter):
|
|
|
57
59
|
# Context + request info
|
|
58
60
|
ctx = request.state.context
|
|
59
61
|
self._ensure_tool_accumulator(ctx)
|
|
62
|
+
if self.mock_handler:
|
|
63
|
+
return await MockAdapter(self.mock_handler).handle_request(request)
|
|
64
|
+
|
|
60
65
|
endpoint = ctx.metadata.get("endpoint", "")
|
|
61
66
|
body = await request.body()
|
|
62
67
|
body = await self._map_request_model(ctx, body)
|
|
63
68
|
headers = extract_request_headers(request)
|
|
64
69
|
|
|
65
70
|
# Determine client streaming intent from body flag (fallback to False)
|
|
66
|
-
wants_stream =
|
|
67
|
-
try:
|
|
68
|
-
data = json.loads(body.decode()) if body else {}
|
|
69
|
-
wants_stream = bool(data.get("stream", False))
|
|
70
|
-
except Exception: # Malformed/missing JSON -> assume non-streaming
|
|
71
|
-
wants_stream = False
|
|
71
|
+
wants_stream = self._detect_streaming_intent(body, headers)
|
|
72
72
|
logger.trace(
|
|
73
73
|
"codex_adapter_request_intent",
|
|
74
74
|
wants_stream=wants_stream,
|
|
@@ -256,37 +256,58 @@ class CodexAdapter(BaseHTTPAdapter):
|
|
|
256
256
|
async def prepare_provider_request(
|
|
257
257
|
self, body: bytes, headers: dict[str, str], endpoint: str
|
|
258
258
|
) -> tuple[bytes, dict[str, str]]:
|
|
259
|
-
|
|
259
|
+
filtered_headers = await self.prepare_provider_headers(headers)
|
|
260
260
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
)
|
|
261
|
+
if self._request_body_is_encoded(headers):
|
|
262
|
+
return body, filtered_headers
|
|
263
|
+
|
|
264
|
+
# Body will be re-serialized as plain JSON; drop stale encoding header
|
|
265
|
+
filtered_headers.pop("content-encoding", None)
|
|
266
266
|
|
|
267
267
|
# Parse body (format conversion is now handled by format chain)
|
|
268
268
|
body_data = json.loads(body.decode()) if body else {}
|
|
269
|
+
if self._should_apply_detection_payload():
|
|
270
|
+
body_data = self._apply_request_template(body_data)
|
|
271
|
+
else:
|
|
272
|
+
body_data = self._normalize_input_messages(body_data)
|
|
269
273
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
instructions = self._get_instructions()
|
|
274
|
+
detected_instructions = (
|
|
275
|
+
self._get_instructions() if self._should_apply_detection_payload() else ""
|
|
276
|
+
)
|
|
274
277
|
|
|
275
278
|
existing_instructions = body_data.get("instructions")
|
|
276
279
|
if isinstance(existing_instructions, str) and existing_instructions:
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
280
|
+
instructions = (
|
|
281
|
+
detected_instructions + "\n" + existing_instructions
|
|
282
|
+
if detected_instructions
|
|
283
|
+
else existing_instructions
|
|
284
|
+
)
|
|
285
|
+
else:
|
|
286
|
+
instructions = detected_instructions
|
|
287
|
+
|
|
288
|
+
if instructions:
|
|
289
|
+
body_data["instructions"] = instructions
|
|
290
|
+
else:
|
|
291
|
+
body_data.pop("instructions", None)
|
|
281
292
|
|
|
282
|
-
body_data
|
|
293
|
+
body_data = self._sanitize_provider_body(body_data)
|
|
294
|
+
|
|
295
|
+
return json.dumps(body_data).encode(), filtered_headers
|
|
296
|
+
|
|
297
|
+
def _sanitize_provider_body(self, body_data: dict[str, Any]) -> dict[str, Any]:
|
|
298
|
+
"""Apply Codex-specific payload sanitization shared by all request paths."""
|
|
283
299
|
|
|
284
300
|
# Codex backend requires stream=true, always override
|
|
285
301
|
body_data["stream"] = True
|
|
286
302
|
body_data["store"] = False
|
|
287
303
|
|
|
288
304
|
# Remove unsupported keys for Codex
|
|
289
|
-
for key in (
|
|
305
|
+
for key in (
|
|
306
|
+
"max_output_tokens",
|
|
307
|
+
"max_completion_tokens",
|
|
308
|
+
"max_tokens",
|
|
309
|
+
"temperature",
|
|
310
|
+
):
|
|
290
311
|
body_data.pop(key, None)
|
|
291
312
|
|
|
292
313
|
list_input = body_data.get("input", [])
|
|
@@ -295,12 +316,23 @@ class CodexAdapter(BaseHTTPAdapter):
|
|
|
295
316
|
input for input in list_input if input.get("type") != "item_reference"
|
|
296
317
|
]
|
|
297
318
|
|
|
298
|
-
#
|
|
299
319
|
# Remove any prefixed metadata fields that shouldn't be sent to the API
|
|
300
320
|
body_data = self._remove_metadata_fields(body_data)
|
|
301
321
|
|
|
302
|
-
|
|
322
|
+
return body_data
|
|
323
|
+
|
|
324
|
+
async def prepare_provider_headers(self, headers: dict[str, str]) -> dict[str, str]:
|
|
325
|
+
token_value = await self._resolve_access_token()
|
|
326
|
+
|
|
327
|
+
profile = await self.token_manager.get_profile_quick()
|
|
328
|
+
chatgpt_account_id = (
|
|
329
|
+
getattr(profile, "chatgpt_account_id", None) if profile else None
|
|
330
|
+
)
|
|
331
|
+
|
|
303
332
|
filtered_headers = filter_request_headers(headers, preserve_auth=False)
|
|
333
|
+
content_encoding = headers.get("content-encoding")
|
|
334
|
+
if content_encoding:
|
|
335
|
+
filtered_headers["content-encoding"] = content_encoding
|
|
304
336
|
|
|
305
337
|
session_id = filtered_headers.get("session_id") or str(uuid.uuid4())
|
|
306
338
|
conversation_id = filtered_headers.get("conversation_id") or str(uuid.uuid4())
|
|
@@ -318,10 +350,10 @@ class CodexAdapter(BaseHTTPAdapter):
|
|
|
318
350
|
filtered_headers.update(base_headers)
|
|
319
351
|
|
|
320
352
|
cli_headers = self._collect_cli_headers()
|
|
321
|
-
|
|
322
|
-
filtered_headers.
|
|
353
|
+
for key, value in cli_headers.items():
|
|
354
|
+
filtered_headers.setdefault(key, value)
|
|
323
355
|
|
|
324
|
-
return
|
|
356
|
+
return filtered_headers
|
|
325
357
|
|
|
326
358
|
async def process_provider_response(
|
|
327
359
|
self, response: httpx.Response, endpoint: str
|
|
@@ -453,6 +485,10 @@ class CodexAdapter(BaseHTTPAdapter):
|
|
|
453
485
|
if not self.streaming_handler:
|
|
454
486
|
# Fallback to base behavior
|
|
455
487
|
return await super().handle_streaming(request, endpoint, **kwargs)
|
|
488
|
+
if self.mock_handler:
|
|
489
|
+
return await MockAdapter(self.mock_handler).handle_streaming(
|
|
490
|
+
request, endpoint, **kwargs
|
|
491
|
+
)
|
|
456
492
|
|
|
457
493
|
# Get context
|
|
458
494
|
ctx = request.state.context
|
|
@@ -581,6 +617,73 @@ class CodexAdapter(BaseHTTPAdapter):
|
|
|
581
617
|
|
|
582
618
|
return cleaned_data
|
|
583
619
|
|
|
620
|
+
def _apply_request_template(self, data: dict[str, Any]) -> dict[str, Any]:
|
|
621
|
+
if not isinstance(data, dict):
|
|
622
|
+
return data
|
|
623
|
+
|
|
624
|
+
template = self._get_request_template()
|
|
625
|
+
if not template:
|
|
626
|
+
return self._normalize_input_messages(data)
|
|
627
|
+
|
|
628
|
+
merged = copy.deepcopy(data)
|
|
629
|
+
|
|
630
|
+
for key in ("include", "parallel_tool_calls", "reasoning", "tool_choice"):
|
|
631
|
+
if key not in merged and key in template:
|
|
632
|
+
merged[key] = copy.deepcopy(template[key])
|
|
633
|
+
|
|
634
|
+
if not merged.get("tools") and isinstance(template.get("tools"), list):
|
|
635
|
+
merged["tools"] = copy.deepcopy(template["tools"])
|
|
636
|
+
|
|
637
|
+
if "prompt_cache_key" not in merged:
|
|
638
|
+
prompt_cache_key = template.get("prompt_cache_key")
|
|
639
|
+
if isinstance(prompt_cache_key, str) and prompt_cache_key:
|
|
640
|
+
merged["prompt_cache_key"] = str(uuid.uuid4())
|
|
641
|
+
|
|
642
|
+
return self._normalize_input_messages(merged)
|
|
643
|
+
|
|
644
|
+
def _normalize_input_messages(self, data: dict[str, Any]) -> dict[str, Any]:
|
|
645
|
+
input_items = data.get("input")
|
|
646
|
+
if not isinstance(input_items, list):
|
|
647
|
+
return data
|
|
648
|
+
|
|
649
|
+
normalized_items: list[Any] = []
|
|
650
|
+
for item in input_items:
|
|
651
|
+
if (
|
|
652
|
+
isinstance(item, dict)
|
|
653
|
+
and "type" not in item
|
|
654
|
+
and "role" in item
|
|
655
|
+
and "content" in item
|
|
656
|
+
):
|
|
657
|
+
normalized_item = dict(item)
|
|
658
|
+
normalized_item["type"] = "message"
|
|
659
|
+
normalized_items.append(normalized_item)
|
|
660
|
+
continue
|
|
661
|
+
|
|
662
|
+
normalized_items.append(item)
|
|
663
|
+
|
|
664
|
+
result = dict(data)
|
|
665
|
+
result["input"] = normalized_items
|
|
666
|
+
return result
|
|
667
|
+
|
|
668
|
+
def _request_body_is_encoded(self, headers: dict[str, str]) -> bool:
|
|
669
|
+
encoding = headers.get("content-encoding", "").strip().lower()
|
|
670
|
+
return bool(encoding and encoding != "identity")
|
|
671
|
+
|
|
672
|
+
def _detect_streaming_intent(self, body: bytes, headers: dict[str, str]) -> bool:
|
|
673
|
+
if self._request_body_is_encoded(headers):
|
|
674
|
+
accept = headers.get("accept", "").lower()
|
|
675
|
+
return "text/event-stream" in accept
|
|
676
|
+
|
|
677
|
+
try:
|
|
678
|
+
data = json.loads(body.decode()) if body else {}
|
|
679
|
+
return bool(data.get("stream", False))
|
|
680
|
+
except Exception:
|
|
681
|
+
accept = headers.get("accept", "").lower()
|
|
682
|
+
return "text/event-stream" in accept
|
|
683
|
+
|
|
684
|
+
def _should_apply_detection_payload(self) -> bool:
|
|
685
|
+
return bool(getattr(self.config, "inject_detection_payload", True))
|
|
686
|
+
|
|
584
687
|
def _get_instructions(self) -> str:
|
|
585
688
|
if not self.detection_service:
|
|
586
689
|
return ""
|
|
@@ -601,6 +704,16 @@ class CodexAdapter(BaseHTTPAdapter):
|
|
|
601
704
|
|
|
602
705
|
return ""
|
|
603
706
|
|
|
707
|
+
def _get_request_template(self) -> dict[str, Any]:
|
|
708
|
+
if not self.detection_service:
|
|
709
|
+
return {}
|
|
710
|
+
|
|
711
|
+
prompts = self.detection_service.get_detected_prompts()
|
|
712
|
+
if isinstance(prompts.raw, dict) and prompts.raw:
|
|
713
|
+
return prompts.raw
|
|
714
|
+
|
|
715
|
+
return {}
|
|
716
|
+
|
|
604
717
|
def adapt_error(self, error_body: dict[str, Any]) -> dict[str, Any]:
|
|
605
718
|
"""Convert Codex error format to appropriate API error format.
|
|
606
719
|
|
|
@@ -124,6 +124,13 @@ class CodexSettings(ProviderConfig):
|
|
|
124
124
|
enable_format_registry: bool = Field(
|
|
125
125
|
default=True, description="Whether to enable format adapter registry"
|
|
126
126
|
)
|
|
127
|
+
inject_detection_payload: bool = Field(
|
|
128
|
+
default=True,
|
|
129
|
+
description=(
|
|
130
|
+
"Whether to inject the captured Codex CLI instructions/template into "
|
|
131
|
+
"provider requests. Disable this for generic OpenAI-compatible API usage."
|
|
132
|
+
),
|
|
133
|
+
)
|
|
127
134
|
|
|
128
135
|
# Detection configuration
|
|
129
136
|
detection_home_mode: Literal["temp", "home"] = Field(
|
|
@@ -12,6 +12,7 @@ from pathlib import Path
|
|
|
12
12
|
from typing import Any, cast
|
|
13
13
|
|
|
14
14
|
from fastapi import FastAPI, Request, Response
|
|
15
|
+
from pydantic import ValidationError
|
|
15
16
|
|
|
16
17
|
from ccproxy.config.settings import Settings
|
|
17
18
|
from ccproxy.config.utils import get_ccproxy_cache_dir
|
|
@@ -43,6 +44,7 @@ class CodexDetectionService:
|
|
|
43
44
|
ignores_header: list[str] = [
|
|
44
45
|
"host",
|
|
45
46
|
"content-length",
|
|
47
|
+
"content-encoding",
|
|
46
48
|
"authorization",
|
|
47
49
|
"x-api-key",
|
|
48
50
|
"session_id",
|
|
@@ -133,17 +135,40 @@ class CodexDetectionService:
|
|
|
133
135
|
"""Return cached headers as structured data."""
|
|
134
136
|
|
|
135
137
|
data = self.get_cached_data()
|
|
136
|
-
if
|
|
137
|
-
|
|
138
|
-
|
|
138
|
+
headers = data.headers if data else DetectedHeaders()
|
|
139
|
+
|
|
140
|
+
required_headers = {
|
|
141
|
+
"accept",
|
|
142
|
+
"content-type",
|
|
143
|
+
"openai-beta",
|
|
144
|
+
"originator",
|
|
145
|
+
"version",
|
|
146
|
+
}
|
|
147
|
+
missing_required = [key for key in required_headers if not headers.get(key)]
|
|
148
|
+
if not missing_required:
|
|
149
|
+
return headers
|
|
150
|
+
|
|
151
|
+
fallback = self._safe_fallback_data()
|
|
152
|
+
if fallback is None:
|
|
153
|
+
return headers
|
|
154
|
+
|
|
155
|
+
merged_headers = fallback.headers.as_dict()
|
|
156
|
+
merged_headers.update(
|
|
157
|
+
{key: value for key, value in headers.as_dict().items() if value}
|
|
158
|
+
)
|
|
159
|
+
return DetectedHeaders(merged_headers)
|
|
139
160
|
|
|
140
161
|
def get_detected_prompts(self) -> DetectedPrompts:
|
|
141
162
|
"""Return cached prompt metadata as structured data."""
|
|
142
163
|
|
|
143
164
|
data = self.get_cached_data()
|
|
144
|
-
if
|
|
145
|
-
|
|
146
|
-
|
|
165
|
+
prompts = data.prompts if data else DetectedPrompts()
|
|
166
|
+
|
|
167
|
+
fallback = self._safe_fallback_data()
|
|
168
|
+
if fallback is None:
|
|
169
|
+
return prompts
|
|
170
|
+
|
|
171
|
+
return self._merge_detected_prompts(prompts, fallback.prompts)
|
|
147
172
|
|
|
148
173
|
def get_ignored_headers(self) -> list[str]:
|
|
149
174
|
"""Headers that should be ignored when forwarding CLI values."""
|
|
@@ -496,6 +521,36 @@ class CodexDetectionService:
|
|
|
496
521
|
fallback_data_dict = json.load(f)
|
|
497
522
|
return CodexCacheData.model_validate(fallback_data_dict)
|
|
498
523
|
|
|
524
|
+
def _safe_fallback_data(self) -> CodexCacheData | None:
|
|
525
|
+
"""Best-effort fallback data loader for partial detection caches."""
|
|
526
|
+
try:
|
|
527
|
+
return self._get_fallback_data()
|
|
528
|
+
except (OSError, json.JSONDecodeError, ValidationError):
|
|
529
|
+
logger.debug(
|
|
530
|
+
"safe_fallback_data_load_failed", exc_info=True, category="plugin"
|
|
531
|
+
)
|
|
532
|
+
return None
|
|
533
|
+
|
|
534
|
+
@staticmethod
|
|
535
|
+
def _merge_detected_prompts(
|
|
536
|
+
prompts: DetectedPrompts, fallback: DetectedPrompts
|
|
537
|
+
) -> DetectedPrompts:
|
|
538
|
+
"""Merge partial prompt caches with fallback defaults."""
|
|
539
|
+
|
|
540
|
+
prompt_raw = prompts.raw if isinstance(prompts.raw, dict) else {}
|
|
541
|
+
fallback_raw = fallback.raw if isinstance(fallback.raw, dict) else {}
|
|
542
|
+
merged_raw = dict(fallback_raw)
|
|
543
|
+
merged_raw.update(prompt_raw)
|
|
544
|
+
|
|
545
|
+
instructions = prompts.instructions or fallback.instructions
|
|
546
|
+
system = prompts.system if prompts.system is not None else fallback.system
|
|
547
|
+
|
|
548
|
+
return DetectedPrompts(
|
|
549
|
+
instructions=instructions,
|
|
550
|
+
system=system,
|
|
551
|
+
raw=merged_raw,
|
|
552
|
+
)
|
|
553
|
+
|
|
499
554
|
def invalidate_cache(self) -> None:
|
|
500
555
|
"""Clear all cached detection data."""
|
|
501
556
|
# Clear the async cache for _get_codex_version
|
|
@@ -222,6 +222,7 @@ class CodexFactory(BaseProviderPluginFactory):
|
|
|
222
222
|
"""Factory for Codex provider plugin."""
|
|
223
223
|
|
|
224
224
|
cli_safe = False # Heavy provider plugin - not safe for CLI
|
|
225
|
+
use_mock_adapter_in_bypass_mode = False
|
|
225
226
|
|
|
226
227
|
# Plugin configuration via class attributes
|
|
227
228
|
plugin_name = "codex"
|