ccproxy-api 0.1.0__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/__init__.py +4 -0
- ccproxy/__main__.py +7 -0
- ccproxy/_version.py +21 -0
- ccproxy/adapters/__init__.py +11 -0
- ccproxy/adapters/base.py +80 -0
- ccproxy/adapters/openai/__init__.py +43 -0
- ccproxy/adapters/openai/adapter.py +915 -0
- ccproxy/adapters/openai/models.py +412 -0
- ccproxy/adapters/openai/streaming.py +449 -0
- ccproxy/api/__init__.py +28 -0
- ccproxy/api/app.py +225 -0
- ccproxy/api/dependencies.py +140 -0
- ccproxy/api/middleware/__init__.py +11 -0
- ccproxy/api/middleware/auth.py +0 -0
- ccproxy/api/middleware/cors.py +55 -0
- ccproxy/api/middleware/errors.py +703 -0
- ccproxy/api/middleware/headers.py +51 -0
- ccproxy/api/middleware/logging.py +175 -0
- ccproxy/api/middleware/request_id.py +69 -0
- ccproxy/api/middleware/server_header.py +62 -0
- ccproxy/api/responses.py +84 -0
- ccproxy/api/routes/__init__.py +16 -0
- ccproxy/api/routes/claude.py +181 -0
- ccproxy/api/routes/health.py +489 -0
- ccproxy/api/routes/metrics.py +1033 -0
- ccproxy/api/routes/proxy.py +238 -0
- ccproxy/auth/__init__.py +75 -0
- ccproxy/auth/bearer.py +68 -0
- ccproxy/auth/credentials_adapter.py +93 -0
- ccproxy/auth/dependencies.py +229 -0
- ccproxy/auth/exceptions.py +79 -0
- ccproxy/auth/manager.py +102 -0
- ccproxy/auth/models.py +118 -0
- ccproxy/auth/oauth/__init__.py +26 -0
- ccproxy/auth/oauth/models.py +49 -0
- ccproxy/auth/oauth/routes.py +396 -0
- ccproxy/auth/oauth/storage.py +0 -0
- ccproxy/auth/storage/__init__.py +12 -0
- ccproxy/auth/storage/base.py +57 -0
- ccproxy/auth/storage/json_file.py +159 -0
- ccproxy/auth/storage/keyring.py +192 -0
- ccproxy/claude_sdk/__init__.py +20 -0
- ccproxy/claude_sdk/client.py +169 -0
- ccproxy/claude_sdk/converter.py +331 -0
- ccproxy/claude_sdk/options.py +120 -0
- ccproxy/cli/__init__.py +14 -0
- ccproxy/cli/commands/__init__.py +8 -0
- ccproxy/cli/commands/auth.py +553 -0
- ccproxy/cli/commands/config/__init__.py +14 -0
- ccproxy/cli/commands/config/commands.py +766 -0
- ccproxy/cli/commands/config/schema_commands.py +119 -0
- ccproxy/cli/commands/serve.py +630 -0
- ccproxy/cli/docker/__init__.py +34 -0
- ccproxy/cli/docker/adapter_factory.py +157 -0
- ccproxy/cli/docker/params.py +278 -0
- ccproxy/cli/helpers.py +144 -0
- ccproxy/cli/main.py +193 -0
- ccproxy/cli/options/__init__.py +14 -0
- ccproxy/cli/options/claude_options.py +216 -0
- ccproxy/cli/options/core_options.py +40 -0
- ccproxy/cli/options/security_options.py +48 -0
- ccproxy/cli/options/server_options.py +117 -0
- ccproxy/config/__init__.py +40 -0
- ccproxy/config/auth.py +154 -0
- ccproxy/config/claude.py +124 -0
- ccproxy/config/cors.py +79 -0
- ccproxy/config/discovery.py +87 -0
- ccproxy/config/docker_settings.py +265 -0
- ccproxy/config/loader.py +108 -0
- ccproxy/config/observability.py +158 -0
- ccproxy/config/pricing.py +88 -0
- ccproxy/config/reverse_proxy.py +31 -0
- ccproxy/config/scheduler.py +89 -0
- ccproxy/config/security.py +14 -0
- ccproxy/config/server.py +81 -0
- ccproxy/config/settings.py +534 -0
- ccproxy/config/validators.py +231 -0
- ccproxy/core/__init__.py +274 -0
- ccproxy/core/async_utils.py +675 -0
- ccproxy/core/constants.py +97 -0
- ccproxy/core/errors.py +256 -0
- ccproxy/core/http.py +328 -0
- ccproxy/core/http_transformers.py +428 -0
- ccproxy/core/interfaces.py +247 -0
- ccproxy/core/logging.py +189 -0
- ccproxy/core/middleware.py +114 -0
- ccproxy/core/proxy.py +143 -0
- ccproxy/core/system.py +38 -0
- ccproxy/core/transformers.py +259 -0
- ccproxy/core/types.py +129 -0
- ccproxy/core/validators.py +288 -0
- ccproxy/docker/__init__.py +67 -0
- ccproxy/docker/adapter.py +588 -0
- ccproxy/docker/docker_path.py +207 -0
- ccproxy/docker/middleware.py +103 -0
- ccproxy/docker/models.py +228 -0
- ccproxy/docker/protocol.py +192 -0
- ccproxy/docker/stream_process.py +264 -0
- ccproxy/docker/validators.py +173 -0
- ccproxy/models/__init__.py +123 -0
- ccproxy/models/errors.py +42 -0
- ccproxy/models/messages.py +243 -0
- ccproxy/models/requests.py +85 -0
- ccproxy/models/responses.py +227 -0
- ccproxy/models/types.py +102 -0
- ccproxy/observability/__init__.py +51 -0
- ccproxy/observability/access_logger.py +400 -0
- ccproxy/observability/context.py +447 -0
- ccproxy/observability/metrics.py +539 -0
- ccproxy/observability/pushgateway.py +366 -0
- ccproxy/observability/sse_events.py +303 -0
- ccproxy/observability/stats_printer.py +755 -0
- ccproxy/observability/storage/__init__.py +1 -0
- ccproxy/observability/storage/duckdb_simple.py +665 -0
- ccproxy/observability/storage/models.py +55 -0
- ccproxy/pricing/__init__.py +19 -0
- ccproxy/pricing/cache.py +212 -0
- ccproxy/pricing/loader.py +267 -0
- ccproxy/pricing/models.py +106 -0
- ccproxy/pricing/updater.py +309 -0
- ccproxy/scheduler/__init__.py +39 -0
- ccproxy/scheduler/core.py +335 -0
- ccproxy/scheduler/exceptions.py +34 -0
- ccproxy/scheduler/manager.py +186 -0
- ccproxy/scheduler/registry.py +150 -0
- ccproxy/scheduler/tasks.py +484 -0
- ccproxy/services/__init__.py +10 -0
- ccproxy/services/claude_sdk_service.py +614 -0
- ccproxy/services/credentials/__init__.py +55 -0
- ccproxy/services/credentials/config.py +105 -0
- ccproxy/services/credentials/manager.py +562 -0
- ccproxy/services/credentials/oauth_client.py +482 -0
- ccproxy/services/proxy_service.py +1536 -0
- ccproxy/static/.keep +0 -0
- ccproxy/testing/__init__.py +34 -0
- ccproxy/testing/config.py +148 -0
- ccproxy/testing/content_generation.py +197 -0
- ccproxy/testing/mock_responses.py +262 -0
- ccproxy/testing/response_handlers.py +161 -0
- ccproxy/testing/scenarios.py +241 -0
- ccproxy/utils/__init__.py +6 -0
- ccproxy/utils/cost_calculator.py +210 -0
- ccproxy/utils/streaming_metrics.py +199 -0
- ccproxy_api-0.1.0.dist-info/METADATA +253 -0
- ccproxy_api-0.1.0.dist-info/RECORD +148 -0
- ccproxy_api-0.1.0.dist-info/WHEEL +4 -0
- ccproxy_api-0.1.0.dist-info/entry_points.txt +2 -0
- ccproxy_api-0.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
"""Configuration validation utilities."""
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Any, Optional, Union
|
|
6
|
+
from urllib.parse import urlparse
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ConfigValidationError(Exception):
|
|
10
|
+
"""Configuration validation error."""
|
|
11
|
+
|
|
12
|
+
pass
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def validate_host(host: str) -> str:
|
|
16
|
+
"""Validate host address.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
host: Host address to validate
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
The validated host address
|
|
23
|
+
|
|
24
|
+
Raises:
|
|
25
|
+
ConfigValidationError: If host is invalid
|
|
26
|
+
"""
|
|
27
|
+
if not host:
|
|
28
|
+
raise ConfigValidationError("Host cannot be empty")
|
|
29
|
+
|
|
30
|
+
# Allow localhost, IP addresses, and domain names
|
|
31
|
+
if host in ["localhost", "0.0.0.0", "127.0.0.1"]:
|
|
32
|
+
return host
|
|
33
|
+
|
|
34
|
+
# Basic IP address validation
|
|
35
|
+
if re.match(r"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$", host):
|
|
36
|
+
parts = host.split(".")
|
|
37
|
+
if all(0 <= int(part) <= 255 for part in parts):
|
|
38
|
+
return host
|
|
39
|
+
raise ConfigValidationError(f"Invalid IP address: {host}")
|
|
40
|
+
|
|
41
|
+
# Basic domain name validation
|
|
42
|
+
if re.match(r"^[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$", host):
|
|
43
|
+
return host
|
|
44
|
+
|
|
45
|
+
return host # Allow other formats for flexibility
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def validate_port(port: int | str) -> int:
|
|
49
|
+
"""Validate port number.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
port: Port number to validate
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
The validated port number
|
|
56
|
+
|
|
57
|
+
Raises:
|
|
58
|
+
ConfigValidationError: If port is invalid
|
|
59
|
+
"""
|
|
60
|
+
if isinstance(port, str):
|
|
61
|
+
try:
|
|
62
|
+
port = int(port)
|
|
63
|
+
except ValueError as e:
|
|
64
|
+
raise ConfigValidationError(f"Port must be a valid integer: {port}") from e
|
|
65
|
+
|
|
66
|
+
if not isinstance(port, int):
|
|
67
|
+
raise ConfigValidationError(f"Port must be an integer: {port}")
|
|
68
|
+
|
|
69
|
+
if port < 1 or port > 65535:
|
|
70
|
+
raise ConfigValidationError(f"Port must be between 1 and 65535: {port}")
|
|
71
|
+
|
|
72
|
+
return port
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def validate_url(url: str) -> str:
|
|
76
|
+
"""Validate URL format.
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
url: URL to validate
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
The validated URL
|
|
83
|
+
|
|
84
|
+
Raises:
|
|
85
|
+
ConfigValidationError: If URL is invalid
|
|
86
|
+
"""
|
|
87
|
+
if not url:
|
|
88
|
+
raise ConfigValidationError("URL cannot be empty")
|
|
89
|
+
|
|
90
|
+
try:
|
|
91
|
+
result = urlparse(url)
|
|
92
|
+
if not result.scheme or not result.netloc:
|
|
93
|
+
raise ConfigValidationError(f"Invalid URL format: {url}")
|
|
94
|
+
except Exception as e:
|
|
95
|
+
raise ConfigValidationError(f"Invalid URL: {url}") from e
|
|
96
|
+
|
|
97
|
+
return url
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def validate_path(path: str | Path) -> Path:
|
|
101
|
+
"""Validate file path.
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
path: Path to validate
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
The validated Path object
|
|
108
|
+
|
|
109
|
+
Raises:
|
|
110
|
+
ConfigValidationError: If path is invalid
|
|
111
|
+
"""
|
|
112
|
+
if isinstance(path, str):
|
|
113
|
+
path = Path(path)
|
|
114
|
+
|
|
115
|
+
if not isinstance(path, Path):
|
|
116
|
+
raise ConfigValidationError(f"Path must be a string or Path object: {path}")
|
|
117
|
+
|
|
118
|
+
return path
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def validate_log_level(level: str) -> str:
|
|
122
|
+
"""Validate log level.
|
|
123
|
+
|
|
124
|
+
Args:
|
|
125
|
+
level: Log level to validate
|
|
126
|
+
|
|
127
|
+
Returns:
|
|
128
|
+
The validated log level
|
|
129
|
+
|
|
130
|
+
Raises:
|
|
131
|
+
ConfigValidationError: If log level is invalid
|
|
132
|
+
"""
|
|
133
|
+
valid_levels = ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]
|
|
134
|
+
level = level.upper()
|
|
135
|
+
|
|
136
|
+
if level not in valid_levels:
|
|
137
|
+
raise ConfigValidationError(
|
|
138
|
+
f"Invalid log level: {level}. Must be one of: {valid_levels}"
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
return level
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def validate_cors_origins(origins: list[str]) -> list[str]:
|
|
145
|
+
"""Validate CORS origins.
|
|
146
|
+
|
|
147
|
+
Args:
|
|
148
|
+
origins: List of origin URLs to validate
|
|
149
|
+
|
|
150
|
+
Returns:
|
|
151
|
+
The validated list of origins
|
|
152
|
+
|
|
153
|
+
Raises:
|
|
154
|
+
ConfigValidationError: If any origin is invalid
|
|
155
|
+
"""
|
|
156
|
+
if not isinstance(origins, list):
|
|
157
|
+
raise ConfigValidationError("CORS origins must be a list")
|
|
158
|
+
|
|
159
|
+
validated_origins = []
|
|
160
|
+
for origin in origins:
|
|
161
|
+
if origin == "*":
|
|
162
|
+
validated_origins.append(origin)
|
|
163
|
+
else:
|
|
164
|
+
validated_origins.append(validate_url(origin))
|
|
165
|
+
|
|
166
|
+
return validated_origins
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def validate_timeout(timeout: int | float) -> int | float:
|
|
170
|
+
"""Validate timeout value.
|
|
171
|
+
|
|
172
|
+
Args:
|
|
173
|
+
timeout: Timeout value to validate
|
|
174
|
+
|
|
175
|
+
Returns:
|
|
176
|
+
The validated timeout value
|
|
177
|
+
|
|
178
|
+
Raises:
|
|
179
|
+
ConfigValidationError: If timeout is invalid
|
|
180
|
+
"""
|
|
181
|
+
if not isinstance(timeout, int | float):
|
|
182
|
+
raise ConfigValidationError(f"Timeout must be a number: {timeout}")
|
|
183
|
+
|
|
184
|
+
if timeout <= 0:
|
|
185
|
+
raise ConfigValidationError(f"Timeout must be positive: {timeout}")
|
|
186
|
+
|
|
187
|
+
return timeout
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def validate_config_dict(config: dict[str, Any]) -> dict[str, Any]:
|
|
191
|
+
"""Validate configuration dictionary.
|
|
192
|
+
|
|
193
|
+
Args:
|
|
194
|
+
config: Configuration dictionary to validate
|
|
195
|
+
|
|
196
|
+
Returns:
|
|
197
|
+
The validated configuration dictionary
|
|
198
|
+
|
|
199
|
+
Raises:
|
|
200
|
+
ConfigValidationError: If configuration is invalid
|
|
201
|
+
"""
|
|
202
|
+
if not isinstance(config, dict):
|
|
203
|
+
raise ConfigValidationError("Configuration must be a dictionary")
|
|
204
|
+
|
|
205
|
+
validated_config: dict[str, Any] = {}
|
|
206
|
+
|
|
207
|
+
# Validate specific fields if present
|
|
208
|
+
if "host" in config:
|
|
209
|
+
validated_config["host"] = validate_host(config["host"])
|
|
210
|
+
|
|
211
|
+
if "port" in config:
|
|
212
|
+
validated_config["port"] = validate_port(config["port"])
|
|
213
|
+
|
|
214
|
+
if "target_url" in config:
|
|
215
|
+
validated_config["target_url"] = validate_url(config["target_url"])
|
|
216
|
+
|
|
217
|
+
if "log_level" in config:
|
|
218
|
+
validated_config["log_level"] = validate_log_level(config["log_level"])
|
|
219
|
+
|
|
220
|
+
if "cors_origins" in config:
|
|
221
|
+
validated_config["cors_origins"] = validate_cors_origins(config["cors_origins"])
|
|
222
|
+
|
|
223
|
+
if "timeout" in config:
|
|
224
|
+
validated_config["timeout"] = validate_timeout(config["timeout"])
|
|
225
|
+
|
|
226
|
+
# Copy other fields without validation
|
|
227
|
+
for key, value in config.items():
|
|
228
|
+
if key not in validated_config:
|
|
229
|
+
validated_config[key] = value
|
|
230
|
+
|
|
231
|
+
return validated_config
|
ccproxy/core/__init__.py
ADDED
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
"""Core abstractions for the CCProxy API."""
|
|
2
|
+
|
|
3
|
+
from ccproxy.core.async_utils import (
|
|
4
|
+
async_cache_result,
|
|
5
|
+
async_timer,
|
|
6
|
+
gather_with_concurrency,
|
|
7
|
+
get_package_dir,
|
|
8
|
+
get_root_package_name,
|
|
9
|
+
patched_typing,
|
|
10
|
+
retry_async,
|
|
11
|
+
run_in_executor,
|
|
12
|
+
safe_await,
|
|
13
|
+
wait_for_condition,
|
|
14
|
+
)
|
|
15
|
+
from ccproxy.core.constants import (
|
|
16
|
+
ANTHROPIC_API_BASE_PATH,
|
|
17
|
+
AUTH_HEADER,
|
|
18
|
+
CHAT_COMPLETIONS_ENDPOINT,
|
|
19
|
+
CONFIG_FILE_NAMES,
|
|
20
|
+
CONTENT_TYPE_HEADER,
|
|
21
|
+
CONTENT_TYPE_JSON,
|
|
22
|
+
CONTENT_TYPE_STREAM,
|
|
23
|
+
CONTENT_TYPE_TEXT,
|
|
24
|
+
DEFAULT_DOCKER_IMAGE,
|
|
25
|
+
DEFAULT_DOCKER_TIMEOUT,
|
|
26
|
+
DEFAULT_MAX_TOKENS,
|
|
27
|
+
DEFAULT_MODEL,
|
|
28
|
+
DEFAULT_RATE_LIMIT,
|
|
29
|
+
DEFAULT_STREAM,
|
|
30
|
+
DEFAULT_TEMPERATURE,
|
|
31
|
+
DEFAULT_TIMEOUT,
|
|
32
|
+
DEFAULT_TOP_P,
|
|
33
|
+
EMAIL_PATTERN,
|
|
34
|
+
ENV_PREFIX,
|
|
35
|
+
ERROR_MSG_INTERNAL_ERROR,
|
|
36
|
+
ERROR_MSG_INVALID_REQUEST,
|
|
37
|
+
ERROR_MSG_INVALID_TOKEN,
|
|
38
|
+
ERROR_MSG_MODEL_NOT_FOUND,
|
|
39
|
+
ERROR_MSG_RATE_LIMIT_EXCEEDED,
|
|
40
|
+
JSON_EXTENSIONS,
|
|
41
|
+
LOG_LEVELS,
|
|
42
|
+
MAX_MESSAGE_LENGTH,
|
|
43
|
+
MAX_PROMPT_LENGTH,
|
|
44
|
+
MAX_TOOL_CALLS,
|
|
45
|
+
MESSAGES_ENDPOINT,
|
|
46
|
+
MODELS_ENDPOINT,
|
|
47
|
+
OPENAI_API_BASE_PATH,
|
|
48
|
+
REQUEST_ID_HEADER,
|
|
49
|
+
STATUS_BAD_GATEWAY,
|
|
50
|
+
STATUS_BAD_REQUEST,
|
|
51
|
+
STATUS_CREATED,
|
|
52
|
+
STATUS_FORBIDDEN,
|
|
53
|
+
STATUS_INTERNAL_ERROR,
|
|
54
|
+
STATUS_NOT_FOUND,
|
|
55
|
+
STATUS_OK,
|
|
56
|
+
STATUS_RATE_LIMITED,
|
|
57
|
+
STATUS_SERVICE_UNAVAILABLE,
|
|
58
|
+
STATUS_UNAUTHORIZED,
|
|
59
|
+
STREAM_EVENT_CONTENT_BLOCK_DELTA,
|
|
60
|
+
STREAM_EVENT_CONTENT_BLOCK_START,
|
|
61
|
+
STREAM_EVENT_CONTENT_BLOCK_STOP,
|
|
62
|
+
STREAM_EVENT_MESSAGE_DELTA,
|
|
63
|
+
STREAM_EVENT_MESSAGE_START,
|
|
64
|
+
STREAM_EVENT_MESSAGE_STOP,
|
|
65
|
+
TOML_EXTENSIONS,
|
|
66
|
+
URL_PATTERN,
|
|
67
|
+
UUID_PATTERN,
|
|
68
|
+
YAML_EXTENSIONS,
|
|
69
|
+
)
|
|
70
|
+
from ccproxy.core.errors import (
|
|
71
|
+
MiddlewareError,
|
|
72
|
+
ProxyAuthenticationError,
|
|
73
|
+
ProxyConnectionError,
|
|
74
|
+
ProxyError,
|
|
75
|
+
ProxyTimeoutError,
|
|
76
|
+
TransformationError,
|
|
77
|
+
)
|
|
78
|
+
from ccproxy.core.http import (
|
|
79
|
+
BaseProxyClient,
|
|
80
|
+
HTTPClient,
|
|
81
|
+
HTTPConnectionError,
|
|
82
|
+
HTTPError,
|
|
83
|
+
HTTPTimeoutError,
|
|
84
|
+
HTTPXClient,
|
|
85
|
+
)
|
|
86
|
+
from ccproxy.core.interfaces import (
|
|
87
|
+
APIAdapter,
|
|
88
|
+
MetricExporter,
|
|
89
|
+
StreamTransformer,
|
|
90
|
+
TokenStorage,
|
|
91
|
+
)
|
|
92
|
+
from ccproxy.core.interfaces import (
|
|
93
|
+
RequestTransformer as IRequestTransformer,
|
|
94
|
+
)
|
|
95
|
+
from ccproxy.core.interfaces import (
|
|
96
|
+
ResponseTransformer as IResponseTransformer,
|
|
97
|
+
)
|
|
98
|
+
from ccproxy.core.interfaces import (
|
|
99
|
+
TransformerProtocol as ITransformerProtocol,
|
|
100
|
+
)
|
|
101
|
+
from ccproxy.core.middleware import (
|
|
102
|
+
BaseMiddleware,
|
|
103
|
+
CompositeMiddleware,
|
|
104
|
+
MiddlewareChain,
|
|
105
|
+
MiddlewareProtocol,
|
|
106
|
+
NextMiddleware,
|
|
107
|
+
)
|
|
108
|
+
from ccproxy.core.proxy import (
|
|
109
|
+
BaseProxy,
|
|
110
|
+
HTTPProxy,
|
|
111
|
+
ProxyProtocol,
|
|
112
|
+
WebSocketProxy,
|
|
113
|
+
)
|
|
114
|
+
from ccproxy.core.transformers import (
|
|
115
|
+
BaseTransformer,
|
|
116
|
+
ChainedTransformer,
|
|
117
|
+
RequestTransformer,
|
|
118
|
+
ResponseTransformer,
|
|
119
|
+
TransformerProtocol,
|
|
120
|
+
)
|
|
121
|
+
from ccproxy.core.types import (
|
|
122
|
+
MiddlewareConfig,
|
|
123
|
+
ProxyConfig,
|
|
124
|
+
ProxyMethod,
|
|
125
|
+
ProxyRequest,
|
|
126
|
+
ProxyResponse,
|
|
127
|
+
TransformContext,
|
|
128
|
+
)
|
|
129
|
+
from ccproxy.core.types import (
|
|
130
|
+
ProxyProtocol as ProxyProtocolEnum,
|
|
131
|
+
)
|
|
132
|
+
from ccproxy.core.validators import (
|
|
133
|
+
ValidationError,
|
|
134
|
+
validate_choice,
|
|
135
|
+
validate_dict,
|
|
136
|
+
validate_email,
|
|
137
|
+
validate_list,
|
|
138
|
+
validate_non_empty_string,
|
|
139
|
+
validate_path,
|
|
140
|
+
validate_port,
|
|
141
|
+
validate_range,
|
|
142
|
+
validate_timeout,
|
|
143
|
+
validate_url,
|
|
144
|
+
validate_uuid,
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
__all__ = [
|
|
149
|
+
# Proxy abstractions
|
|
150
|
+
"BaseProxy",
|
|
151
|
+
"HTTPProxy",
|
|
152
|
+
"WebSocketProxy",
|
|
153
|
+
"ProxyProtocol",
|
|
154
|
+
# HTTP client abstractions
|
|
155
|
+
"HTTPClient",
|
|
156
|
+
"BaseProxyClient",
|
|
157
|
+
"HTTPError",
|
|
158
|
+
"HTTPTimeoutError",
|
|
159
|
+
"HTTPConnectionError",
|
|
160
|
+
"HTTPXClient",
|
|
161
|
+
# Interface abstractions
|
|
162
|
+
"APIAdapter",
|
|
163
|
+
"MetricExporter",
|
|
164
|
+
"IRequestTransformer",
|
|
165
|
+
"IResponseTransformer",
|
|
166
|
+
"StreamTransformer",
|
|
167
|
+
"TokenStorage",
|
|
168
|
+
"ITransformerProtocol",
|
|
169
|
+
# Transformer abstractions
|
|
170
|
+
"BaseTransformer",
|
|
171
|
+
"RequestTransformer",
|
|
172
|
+
"ResponseTransformer",
|
|
173
|
+
"TransformerProtocol",
|
|
174
|
+
"ChainedTransformer",
|
|
175
|
+
# Middleware abstractions
|
|
176
|
+
"BaseMiddleware",
|
|
177
|
+
"MiddlewareChain",
|
|
178
|
+
"MiddlewareProtocol",
|
|
179
|
+
"CompositeMiddleware",
|
|
180
|
+
"NextMiddleware",
|
|
181
|
+
# Error types
|
|
182
|
+
"ProxyError",
|
|
183
|
+
"TransformationError",
|
|
184
|
+
"MiddlewareError",
|
|
185
|
+
"ProxyConnectionError",
|
|
186
|
+
"ProxyTimeoutError",
|
|
187
|
+
"ProxyAuthenticationError",
|
|
188
|
+
"ValidationError",
|
|
189
|
+
# Type definitions
|
|
190
|
+
"ProxyRequest",
|
|
191
|
+
"ProxyResponse",
|
|
192
|
+
"TransformContext",
|
|
193
|
+
"ProxyMethod",
|
|
194
|
+
"ProxyProtocolEnum",
|
|
195
|
+
"ProxyConfig",
|
|
196
|
+
"MiddlewareConfig",
|
|
197
|
+
# Async utilities
|
|
198
|
+
"async_cache_result",
|
|
199
|
+
"async_timer",
|
|
200
|
+
"gather_with_concurrency",
|
|
201
|
+
"get_package_dir",
|
|
202
|
+
"get_root_package_name",
|
|
203
|
+
"patched_typing",
|
|
204
|
+
"retry_async",
|
|
205
|
+
"run_in_executor",
|
|
206
|
+
"safe_await",
|
|
207
|
+
"wait_for_condition",
|
|
208
|
+
# Constants
|
|
209
|
+
"ANTHROPIC_API_BASE_PATH",
|
|
210
|
+
"AUTH_HEADER",
|
|
211
|
+
"CHAT_COMPLETIONS_ENDPOINT",
|
|
212
|
+
"CONFIG_FILE_NAMES",
|
|
213
|
+
"CONTENT_TYPE_HEADER",
|
|
214
|
+
"CONTENT_TYPE_JSON",
|
|
215
|
+
"CONTENT_TYPE_STREAM",
|
|
216
|
+
"CONTENT_TYPE_TEXT",
|
|
217
|
+
"DEFAULT_DOCKER_IMAGE",
|
|
218
|
+
"DEFAULT_DOCKER_TIMEOUT",
|
|
219
|
+
"DEFAULT_MAX_TOKENS",
|
|
220
|
+
"DEFAULT_MODEL",
|
|
221
|
+
"DEFAULT_RATE_LIMIT",
|
|
222
|
+
"DEFAULT_STREAM",
|
|
223
|
+
"DEFAULT_TEMPERATURE",
|
|
224
|
+
"DEFAULT_TIMEOUT",
|
|
225
|
+
"DEFAULT_TOP_P",
|
|
226
|
+
"EMAIL_PATTERN",
|
|
227
|
+
"ENV_PREFIX",
|
|
228
|
+
"ERROR_MSG_INTERNAL_ERROR",
|
|
229
|
+
"ERROR_MSG_INVALID_REQUEST",
|
|
230
|
+
"ERROR_MSG_INVALID_TOKEN",
|
|
231
|
+
"ERROR_MSG_MODEL_NOT_FOUND",
|
|
232
|
+
"ERROR_MSG_RATE_LIMIT_EXCEEDED",
|
|
233
|
+
"JSON_EXTENSIONS",
|
|
234
|
+
"LOG_LEVELS",
|
|
235
|
+
"MAX_MESSAGE_LENGTH",
|
|
236
|
+
"MAX_PROMPT_LENGTH",
|
|
237
|
+
"MAX_TOOL_CALLS",
|
|
238
|
+
"MESSAGES_ENDPOINT",
|
|
239
|
+
"MODELS_ENDPOINT",
|
|
240
|
+
"OPENAI_API_BASE_PATH",
|
|
241
|
+
"REQUEST_ID_HEADER",
|
|
242
|
+
"STATUS_BAD_GATEWAY",
|
|
243
|
+
"STATUS_BAD_REQUEST",
|
|
244
|
+
"STATUS_CREATED",
|
|
245
|
+
"STATUS_FORBIDDEN",
|
|
246
|
+
"STATUS_INTERNAL_ERROR",
|
|
247
|
+
"STATUS_NOT_FOUND",
|
|
248
|
+
"STATUS_OK",
|
|
249
|
+
"STATUS_RATE_LIMITED",
|
|
250
|
+
"STATUS_SERVICE_UNAVAILABLE",
|
|
251
|
+
"STATUS_UNAUTHORIZED",
|
|
252
|
+
"STREAM_EVENT_CONTENT_BLOCK_DELTA",
|
|
253
|
+
"STREAM_EVENT_CONTENT_BLOCK_START",
|
|
254
|
+
"STREAM_EVENT_CONTENT_BLOCK_STOP",
|
|
255
|
+
"STREAM_EVENT_MESSAGE_DELTA",
|
|
256
|
+
"STREAM_EVENT_MESSAGE_START",
|
|
257
|
+
"STREAM_EVENT_MESSAGE_STOP",
|
|
258
|
+
"TOML_EXTENSIONS",
|
|
259
|
+
"URL_PATTERN",
|
|
260
|
+
"UUID_PATTERN",
|
|
261
|
+
"YAML_EXTENSIONS",
|
|
262
|
+
# Validators
|
|
263
|
+
"validate_choice",
|
|
264
|
+
"validate_dict",
|
|
265
|
+
"validate_email",
|
|
266
|
+
"validate_list",
|
|
267
|
+
"validate_non_empty_string",
|
|
268
|
+
"validate_path",
|
|
269
|
+
"validate_port",
|
|
270
|
+
"validate_range",
|
|
271
|
+
"validate_timeout",
|
|
272
|
+
"validate_url",
|
|
273
|
+
"validate_uuid",
|
|
274
|
+
]
|