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,619 @@
|
|
|
1
|
+
from copy import deepcopy
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
from typing import Annotated, Any, Literal
|
|
4
|
+
|
|
5
|
+
from pydantic import Field, model_validator
|
|
6
|
+
|
|
7
|
+
from ccproxy.llms.formatters import LlmBaseModel
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
# ===================================================================
|
|
11
|
+
# Error Models
|
|
12
|
+
# ===================================================================
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class ErrorDetail(LlmBaseModel):
|
|
16
|
+
"""Base model for an error."""
|
|
17
|
+
|
|
18
|
+
message: str
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class InvalidRequestError(ErrorDetail):
|
|
22
|
+
"""Error for an invalid request."""
|
|
23
|
+
|
|
24
|
+
type: Literal["invalid_request_error"] = Field(
|
|
25
|
+
default="invalid_request_error", alias="type"
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class AuthenticationError(ErrorDetail):
|
|
30
|
+
"""Error for authentication issues."""
|
|
31
|
+
|
|
32
|
+
type: Literal["authentication_error"] = Field(
|
|
33
|
+
default="authentication_error", alias="type"
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class BillingError(ErrorDetail):
|
|
38
|
+
"""Error for billing issues."""
|
|
39
|
+
|
|
40
|
+
type: Literal["billing_error"] = Field(default="billing_error", alias="type")
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class PermissionError(ErrorDetail):
|
|
44
|
+
"""Error for permission issues."""
|
|
45
|
+
|
|
46
|
+
type: Literal["permission_error"] = Field(default="permission_error", alias="type")
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class NotFoundError(ErrorDetail):
|
|
50
|
+
"""Error for a resource not being found."""
|
|
51
|
+
|
|
52
|
+
type: Literal["not_found_error"] = Field(default="not_found_error", alias="type")
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class RateLimitError(ErrorDetail):
|
|
56
|
+
"""Error for rate limiting."""
|
|
57
|
+
|
|
58
|
+
type: Literal["rate_limit_error"] = Field(default="rate_limit_error", alias="type")
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class GatewayTimeoutError(ErrorDetail):
|
|
62
|
+
"""Error for a gateway timeout."""
|
|
63
|
+
|
|
64
|
+
type: Literal["timeout_error"] = Field(default="timeout_error", alias="type")
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class APIError(ErrorDetail):
|
|
68
|
+
"""A generic API error."""
|
|
69
|
+
|
|
70
|
+
type: Literal["api_error"] = Field(default="api_error", alias="type")
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class OverloadedError(ErrorDetail):
|
|
74
|
+
"""Error for when the server is overloaded."""
|
|
75
|
+
|
|
76
|
+
type: Literal["overloaded_error"] = Field(default="overloaded_error", alias="type")
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
ErrorType = Annotated[
|
|
80
|
+
InvalidRequestError
|
|
81
|
+
| AuthenticationError
|
|
82
|
+
| BillingError
|
|
83
|
+
| PermissionError
|
|
84
|
+
| NotFoundError
|
|
85
|
+
| RateLimitError
|
|
86
|
+
| GatewayTimeoutError
|
|
87
|
+
| APIError
|
|
88
|
+
| OverloadedError,
|
|
89
|
+
Field(discriminator="type"),
|
|
90
|
+
]
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class ErrorResponse(LlmBaseModel):
|
|
94
|
+
"""The structure of an error response."""
|
|
95
|
+
|
|
96
|
+
type: Literal["error"] = Field(default="error", alias="type")
|
|
97
|
+
error: ErrorType
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
# ===================================================================
|
|
101
|
+
# Models API Models (/v1/models)
|
|
102
|
+
# ===================================================================
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
class ModelInfo(LlmBaseModel):
|
|
106
|
+
"""Information about an available model."""
|
|
107
|
+
|
|
108
|
+
id: str
|
|
109
|
+
type: Literal["model"] = Field(default="model", alias="type")
|
|
110
|
+
created_at: datetime
|
|
111
|
+
display_name: str
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class ListModelsResponse(LlmBaseModel):
|
|
115
|
+
"""Response containing a list of available models."""
|
|
116
|
+
|
|
117
|
+
data: list[ModelInfo]
|
|
118
|
+
first_id: str | None = None
|
|
119
|
+
last_id: str | None = None
|
|
120
|
+
has_more: bool
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
# ===================================================================
|
|
124
|
+
# Messages API Models (/v1/messages)
|
|
125
|
+
# ===================================================================
|
|
126
|
+
|
|
127
|
+
# --- Base Models & Common Structures for Messages ---
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
class ContentBlockBase(LlmBaseModel):
|
|
131
|
+
"""Base model for a content block."""
|
|
132
|
+
|
|
133
|
+
pass
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
class TextBlock(ContentBlockBase):
|
|
137
|
+
"""A block of text content."""
|
|
138
|
+
|
|
139
|
+
type: Literal["text"] = Field(default="text", alias="type")
|
|
140
|
+
text: str
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
class TextDelta(ContentBlockBase):
|
|
144
|
+
"""A delta chunk of text content used in streaming events."""
|
|
145
|
+
|
|
146
|
+
type: Literal["text_delta"] = Field(default="text_delta", alias="type")
|
|
147
|
+
text: str
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
class ImageSource(LlmBaseModel):
|
|
151
|
+
"""Source of an image."""
|
|
152
|
+
|
|
153
|
+
type: Literal["base64"] = Field(default="base64", alias="type")
|
|
154
|
+
media_type: Literal["image/jpeg", "image/png", "image/gif", "image/webp"]
|
|
155
|
+
data: str
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
class ImageBlock(ContentBlockBase):
|
|
159
|
+
"""A block of image content."""
|
|
160
|
+
|
|
161
|
+
type: Literal["image"] = Field(default="image", alias="type")
|
|
162
|
+
source: ImageSource
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
class ToolUseBlock(ContentBlockBase):
|
|
166
|
+
"""Block for a tool use."""
|
|
167
|
+
|
|
168
|
+
type: Literal["tool_use"] = Field(default="tool_use", alias="type")
|
|
169
|
+
id: str
|
|
170
|
+
name: str
|
|
171
|
+
input: dict[str, Any]
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
class ToolResultBlock(ContentBlockBase):
|
|
175
|
+
"""Block for the result of a tool use."""
|
|
176
|
+
|
|
177
|
+
type: Literal["tool_result"] = Field(default="tool_result", alias="type")
|
|
178
|
+
tool_use_id: str
|
|
179
|
+
content: str | list[TextBlock | ImageBlock] = ""
|
|
180
|
+
is_error: bool = False
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
class ThinkingBlock(ContentBlockBase):
|
|
184
|
+
"""Block representing the model's thinking process."""
|
|
185
|
+
|
|
186
|
+
type: Literal["thinking"] = Field(default="thinking", alias="type")
|
|
187
|
+
thinking: str
|
|
188
|
+
signature: str
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
class ThinkingDelta(ContentBlockBase):
|
|
192
|
+
"""Partial thinking content emitted during streaming."""
|
|
193
|
+
|
|
194
|
+
type: Literal["thinking_delta"] = Field(default="thinking_delta", alias="type")
|
|
195
|
+
thinking: str = ""
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
class SignatureDelta(ContentBlockBase):
|
|
199
|
+
"""Partial signature content for a thinking block."""
|
|
200
|
+
|
|
201
|
+
type: Literal["signature_delta"] = Field(default="signature_delta", alias="type")
|
|
202
|
+
signature: str = ""
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
class InputJsonDelta(ContentBlockBase):
|
|
206
|
+
"""Partial JSON payload for a tool use block."""
|
|
207
|
+
|
|
208
|
+
type: Literal["input_json_delta"] = Field(default="input_json_delta", alias="type")
|
|
209
|
+
partial_json: str = ""
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
class RedactedThinkingBlock(ContentBlockBase):
|
|
213
|
+
"""A block specifying internal, redacted thinking by the model."""
|
|
214
|
+
|
|
215
|
+
type: Literal["redacted_thinking"] = Field(
|
|
216
|
+
default="redacted_thinking", alias="type"
|
|
217
|
+
)
|
|
218
|
+
data: str
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
RequestContentBlock = Annotated[
|
|
222
|
+
TextBlock | ImageBlock | ToolUseBlock | ToolResultBlock, Field(discriminator="type")
|
|
223
|
+
]
|
|
224
|
+
|
|
225
|
+
ResponseContentBlock = Annotated[
|
|
226
|
+
TextBlock | ToolUseBlock | ThinkingBlock | RedactedThinkingBlock,
|
|
227
|
+
Field(discriminator="type"),
|
|
228
|
+
]
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
class Message(LlmBaseModel):
|
|
232
|
+
"""A message in the conversation."""
|
|
233
|
+
|
|
234
|
+
role: Literal["user", "assistant"]
|
|
235
|
+
content: str | list[RequestContentBlock]
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
class CacheCreation(LlmBaseModel):
|
|
239
|
+
"""Breakdown of cached tokens."""
|
|
240
|
+
|
|
241
|
+
ephemeral_1h_input_tokens: int
|
|
242
|
+
ephemeral_5m_input_tokens: int
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
class ServerToolUsage(LlmBaseModel):
|
|
246
|
+
"""Server-side tool usage statistics."""
|
|
247
|
+
|
|
248
|
+
web_search_requests: int
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
class Usage(LlmBaseModel):
|
|
252
|
+
"""Token usage statistics."""
|
|
253
|
+
|
|
254
|
+
input_tokens: int | None = None
|
|
255
|
+
output_tokens: int | None = None
|
|
256
|
+
cache_creation: CacheCreation | None = None
|
|
257
|
+
cache_creation_input_tokens: int | None = None
|
|
258
|
+
cache_read_input_tokens: int | None = None
|
|
259
|
+
server_tool_use: ServerToolUsage | None = None
|
|
260
|
+
service_tier: Literal["standard", "priority", "batch"] | None = None
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
# --- Tool Definitions ---
|
|
264
|
+
def _normalize_tool_payload(value: Any) -> Any:
|
|
265
|
+
"""Return a mutable dict with required tool fields normalized."""
|
|
266
|
+
|
|
267
|
+
if not isinstance(value, dict):
|
|
268
|
+
return value
|
|
269
|
+
|
|
270
|
+
normalized: dict[str, Any] = deepcopy(value)
|
|
271
|
+
custom = normalized.get("custom")
|
|
272
|
+
if isinstance(custom, dict):
|
|
273
|
+
for key in ("name", "description", "input_schema"):
|
|
274
|
+
normalized.setdefault(key, custom.get(key))
|
|
275
|
+
|
|
276
|
+
normalized.setdefault("input_schema", normalized.get("input_schema") or {})
|
|
277
|
+
|
|
278
|
+
if "type" not in normalized:
|
|
279
|
+
normalized["type"] = "custom"
|
|
280
|
+
|
|
281
|
+
return normalized
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
class ToolBase(LlmBaseModel):
|
|
285
|
+
"""Shared fields for custom tool definitions."""
|
|
286
|
+
|
|
287
|
+
name: str = Field(
|
|
288
|
+
..., min_length=1, max_length=128, pattern=r"^[a-zA-Z0-9_-]{1,128}$"
|
|
289
|
+
)
|
|
290
|
+
description: str | None = None
|
|
291
|
+
input_schema: dict[str, Any] = Field(default_factory=dict)
|
|
292
|
+
|
|
293
|
+
@model_validator(mode="before")
|
|
294
|
+
@classmethod
|
|
295
|
+
def _merge_nested_custom(cls, value: Any) -> Any:
|
|
296
|
+
"""Support nested {"custom": {...}} payloads by flattening fields."""
|
|
297
|
+
return _normalize_tool_payload(value)
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
class Tool(ToolBase):
|
|
301
|
+
"""Definition of a custom tool in the current Anthropic schema."""
|
|
302
|
+
|
|
303
|
+
type: Literal["tool"] = Field(default="tool", alias="type")
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
class LegacyCustomTool(ToolBase):
|
|
307
|
+
"""Backward-compatible support for earlier 'custom' tool payloads."""
|
|
308
|
+
|
|
309
|
+
type: Literal["custom"] = Field(default="custom", alias="type")
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
class WebSearchTool(LlmBaseModel):
|
|
313
|
+
"""Definition for the built-in web search tool."""
|
|
314
|
+
|
|
315
|
+
type: Literal["web_search_20250305"] = Field(
|
|
316
|
+
default="web_search_20250305", alias="type"
|
|
317
|
+
)
|
|
318
|
+
name: Literal["web_search"] = "web_search"
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
# Add other specific built-in tool models here as needed
|
|
322
|
+
AnyTool = Annotated[
|
|
323
|
+
Tool | LegacyCustomTool | WebSearchTool, # Union of all tool types
|
|
324
|
+
Field(discriminator="type"),
|
|
325
|
+
]
|
|
326
|
+
|
|
327
|
+
# --- Supporting models for CreateMessageRequest ---
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
class Metadata(LlmBaseModel):
|
|
331
|
+
"""Metadata about the request."""
|
|
332
|
+
|
|
333
|
+
user_id: str | None = Field(None, max_length=256)
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
class ThinkingConfigBase(LlmBaseModel):
|
|
337
|
+
"""Base model for thinking configuration."""
|
|
338
|
+
|
|
339
|
+
pass
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
class ThinkingConfigEnabled(ThinkingConfigBase):
|
|
343
|
+
"""Configuration for enabled thinking."""
|
|
344
|
+
|
|
345
|
+
type: Literal["enabled"] = Field(default="enabled", alias="type")
|
|
346
|
+
budget_tokens: int = Field(..., ge=1024)
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
class ThinkingConfigDisabled(ThinkingConfigBase):
|
|
350
|
+
"""Configuration for disabled thinking."""
|
|
351
|
+
|
|
352
|
+
type: Literal["disabled"] = Field(default="disabled", alias="type")
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
ThinkingConfig = Annotated[
|
|
356
|
+
ThinkingConfigEnabled | ThinkingConfigDisabled, Field(discriminator="type")
|
|
357
|
+
]
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
class ToolChoiceBase(LlmBaseModel):
|
|
361
|
+
"""Base model for tool choice."""
|
|
362
|
+
|
|
363
|
+
pass
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
class ToolChoiceAuto(ToolChoiceBase):
|
|
367
|
+
"""The model will automatically decide whether to use tools."""
|
|
368
|
+
|
|
369
|
+
type: Literal["auto"] = Field(default="auto", alias="type")
|
|
370
|
+
disable_parallel_tool_use: bool = False
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
class ToolChoiceAny(ToolChoiceBase):
|
|
374
|
+
"""The model will use any available tools."""
|
|
375
|
+
|
|
376
|
+
type: Literal["any"] = Field(default="any", alias="type")
|
|
377
|
+
disable_parallel_tool_use: bool = False
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
class ToolChoiceTool(ToolChoiceBase):
|
|
381
|
+
"""The model will use the specified tool."""
|
|
382
|
+
|
|
383
|
+
type: Literal["tool"] = Field(default="tool", alias="type")
|
|
384
|
+
name: str
|
|
385
|
+
disable_parallel_tool_use: bool = False
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
class ToolChoiceNone(ToolChoiceBase):
|
|
389
|
+
"""The model will not use any tools."""
|
|
390
|
+
|
|
391
|
+
type: Literal["none"] = Field(default="none", alias="type")
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
ToolChoice = Annotated[
|
|
395
|
+
ToolChoiceAuto | ToolChoiceAny | ToolChoiceTool | ToolChoiceNone,
|
|
396
|
+
Field(discriminator="type"),
|
|
397
|
+
]
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
class RequestMCPServerToolConfiguration(LlmBaseModel):
|
|
401
|
+
"""Tool configuration for an MCP server."""
|
|
402
|
+
|
|
403
|
+
allowed_tools: list[str] | None = None
|
|
404
|
+
enabled: bool | None = None
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
class RequestMCPServerURLDefinition(LlmBaseModel):
|
|
408
|
+
"""URL definition for an MCP server."""
|
|
409
|
+
|
|
410
|
+
name: str
|
|
411
|
+
type: Literal["url"] = Field(default="url", alias="type")
|
|
412
|
+
url: str
|
|
413
|
+
authorization_token: str | None = None
|
|
414
|
+
tool_configuration: RequestMCPServerToolConfiguration | None = None
|
|
415
|
+
|
|
416
|
+
|
|
417
|
+
class Container(LlmBaseModel):
|
|
418
|
+
"""Information about the container used in a request."""
|
|
419
|
+
|
|
420
|
+
id: str
|
|
421
|
+
expires_at: datetime
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
# --- Request Models ---
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
class CreateMessageRequest(LlmBaseModel):
|
|
428
|
+
"""Request model for creating a new message."""
|
|
429
|
+
|
|
430
|
+
model: str
|
|
431
|
+
messages: list[Message]
|
|
432
|
+
max_tokens: int
|
|
433
|
+
container: str | None = None
|
|
434
|
+
mcp_servers: list[RequestMCPServerURLDefinition] | None = None
|
|
435
|
+
metadata: Metadata | None = None
|
|
436
|
+
service_tier: Literal["auto", "standard_only"] | None = None
|
|
437
|
+
stop_sequences: list[str] | None = None
|
|
438
|
+
stream: bool = False
|
|
439
|
+
system: str | list[TextBlock] | None = None
|
|
440
|
+
temperature: float | None = Field(default=None, ge=0.0, le=1.0)
|
|
441
|
+
thinking: ThinkingConfig | None = None
|
|
442
|
+
tools: list[AnyTool] | None = None
|
|
443
|
+
tool_choice: ToolChoice | None = Field(default=None)
|
|
444
|
+
top_k: int | None = None
|
|
445
|
+
top_p: float | None = Field(default=None, ge=0.0, le=1.0)
|
|
446
|
+
|
|
447
|
+
@model_validator(mode="before")
|
|
448
|
+
@classmethod
|
|
449
|
+
def _normalize_tools(cls, data: Any) -> Any:
|
|
450
|
+
if not isinstance(data, dict):
|
|
451
|
+
return data
|
|
452
|
+
|
|
453
|
+
tools = data.get("tools")
|
|
454
|
+
if isinstance(tools, list):
|
|
455
|
+
data["tools"] = [_normalize_tool_payload(tool) for tool in tools]
|
|
456
|
+
|
|
457
|
+
return data
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
class CountMessageTokensRequest(LlmBaseModel):
|
|
461
|
+
"""Request model for counting tokens in a message."""
|
|
462
|
+
|
|
463
|
+
model: str
|
|
464
|
+
messages: list[Message]
|
|
465
|
+
system: str | list[TextBlock] | None = None
|
|
466
|
+
tools: list[AnyTool] | None = None
|
|
467
|
+
|
|
468
|
+
@model_validator(mode="before")
|
|
469
|
+
@classmethod
|
|
470
|
+
def _normalize_tools(cls, data: Any) -> Any:
|
|
471
|
+
if not isinstance(data, dict):
|
|
472
|
+
return data
|
|
473
|
+
|
|
474
|
+
tools = data.get("tools")
|
|
475
|
+
if isinstance(tools, list):
|
|
476
|
+
data["tools"] = [_normalize_tool_payload(tool) for tool in tools]
|
|
477
|
+
|
|
478
|
+
return data
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
# --- Response Models ---
|
|
482
|
+
|
|
483
|
+
|
|
484
|
+
class MessageResponse(LlmBaseModel):
|
|
485
|
+
"""Response model for a created message."""
|
|
486
|
+
|
|
487
|
+
id: str
|
|
488
|
+
type: Literal["message"] = Field(default="message", alias="type")
|
|
489
|
+
role: Literal["assistant"]
|
|
490
|
+
content: list[ResponseContentBlock]
|
|
491
|
+
model: str
|
|
492
|
+
stop_reason: (
|
|
493
|
+
Literal[
|
|
494
|
+
"end_turn",
|
|
495
|
+
"max_tokens",
|
|
496
|
+
"stop_sequence",
|
|
497
|
+
"tool_use",
|
|
498
|
+
"pause_turn",
|
|
499
|
+
"refusal",
|
|
500
|
+
]
|
|
501
|
+
| None
|
|
502
|
+
) = None
|
|
503
|
+
stop_sequence: str | None = None
|
|
504
|
+
usage: Usage
|
|
505
|
+
container: Container | None = None
|
|
506
|
+
|
|
507
|
+
|
|
508
|
+
class CountMessageTokensResponse(LlmBaseModel):
|
|
509
|
+
"""Response model for a token count request."""
|
|
510
|
+
|
|
511
|
+
input_tokens: int
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
# ===================================================================
|
|
515
|
+
# Streaming Models for /v1/messages
|
|
516
|
+
# ===================================================================
|
|
517
|
+
|
|
518
|
+
|
|
519
|
+
class PingEvent(LlmBaseModel):
|
|
520
|
+
"""A keep-alive event."""
|
|
521
|
+
|
|
522
|
+
type: Literal["ping"] = Field(default="ping", alias="type")
|
|
523
|
+
|
|
524
|
+
|
|
525
|
+
class ErrorEvent(LlmBaseModel):
|
|
526
|
+
"""An error event in the stream."""
|
|
527
|
+
|
|
528
|
+
type: Literal["error"] = Field(default="error", alias="type")
|
|
529
|
+
error: ErrorDetail
|
|
530
|
+
|
|
531
|
+
|
|
532
|
+
class MessageStartEvent(LlmBaseModel):
|
|
533
|
+
"""Event sent when a message stream starts."""
|
|
534
|
+
|
|
535
|
+
type: Literal["message_start"] = Field(default="message_start", alias="type")
|
|
536
|
+
message: MessageResponse
|
|
537
|
+
|
|
538
|
+
|
|
539
|
+
class ContentBlockStartEvent(LlmBaseModel):
|
|
540
|
+
"""Event when a content block starts."""
|
|
541
|
+
|
|
542
|
+
type: Literal["content_block_start"] = Field(
|
|
543
|
+
default="content_block_start", alias="type"
|
|
544
|
+
)
|
|
545
|
+
index: int
|
|
546
|
+
content_block: ResponseContentBlock
|
|
547
|
+
|
|
548
|
+
|
|
549
|
+
class ContentBlockDeltaEvent(LlmBaseModel):
|
|
550
|
+
"""Event for a delta in a content block."""
|
|
551
|
+
|
|
552
|
+
type: Literal["content_block_delta"] = Field(
|
|
553
|
+
default="content_block_delta", alias="type"
|
|
554
|
+
)
|
|
555
|
+
index: int
|
|
556
|
+
# Anthropic streams use delta.type == "text_delta" during streaming.
|
|
557
|
+
# Accept both TextBlock (some SDKs may coerce) and TextDelta.
|
|
558
|
+
delta: Annotated[
|
|
559
|
+
TextBlock
|
|
560
|
+
| TextDelta
|
|
561
|
+
| ThinkingBlock
|
|
562
|
+
| ThinkingDelta
|
|
563
|
+
| SignatureDelta
|
|
564
|
+
| InputJsonDelta,
|
|
565
|
+
Field(discriminator="type"),
|
|
566
|
+
]
|
|
567
|
+
|
|
568
|
+
|
|
569
|
+
class ContentBlockStopEvent(LlmBaseModel):
|
|
570
|
+
"""Event when a content block stops."""
|
|
571
|
+
|
|
572
|
+
type: Literal["content_block_stop"] = Field(
|
|
573
|
+
default="content_block_stop", alias="type"
|
|
574
|
+
)
|
|
575
|
+
index: int
|
|
576
|
+
|
|
577
|
+
|
|
578
|
+
class MessageDelta(LlmBaseModel):
|
|
579
|
+
"""The delta in a message delta event."""
|
|
580
|
+
|
|
581
|
+
stop_reason: (
|
|
582
|
+
Literal[
|
|
583
|
+
"end_turn",
|
|
584
|
+
"max_tokens",
|
|
585
|
+
"stop_sequence",
|
|
586
|
+
"tool_use",
|
|
587
|
+
"pause_turn",
|
|
588
|
+
"refusal",
|
|
589
|
+
]
|
|
590
|
+
| None
|
|
591
|
+
) = None
|
|
592
|
+
stop_sequence: str | None = None
|
|
593
|
+
|
|
594
|
+
|
|
595
|
+
class MessageDeltaEvent(LlmBaseModel):
|
|
596
|
+
"""Event for a delta in the message metadata."""
|
|
597
|
+
|
|
598
|
+
type: Literal["message_delta"] = Field(default="message_delta", alias="type")
|
|
599
|
+
delta: MessageDelta
|
|
600
|
+
usage: Usage
|
|
601
|
+
|
|
602
|
+
|
|
603
|
+
class MessageStopEvent(LlmBaseModel):
|
|
604
|
+
"""Event sent when a message stream stops."""
|
|
605
|
+
|
|
606
|
+
type: Literal["message_stop"] = Field(default="message_stop", alias="type")
|
|
607
|
+
|
|
608
|
+
|
|
609
|
+
MessageStreamEvent = Annotated[
|
|
610
|
+
PingEvent
|
|
611
|
+
| ErrorEvent
|
|
612
|
+
| MessageStartEvent
|
|
613
|
+
| ContentBlockStartEvent
|
|
614
|
+
| ContentBlockDeltaEvent
|
|
615
|
+
| ContentBlockStopEvent
|
|
616
|
+
| MessageDeltaEvent
|
|
617
|
+
| MessageStopEvent,
|
|
618
|
+
Field(discriminator="type"),
|
|
619
|
+
]
|