ccproxy-api 0.1.3__py3-none-any.whl → 0.1.5__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/_version.py +2 -2
- ccproxy/adapters/openai/adapter.py +1 -1
- ccproxy/adapters/openai/streaming.py +1 -0
- ccproxy/api/app.py +134 -224
- ccproxy/api/dependencies.py +22 -2
- ccproxy/api/middleware/errors.py +27 -3
- ccproxy/api/middleware/logging.py +4 -0
- ccproxy/api/responses.py +6 -1
- ccproxy/api/routes/claude.py +222 -17
- ccproxy/api/routes/proxy.py +25 -6
- ccproxy/api/services/permission_service.py +2 -2
- ccproxy/claude_sdk/__init__.py +4 -8
- ccproxy/claude_sdk/client.py +661 -131
- ccproxy/claude_sdk/exceptions.py +16 -0
- ccproxy/claude_sdk/manager.py +219 -0
- ccproxy/claude_sdk/message_queue.py +342 -0
- ccproxy/claude_sdk/options.py +5 -0
- ccproxy/claude_sdk/session_client.py +546 -0
- ccproxy/claude_sdk/session_pool.py +550 -0
- ccproxy/claude_sdk/stream_handle.py +538 -0
- ccproxy/claude_sdk/stream_worker.py +392 -0
- ccproxy/claude_sdk/streaming.py +53 -11
- ccproxy/cli/commands/serve.py +96 -0
- ccproxy/cli/options/claude_options.py +47 -0
- ccproxy/config/__init__.py +0 -3
- ccproxy/config/claude.py +171 -23
- ccproxy/config/discovery.py +10 -1
- ccproxy/config/scheduler.py +4 -4
- ccproxy/config/settings.py +19 -1
- ccproxy/core/http_transformers.py +305 -73
- ccproxy/core/logging.py +108 -12
- ccproxy/core/transformers.py +5 -0
- ccproxy/models/claude_sdk.py +57 -0
- ccproxy/models/detection.py +126 -0
- ccproxy/observability/access_logger.py +72 -14
- ccproxy/observability/metrics.py +151 -0
- ccproxy/observability/storage/duckdb_simple.py +12 -0
- ccproxy/observability/storage/models.py +16 -0
- ccproxy/observability/streaming_response.py +107 -0
- ccproxy/scheduler/manager.py +31 -6
- ccproxy/scheduler/tasks.py +122 -0
- ccproxy/services/claude_detection_service.py +269 -0
- ccproxy/services/claude_sdk_service.py +334 -131
- ccproxy/services/proxy_service.py +91 -200
- ccproxy/utils/__init__.py +9 -1
- ccproxy/utils/disconnection_monitor.py +83 -0
- ccproxy/utils/id_generator.py +12 -0
- ccproxy/utils/startup_helpers.py +408 -0
- {ccproxy_api-0.1.3.dist-info → ccproxy_api-0.1.5.dist-info}/METADATA +29 -2
- {ccproxy_api-0.1.3.dist-info → ccproxy_api-0.1.5.dist-info}/RECORD +53 -41
- ccproxy/config/loader.py +0 -105
- {ccproxy_api-0.1.3.dist-info → ccproxy_api-0.1.5.dist-info}/WHEEL +0 -0
- {ccproxy_api-0.1.3.dist-info → ccproxy_api-0.1.5.dist-info}/entry_points.txt +0 -0
- {ccproxy_api-0.1.3.dist-info → ccproxy_api-0.1.5.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
"""Startup utility functions for application lifecycle management.
|
|
2
|
+
|
|
3
|
+
This module contains simple utility functions to extract and organize
|
|
4
|
+
the complex startup logic from the main lifespan function, following
|
|
5
|
+
the KISS principle and avoiding overengineering.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from datetime import UTC, datetime
|
|
11
|
+
from typing import TYPE_CHECKING
|
|
12
|
+
|
|
13
|
+
import structlog
|
|
14
|
+
from fastapi import FastAPI
|
|
15
|
+
|
|
16
|
+
from ccproxy.auth.credentials_adapter import CredentialsAuthManager
|
|
17
|
+
from ccproxy.auth.exceptions import CredentialsNotFoundError
|
|
18
|
+
from ccproxy.observability import get_metrics
|
|
19
|
+
|
|
20
|
+
# Note: get_claude_cli_info is imported locally to avoid circular imports
|
|
21
|
+
from ccproxy.observability.storage.duckdb_simple import SimpleDuckDBStorage
|
|
22
|
+
from ccproxy.scheduler.errors import SchedulerError
|
|
23
|
+
from ccproxy.scheduler.manager import start_scheduler, stop_scheduler
|
|
24
|
+
from ccproxy.services.claude_detection_service import ClaudeDetectionService
|
|
25
|
+
from ccproxy.services.claude_sdk_service import ClaudeSDKService
|
|
26
|
+
from ccproxy.services.credentials.manager import CredentialsManager
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
# Note: get_permission_service is imported locally to avoid circular imports
|
|
30
|
+
|
|
31
|
+
if TYPE_CHECKING:
|
|
32
|
+
from ccproxy.config.settings import Settings
|
|
33
|
+
|
|
34
|
+
logger = structlog.get_logger(__name__)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
async def validate_authentication_startup(app: FastAPI, settings: Settings) -> None:
|
|
38
|
+
"""Validate authentication credentials at startup.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
app: FastAPI application instance
|
|
42
|
+
settings: Application settings
|
|
43
|
+
"""
|
|
44
|
+
try:
|
|
45
|
+
credentials_manager = CredentialsManager()
|
|
46
|
+
validation = await credentials_manager.validate()
|
|
47
|
+
|
|
48
|
+
if validation.valid and not validation.expired:
|
|
49
|
+
credentials = validation.credentials
|
|
50
|
+
oauth_token = credentials.claude_ai_oauth if credentials else None
|
|
51
|
+
|
|
52
|
+
if oauth_token and oauth_token.expires_at_datetime:
|
|
53
|
+
hours_until_expiry = int(
|
|
54
|
+
(
|
|
55
|
+
oauth_token.expires_at_datetime - datetime.now(UTC)
|
|
56
|
+
).total_seconds()
|
|
57
|
+
/ 3600
|
|
58
|
+
)
|
|
59
|
+
logger.debug(
|
|
60
|
+
"auth_token_valid",
|
|
61
|
+
expires_in_hours=hours_until_expiry,
|
|
62
|
+
subscription_type=oauth_token.subscription_type,
|
|
63
|
+
credentials_path=str(validation.path) if validation.path else None,
|
|
64
|
+
)
|
|
65
|
+
else:
|
|
66
|
+
logger.debug("auth_token_valid", credentials_path=str(validation.path))
|
|
67
|
+
elif validation.expired:
|
|
68
|
+
logger.warning(
|
|
69
|
+
"auth_token_expired",
|
|
70
|
+
message="Authentication token has expired. Please run 'ccproxy auth login' to refresh.",
|
|
71
|
+
credentials_path=str(validation.path) if validation.path else None,
|
|
72
|
+
)
|
|
73
|
+
else:
|
|
74
|
+
logger.warning(
|
|
75
|
+
"auth_token_invalid",
|
|
76
|
+
message="Authentication token is invalid. Please run 'ccproxy auth login'.",
|
|
77
|
+
credentials_path=str(validation.path) if validation.path else None,
|
|
78
|
+
)
|
|
79
|
+
except CredentialsNotFoundError:
|
|
80
|
+
logger.warning(
|
|
81
|
+
"auth_token_not_found",
|
|
82
|
+
message="No authentication credentials found. Please run 'ccproxy auth login' to authenticate.",
|
|
83
|
+
searched_paths=settings.auth.storage.storage_paths,
|
|
84
|
+
)
|
|
85
|
+
except Exception as e:
|
|
86
|
+
logger.error(
|
|
87
|
+
"auth_token_validation_error",
|
|
88
|
+
error=str(e),
|
|
89
|
+
message="Failed to validate authentication token. The server will continue without authentication.",
|
|
90
|
+
exc_info=True,
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
async def check_claude_cli_startup(app: FastAPI, settings: Settings) -> None:
|
|
95
|
+
"""Check Claude CLI availability at startup.
|
|
96
|
+
|
|
97
|
+
Args:
|
|
98
|
+
app: FastAPI application instance
|
|
99
|
+
settings: Application settings
|
|
100
|
+
"""
|
|
101
|
+
try:
|
|
102
|
+
from ccproxy.api.routes.health import get_claude_cli_info
|
|
103
|
+
|
|
104
|
+
claude_info = await get_claude_cli_info()
|
|
105
|
+
|
|
106
|
+
if claude_info.status == "available":
|
|
107
|
+
logger.info(
|
|
108
|
+
"claude_cli_available",
|
|
109
|
+
status=claude_info.status,
|
|
110
|
+
version=claude_info.version,
|
|
111
|
+
binary_path=claude_info.binary_path,
|
|
112
|
+
)
|
|
113
|
+
else:
|
|
114
|
+
logger.warning(
|
|
115
|
+
"claude_cli_unavailable",
|
|
116
|
+
status=claude_info.status,
|
|
117
|
+
error=claude_info.error,
|
|
118
|
+
binary_path=claude_info.binary_path,
|
|
119
|
+
message=f"Claude CLI status: {claude_info.status}",
|
|
120
|
+
)
|
|
121
|
+
except Exception as e:
|
|
122
|
+
logger.error(
|
|
123
|
+
"claude_cli_check_failed",
|
|
124
|
+
error=str(e),
|
|
125
|
+
message="Failed to check Claude CLI status during startup",
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
async def initialize_log_storage_startup(app: FastAPI, settings: Settings) -> None:
|
|
130
|
+
"""Initialize log storage if needed and backend is DuckDB.
|
|
131
|
+
|
|
132
|
+
Args:
|
|
133
|
+
app: FastAPI application instance
|
|
134
|
+
settings: Application settings
|
|
135
|
+
"""
|
|
136
|
+
if (
|
|
137
|
+
settings.observability.needs_storage_backend
|
|
138
|
+
and settings.observability.log_storage_backend == "duckdb"
|
|
139
|
+
):
|
|
140
|
+
try:
|
|
141
|
+
storage = SimpleDuckDBStorage(
|
|
142
|
+
database_path=settings.observability.duckdb_path
|
|
143
|
+
)
|
|
144
|
+
await storage.initialize()
|
|
145
|
+
app.state.log_storage = storage
|
|
146
|
+
logger.debug(
|
|
147
|
+
"log_storage_initialized",
|
|
148
|
+
backend="duckdb",
|
|
149
|
+
path=str(settings.observability.duckdb_path),
|
|
150
|
+
collection_enabled=settings.observability.logs_collection_enabled,
|
|
151
|
+
)
|
|
152
|
+
except Exception as e:
|
|
153
|
+
logger.error("log_storage_initialization_failed", error=str(e))
|
|
154
|
+
# Continue without log storage (graceful degradation)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
async def initialize_log_storage_shutdown(app: FastAPI) -> None:
|
|
158
|
+
"""Close log storage if initialized.
|
|
159
|
+
|
|
160
|
+
Args:
|
|
161
|
+
app: FastAPI application instance
|
|
162
|
+
"""
|
|
163
|
+
if hasattr(app.state, "log_storage") and app.state.log_storage:
|
|
164
|
+
try:
|
|
165
|
+
await app.state.log_storage.close()
|
|
166
|
+
logger.debug("log_storage_closed")
|
|
167
|
+
except Exception as e:
|
|
168
|
+
logger.error("log_storage_close_failed", error=str(e))
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
async def setup_scheduler_startup(app: FastAPI, settings: Settings) -> None:
|
|
172
|
+
"""Start scheduler system and configure tasks.
|
|
173
|
+
|
|
174
|
+
Args:
|
|
175
|
+
app: FastAPI application instance
|
|
176
|
+
settings: Application settings
|
|
177
|
+
"""
|
|
178
|
+
try:
|
|
179
|
+
scheduler = await start_scheduler(settings)
|
|
180
|
+
app.state.scheduler = scheduler
|
|
181
|
+
logger.debug("scheduler_initialized")
|
|
182
|
+
|
|
183
|
+
# Add session pool stats task if session manager is available
|
|
184
|
+
if (
|
|
185
|
+
scheduler
|
|
186
|
+
and hasattr(app.state, "session_manager")
|
|
187
|
+
and app.state.session_manager
|
|
188
|
+
):
|
|
189
|
+
try:
|
|
190
|
+
# Add session pool stats task that runs every minute
|
|
191
|
+
await scheduler.add_task(
|
|
192
|
+
task_name="session_pool_stats",
|
|
193
|
+
task_type="pool_stats",
|
|
194
|
+
interval_seconds=60, # Every minute
|
|
195
|
+
enabled=True,
|
|
196
|
+
pool_manager=app.state.session_manager,
|
|
197
|
+
)
|
|
198
|
+
logger.debug("session_pool_stats_task_added", interval_seconds=60)
|
|
199
|
+
except Exception as e:
|
|
200
|
+
logger.error(
|
|
201
|
+
"session_pool_stats_task_add_failed",
|
|
202
|
+
error=str(e),
|
|
203
|
+
error_type=type(e).__name__,
|
|
204
|
+
)
|
|
205
|
+
except SchedulerError as e:
|
|
206
|
+
logger.error("scheduler_initialization_failed", error=str(e))
|
|
207
|
+
# Continue startup even if scheduler fails (graceful degradation)
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
async def setup_scheduler_shutdown(app: FastAPI) -> None:
|
|
211
|
+
"""Stop scheduler system.
|
|
212
|
+
|
|
213
|
+
Args:
|
|
214
|
+
app: FastAPI application instance
|
|
215
|
+
"""
|
|
216
|
+
try:
|
|
217
|
+
scheduler = getattr(app.state, "scheduler", None)
|
|
218
|
+
await stop_scheduler(scheduler)
|
|
219
|
+
logger.debug("scheduler_stopped_lifespan")
|
|
220
|
+
except SchedulerError as e:
|
|
221
|
+
logger.error("scheduler_stop_failed", error=str(e))
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
async def setup_session_manager_shutdown(app: FastAPI) -> None:
|
|
225
|
+
"""Shutdown Claude SDK session manager if it was created.
|
|
226
|
+
|
|
227
|
+
Args:
|
|
228
|
+
app: FastAPI application instance
|
|
229
|
+
"""
|
|
230
|
+
if hasattr(app.state, "session_manager") and app.state.session_manager:
|
|
231
|
+
try:
|
|
232
|
+
await app.state.session_manager.shutdown()
|
|
233
|
+
logger.debug("claude_sdk_session_manager_shutdown")
|
|
234
|
+
except Exception as e:
|
|
235
|
+
logger.error("claude_sdk_session_manager_shutdown_failed", error=str(e))
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
async def initialize_claude_detection_startup(app: FastAPI, settings: Settings) -> None:
|
|
239
|
+
"""Initialize Claude detection service.
|
|
240
|
+
|
|
241
|
+
Args:
|
|
242
|
+
app: FastAPI application instance
|
|
243
|
+
settings: Application settings
|
|
244
|
+
"""
|
|
245
|
+
try:
|
|
246
|
+
logger.debug("initializing_claude_detection")
|
|
247
|
+
detection_service = ClaudeDetectionService(settings)
|
|
248
|
+
claude_data = await detection_service.initialize_detection()
|
|
249
|
+
app.state.claude_detection_data = claude_data
|
|
250
|
+
app.state.claude_detection_service = detection_service
|
|
251
|
+
logger.debug(
|
|
252
|
+
"claude_detection_completed",
|
|
253
|
+
version=claude_data.claude_version,
|
|
254
|
+
cached_at=claude_data.cached_at.isoformat(),
|
|
255
|
+
)
|
|
256
|
+
except Exception as e:
|
|
257
|
+
logger.error("claude_detection_startup_failed", error=str(e))
|
|
258
|
+
# Continue startup with fallback - detection service will provide fallback data
|
|
259
|
+
detection_service = ClaudeDetectionService(settings)
|
|
260
|
+
app.state.claude_detection_data = detection_service._get_fallback_data()
|
|
261
|
+
app.state.claude_detection_service = detection_service
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
async def initialize_claude_sdk_startup(app: FastAPI, settings: Settings) -> None:
|
|
265
|
+
"""Initialize ClaudeSDKService and store in app state.
|
|
266
|
+
|
|
267
|
+
Args:
|
|
268
|
+
app: FastAPI application instance
|
|
269
|
+
settings: Application settings
|
|
270
|
+
"""
|
|
271
|
+
try:
|
|
272
|
+
# Create auth manager with settings
|
|
273
|
+
auth_manager = CredentialsAuthManager()
|
|
274
|
+
|
|
275
|
+
# Get global metrics instance
|
|
276
|
+
metrics = get_metrics()
|
|
277
|
+
|
|
278
|
+
# Check if session pool should be enabled from settings configuration
|
|
279
|
+
use_session_pool = settings.claude.sdk_session_pool.enabled
|
|
280
|
+
|
|
281
|
+
# Initialize session manager if session pool is enabled
|
|
282
|
+
session_manager = None
|
|
283
|
+
if use_session_pool:
|
|
284
|
+
from ccproxy.claude_sdk.manager import SessionManager
|
|
285
|
+
|
|
286
|
+
# Create SessionManager with dependency injection
|
|
287
|
+
session_manager = SessionManager(
|
|
288
|
+
settings=settings, metrics_factory=lambda: metrics
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
# Start the session manager (initializes session pool if enabled)
|
|
292
|
+
await session_manager.start()
|
|
293
|
+
|
|
294
|
+
# Create ClaudeSDKService instance
|
|
295
|
+
claude_service = ClaudeSDKService(
|
|
296
|
+
auth_manager=auth_manager,
|
|
297
|
+
metrics=metrics,
|
|
298
|
+
settings=settings,
|
|
299
|
+
session_manager=session_manager,
|
|
300
|
+
)
|
|
301
|
+
|
|
302
|
+
# Store in app state for reuse in dependencies
|
|
303
|
+
app.state.claude_service = claude_service
|
|
304
|
+
app.state.session_manager = (
|
|
305
|
+
session_manager # Store session_manager for shutdown
|
|
306
|
+
)
|
|
307
|
+
logger.debug("claude_sdk_service_initialized")
|
|
308
|
+
except Exception as e:
|
|
309
|
+
logger.error("claude_sdk_service_initialization_failed", error=str(e))
|
|
310
|
+
# Continue startup even if ClaudeSDKService fails (graceful degradation)
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
async def initialize_permission_service_startup(
|
|
314
|
+
app: FastAPI, settings: Settings
|
|
315
|
+
) -> None:
|
|
316
|
+
"""Initialize permission service (conditional on builtin_permissions).
|
|
317
|
+
|
|
318
|
+
Args:
|
|
319
|
+
app: FastAPI application instance
|
|
320
|
+
settings: Application settings
|
|
321
|
+
"""
|
|
322
|
+
if settings.claude.builtin_permissions:
|
|
323
|
+
try:
|
|
324
|
+
from ccproxy.api.services.permission_service import get_permission_service
|
|
325
|
+
|
|
326
|
+
permission_service = get_permission_service()
|
|
327
|
+
|
|
328
|
+
# Only connect terminal handler if not using external handler
|
|
329
|
+
if settings.server.use_terminal_permission_handler:
|
|
330
|
+
# terminal_handler = TerminalPermissionHandler()
|
|
331
|
+
|
|
332
|
+
# TODO: Terminal handler should subscribe to events from the service
|
|
333
|
+
# instead of trying to set a handler directly
|
|
334
|
+
# The service uses an event-based architecture, not direct handlers
|
|
335
|
+
|
|
336
|
+
# logger.info(
|
|
337
|
+
# "permission_handler_configured",
|
|
338
|
+
# handler_type="terminal",
|
|
339
|
+
# message="Connected terminal handler to permission service",
|
|
340
|
+
# )
|
|
341
|
+
# app.state.terminal_handler = terminal_handler
|
|
342
|
+
pass
|
|
343
|
+
else:
|
|
344
|
+
logger.debug(
|
|
345
|
+
"permission_handler_configured",
|
|
346
|
+
handler_type="external_sse",
|
|
347
|
+
message="Terminal permission handler disabled - use 'ccproxy permission-handler connect' to handle permissions",
|
|
348
|
+
)
|
|
349
|
+
logger.warning(
|
|
350
|
+
"permission_handler_required",
|
|
351
|
+
message="Start external handler with: ccproxy permission-handler connect",
|
|
352
|
+
)
|
|
353
|
+
|
|
354
|
+
# Start the permission service
|
|
355
|
+
await permission_service.start()
|
|
356
|
+
|
|
357
|
+
# Store references in app state
|
|
358
|
+
app.state.permission_service = permission_service
|
|
359
|
+
|
|
360
|
+
logger.debug(
|
|
361
|
+
"permission_service_initialized",
|
|
362
|
+
timeout_seconds=permission_service._timeout_seconds,
|
|
363
|
+
terminal_handler_enabled=settings.server.use_terminal_permission_handler,
|
|
364
|
+
builtin_permissions_enabled=True,
|
|
365
|
+
)
|
|
366
|
+
except Exception as e:
|
|
367
|
+
logger.error("permission_service_initialization_failed", error=str(e))
|
|
368
|
+
# Continue without permission service (API will work but without prompts)
|
|
369
|
+
else:
|
|
370
|
+
logger.debug(
|
|
371
|
+
"permission_service_skipped",
|
|
372
|
+
builtin_permissions_enabled=False,
|
|
373
|
+
message="Built-in permission handling disabled - users can configure custom MCP servers and permission tools",
|
|
374
|
+
)
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
async def setup_permission_service_shutdown(app: FastAPI, settings: Settings) -> None:
|
|
378
|
+
"""Stop permission service (if it was initialized).
|
|
379
|
+
|
|
380
|
+
Args:
|
|
381
|
+
app: FastAPI application instance
|
|
382
|
+
settings: Application settings
|
|
383
|
+
"""
|
|
384
|
+
if (
|
|
385
|
+
hasattr(app.state, "permission_service")
|
|
386
|
+
and app.state.permission_service
|
|
387
|
+
and settings.claude.builtin_permissions
|
|
388
|
+
):
|
|
389
|
+
try:
|
|
390
|
+
await app.state.permission_service.stop()
|
|
391
|
+
logger.debug("permission_service_stopped")
|
|
392
|
+
except Exception as e:
|
|
393
|
+
logger.error("permission_service_stop_failed", error=str(e))
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
async def flush_streaming_batches_shutdown(app: FastAPI) -> None:
|
|
397
|
+
"""Flush any remaining streaming log batches.
|
|
398
|
+
|
|
399
|
+
Args:
|
|
400
|
+
app: FastAPI application instance
|
|
401
|
+
"""
|
|
402
|
+
try:
|
|
403
|
+
from ccproxy.utils.simple_request_logger import flush_all_streaming_batches
|
|
404
|
+
|
|
405
|
+
await flush_all_streaming_batches()
|
|
406
|
+
logger.debug("streaming_batches_flushed")
|
|
407
|
+
except Exception as e:
|
|
408
|
+
logger.error("streaming_batches_flush_failed", error=str(e))
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ccproxy-api
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.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
7
|
Requires-Dist: aiofiles>=24.1.0
|
|
8
8
|
Requires-Dist: aiosqlite>=0.21.0
|
|
9
|
-
Requires-Dist: claude-code-sdk>=0.0.
|
|
9
|
+
Requires-Dist: claude-code-sdk>=0.0.19
|
|
10
10
|
Requires-Dist: duckdb-engine>=0.17.0
|
|
11
11
|
Requires-Dist: duckdb>=1.1.0
|
|
12
12
|
Requires-Dist: fastapi-mcp
|
|
@@ -182,6 +182,33 @@ CLAUDE__SDK_MESSAGE_MODE=formatted ccproxy
|
|
|
182
182
|
CLAUDE__PRETTY_FORMAT=false ccproxy
|
|
183
183
|
```
|
|
184
184
|
|
|
185
|
+
## Claude SDK Pool Mode
|
|
186
|
+
|
|
187
|
+
CCProxy supports connection pooling for Claude Code SDK clients to improve request performance by maintaining a pool of pre-initialized Claude instances.
|
|
188
|
+
|
|
189
|
+
### Benefits
|
|
190
|
+
- **Reduced Latency**: Eliminates Claude Code startup overhead on each request
|
|
191
|
+
- **Improved Performance**: Reuses established connections for faster response times
|
|
192
|
+
- **Resource Efficiency**: Maintains a configurable pool size to balance performance and resource usage
|
|
193
|
+
|
|
194
|
+
### Usage
|
|
195
|
+
Pool mode is disabled by default and can be enabled using the CLI flag:
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
# Enable pool mode with default settings
|
|
199
|
+
ccproxy --sdk-enable-pool
|
|
200
|
+
|
|
201
|
+
# Configure pool size (default: 3)
|
|
202
|
+
ccproxy --sdk-enable-pool --sdk-pool-size 5
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Limitations
|
|
206
|
+
- **No Dynamic Options**: Pool instances cannot change Claude options (max_tokens, model, etc.) after initialization
|
|
207
|
+
- **Shared Configuration**: All requests using the pool must use identical Claude configuration
|
|
208
|
+
- **Memory Usage**: Each pool instance consumes additional memory
|
|
209
|
+
|
|
210
|
+
Pool mode is most effective for high-frequency requests with consistent configuration requirements.
|
|
211
|
+
|
|
185
212
|
## Using with Aider
|
|
186
213
|
|
|
187
214
|
CCProxy works seamlessly with Aider and other AI coding assistants:
|
|
@@ -1,34 +1,34 @@
|
|
|
1
1
|
ccproxy/__init__.py,sha256=VrtzUTUA8MwpYqFJAiwKLPxRdMRc7UOzFi2VB_1W9qw,62
|
|
2
2
|
ccproxy/__main__.py,sha256=kcejcfzAaMnFiSxEiVtNl-_TwynpntkupRxqG5XR15s,116
|
|
3
|
-
ccproxy/_version.py,sha256=
|
|
3
|
+
ccproxy/_version.py,sha256=Y4jy4bEMmwl_qNPCmiMFnlQ2ofMoqyG37hp8uwI3m10,511
|
|
4
4
|
ccproxy/adapters/__init__.py,sha256=CMr5MPIFigfazoXfhyD2eLqBrutzaSzBaEi8u2i9xJQ,206
|
|
5
5
|
ccproxy/adapters/base.py,sha256=aufx8ho9LhF0kmTsCvw1a9K3lk5YyYymJV8h_wt5TpU,2191
|
|
6
6
|
ccproxy/adapters/openai/__init__.py,sha256=CEOtyALpgaq6XT6upZKt0u_ilvnXIyH9K2hFXZJ-hOY,1063
|
|
7
|
-
ccproxy/adapters/openai/adapter.py,sha256=
|
|
7
|
+
ccproxy/adapters/openai/adapter.py,sha256=8g9jBtEET_NEZKt27prw_Go9WMS_BJUoxyvhoMk74-g,37960
|
|
8
8
|
ccproxy/adapters/openai/models.py,sha256=tg5NLFmTAOjLd2-gjqRQPU3IkL9ATftXv4ZugGw-rwc,11645
|
|
9
|
-
ccproxy/adapters/openai/streaming.py,sha256
|
|
9
|
+
ccproxy/adapters/openai/streaming.py,sha256=-nhKVPqCfAlV8PDi5-q3dVyslCpAu5DHh0BCrBfb9GU,23219
|
|
10
10
|
ccproxy/api/__init__.py,sha256=_u4wpzvN4Y0qS4CTaGp8nD8ZopB0HeFxnIIw9GYjvvk,527
|
|
11
|
-
ccproxy/api/app.py,sha256=
|
|
12
|
-
ccproxy/api/dependencies.py,sha256
|
|
13
|
-
ccproxy/api/responses.py,sha256=
|
|
11
|
+
ccproxy/api/app.py,sha256=VgRC5kM8ztfhPhZ86MZre-7olQkmvtp6m4h6Ov3Bj9g,11853
|
|
12
|
+
ccproxy/api/dependencies.py,sha256=-oGT8XSXpyyxenUMXTs5Ap3wJRbda4mfDagDW01pkoE,6989
|
|
13
|
+
ccproxy/api/responses.py,sha256=97TUQ8KF_eKLBRWgAnziGZBjBfJtY13cjgM_o0k_lDc,3062
|
|
14
14
|
ccproxy/api/middleware/__init__.py,sha256=S887PXY40Tnb0IFGei4Sgs7sygkcoT0IEOciOO7IDBc,284
|
|
15
15
|
ccproxy/api/middleware/auth.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
16
16
|
ccproxy/api/middleware/cors.py,sha256=u8bnWmBXRG9J2etbQdNsQOTIQY6PFWawk2Oa0Ei1x3s,1666
|
|
17
|
-
ccproxy/api/middleware/errors.py,sha256=
|
|
17
|
+
ccproxy/api/middleware/errors.py,sha256=YMfg5ovad7BMAiGK-66BCVacLveRX5ylJIRr1BFf3lE,22939
|
|
18
18
|
ccproxy/api/middleware/headers.py,sha256=zGhF3F11TKeb3zY5qzblU3Sdwx1MSlqm2QSOqtVfpoY,1775
|
|
19
|
-
ccproxy/api/middleware/logging.py,sha256=
|
|
19
|
+
ccproxy/api/middleware/logging.py,sha256=fGHacI_vRtQs9LpKpCebVUpo7bSC6qy4hbqftmLe_Uk,7353
|
|
20
20
|
ccproxy/api/middleware/request_content_logging.py,sha256=aIH1G9kjNr4-O5IFoisI9fO93rPePVWBQJM4wX1NCnY,10333
|
|
21
21
|
ccproxy/api/middleware/request_id.py,sha256=OOZh63FYP_JY3olZNzgzVdPFZUJFT_KerZxYMxsPmyQ,2538
|
|
22
22
|
ccproxy/api/middleware/server_header.py,sha256=9A3c7L12CFkQftMOZwB5JzqocGWymuV8AT_u_Y2s9RA,2329
|
|
23
23
|
ccproxy/api/routes/__init__.py,sha256=xXoslArg915ZTmN2ITQ-i3iO7fu8ZkQAMrSgC41U5oA,664
|
|
24
|
-
ccproxy/api/routes/claude.py,sha256=
|
|
24
|
+
ccproxy/api/routes/claude.py,sha256=lERvCRFiHfhfQC6uYaUSRwplSRvUbn3of0tACYib4x0,15079
|
|
25
25
|
ccproxy/api/routes/health.py,sha256=6eIoZ5oCBG8npDXqTnAU-rLWgO53b4E6SA0l12bAkjA,18932
|
|
26
26
|
ccproxy/api/routes/mcp.py,sha256=-EVGid0uNOWeXP4w8F_hKUp1odkNnFXPHPmaOGC0UzQ,5389
|
|
27
27
|
ccproxy/api/routes/metrics.py,sha256=MHG2nEGu3amrU6zJCuH2RktM8kg2EFxu4xNOFCzXMn4,40813
|
|
28
28
|
ccproxy/api/routes/permissions.py,sha256=dvbWORmmAce7VZWlZPvchTCO9F6fauavmSbs8hUltKE,6231
|
|
29
|
-
ccproxy/api/routes/proxy.py,sha256=
|
|
29
|
+
ccproxy/api/routes/proxy.py,sha256=flx4fyhYFsZvImLbwXy2qSEVVnlOA8xc0uR0T3-hUBI,8364
|
|
30
30
|
ccproxy/api/services/__init__.py,sha256=_n4k1Ciao8BEbiMBSldq82nbs7N8qXu_1TcBwWLV8bE,167
|
|
31
|
-
ccproxy/api/services/permission_service.py,sha256=
|
|
31
|
+
ccproxy/api/services/permission_service.py,sha256=mG6HGRQ5sly9rfA8ii601Rx5R-MunVAjOy3ky8Jqsoc,12024
|
|
32
32
|
ccproxy/api/ui/__init__.py,sha256=oEgfWr8pgSO7uHYQBchJ2QspFrFsqTCO8mLPlfhHTfU,147
|
|
33
33
|
ccproxy/api/ui/permission_handler_protocol.py,sha256=_jZAQ1KN5dK1Z28jqaW90Ggt8usVTR1P7pEKPWGN9SY,972
|
|
34
34
|
ccproxy/api/ui/terminal_permission_handler.py,sha256=GuD_RyQCiuxJtFJI-SKsWPvw1brz1_IGz31YjLVQ9js,20195
|
|
@@ -48,19 +48,26 @@ ccproxy/auth/storage/__init__.py,sha256=5thfvXhc8HGJblQWMiG6ZPl594RpbTGdAgyAlpAe
|
|
|
48
48
|
ccproxy/auth/storage/base.py,sha256=Gw20tabOKTwey6YrOm09Bxu-MYJuMIrQULLJT6RQ07E,1357
|
|
49
49
|
ccproxy/auth/storage/json_file.py,sha256=iZBFCJ5EsZeFtlT7ORTXcEdAvMADIaDTXUPEBSjMcr0,5027
|
|
50
50
|
ccproxy/auth/storage/keyring.py,sha256=qg4q-O-Y6D7y4HQfgg5g9bhUpuD9DAec9npWne0VLwg,5950
|
|
51
|
-
ccproxy/claude_sdk/__init__.py,sha256=
|
|
52
|
-
ccproxy/claude_sdk/client.py,sha256=
|
|
51
|
+
ccproxy/claude_sdk/__init__.py,sha256=b794sieTPU1HEH_CmtqFK1be_p-bMUopi4v8gxRET9M,482
|
|
52
|
+
ccproxy/claude_sdk/client.py,sha256=YPgi4Uql8YW_fKFA6TAAmy5aDA-T0F5T_HJf7o9bbLY,29799
|
|
53
53
|
ccproxy/claude_sdk/converter.py,sha256=GeU7AzbzK1ltaiUEr60mG4VYaSup95Z6OxVSG9Pu0PY,19035
|
|
54
|
-
ccproxy/claude_sdk/
|
|
54
|
+
ccproxy/claude_sdk/exceptions.py,sha256=LYUmy4K4TnrOixINScswc-Xg31gZJbbFimZgw9hIfy4,428
|
|
55
|
+
ccproxy/claude_sdk/manager.py,sha256=UuUhFNSF6UTaonmllHzwORwrXjcv1k_DwkHmsYJUhqY,7319
|
|
56
|
+
ccproxy/claude_sdk/message_queue.py,sha256=V2BU2Wdsdfb-TyfvOzYMszeEcdcBmVkiqB52IjS_oM8,11136
|
|
57
|
+
ccproxy/claude_sdk/options.py,sha256=uM1PdM4Uypb5HagvLGR0l4URbcxSQMcMd1pY1P2_uHM,7079
|
|
55
58
|
ccproxy/claude_sdk/parser.py,sha256=1LcZOTkaKLSxZO_iVIvpZq44vUjApvMIA8Wlv61V6Jo,7193
|
|
56
|
-
ccproxy/claude_sdk/
|
|
59
|
+
ccproxy/claude_sdk/session_client.py,sha256=ipKvWyFx7nCI4n1VHbCsqbSjo5HdMC1P2lrX8fkTy8g,20052
|
|
60
|
+
ccproxy/claude_sdk/session_pool.py,sha256=BX0I4TdtgfVDEJozjmoSQTls24s-3KfFNTSSAgmA9LM,23993
|
|
61
|
+
ccproxy/claude_sdk/stream_handle.py,sha256=bu2WjWZmhRFyzhjH4UeYe9NmFeAonR9zBfyDirJJ1XE,20576
|
|
62
|
+
ccproxy/claude_sdk/stream_worker.py,sha256=CjyzNDVIFvoPLMXfmF6juJlxRYpiRRBM-IS3oQuEPpc,13429
|
|
63
|
+
ccproxy/claude_sdk/streaming.py,sha256=FjyLKS1fbBLf3hXtBhwyZzmSvWvOMxOZqrIxQDul_ik,14765
|
|
57
64
|
ccproxy/cli/__init__.py,sha256=_vISKEqzAsAYrTZ-j9ScxTUtFZp3RVRbIvGpCcu--SU,262
|
|
58
65
|
ccproxy/cli/helpers.py,sha256=LHGh5ZSywPUY61XVaSD5mx2eaIF4bi8hzbdMCJ0YRrQ,3814
|
|
59
66
|
ccproxy/cli/main.py,sha256=QLdSbSm3PjvwluL6WO7kpe8S7qrgsw2VjMR84aZ2fsg,2452
|
|
60
67
|
ccproxy/cli/commands/__init__.py,sha256=eWugiC37ualVtsTazu7GBCV7kZ12xkAnTUztjV7kVao,200
|
|
61
68
|
ccproxy/cli/commands/auth.py,sha256=crpPeJ5Xs5I-xl5BC27HUJxlTHgcjL7GeMH0e31DXQc,20716
|
|
62
69
|
ccproxy/cli/commands/permission_handler.py,sha256=rdPxXCZ3pK6a93eKED2XFNIwtnNcTW5XjM-X7edBcb0,18463
|
|
63
|
-
ccproxy/cli/commands/serve.py,sha256=
|
|
70
|
+
ccproxy/cli/commands/serve.py,sha256=1tV_QxSPEd_W14E-biYbpQzxuu_RZ4mzrEgBuVP7ogE,32917
|
|
64
71
|
ccproxy/cli/commands/config/__init__.py,sha256=uX8VewtrMu5X8VAx5ym1slwNtlICDBEs3S1HfoFe5Qo,376
|
|
65
72
|
ccproxy/cli/commands/config/commands.py,sha256=ukAr55NLFTg67f5czpjbuz_Ap_mwFIMIfMGHeXv_E5c,28917
|
|
66
73
|
ccproxy/cli/commands/config/schema_commands.py,sha256=ZSuK_Q1bWp8WUOSbkuwKz_4TwrxkRsA6MOt_-y1eiVs,4218
|
|
@@ -68,37 +75,36 @@ ccproxy/cli/docker/__init__.py,sha256=4x9QO8SF9aloJFs4xrUEhGcSmoosIYmjcMTk4-GnHB
|
|
|
68
75
|
ccproxy/cli/docker/adapter_factory.py,sha256=dbO_MGrrAsyF0DDZMKbrk4oMx2xAMZPihOAviF7D5zY,5022
|
|
69
76
|
ccproxy/cli/docker/params.py,sha256=cAkszIkS6lztpXxRuHRGBseA0n6n-huwyydDRKUHjSM,7378
|
|
70
77
|
ccproxy/cli/options/__init__.py,sha256=OiToWXDNOXnO-fuPz2H5qXYwp9ht7uB12-4wxqner1Q,340
|
|
71
|
-
ccproxy/cli/options/claude_options.py,sha256=
|
|
78
|
+
ccproxy/cli/options/claude_options.py,sha256=zkH0YHf_KLmkgkpIQsO-0C9IKFri8wxqrgKk0c2UEB0,5885
|
|
72
79
|
ccproxy/cli/options/core_options.py,sha256=80qVieUiUMYwjDKVeFfBDGjF1a8P1qB8Ppf-zSZ1eek,552
|
|
73
80
|
ccproxy/cli/options/security_options.py,sha256=95TfENdeAsDMes7SH39mQJERgrqoL4jZEKvZL7NlzJQ,873
|
|
74
81
|
ccproxy/cli/options/server_options.py,sha256=y37dtZGWuuYcDOn92zSzKwblnTgq65ZJJk2fWBA__s4,1935
|
|
75
|
-
ccproxy/config/__init__.py,sha256=
|
|
82
|
+
ccproxy/config/__init__.py,sha256=OGN54wL_XB-vP-g603NhqsSxYvKEXvBXVuEIxLV_tb4,891
|
|
76
83
|
ccproxy/config/auth.py,sha256=CDc5qiexq4jH3Ve39tnL1Vn5c5bOUBWUdi7j4VLwewU,4653
|
|
77
|
-
ccproxy/config/claude.py,sha256=
|
|
84
|
+
ccproxy/config/claude.py,sha256=i0ybt8BPFLIdIn5257cNxVzJc22mO2pirVxEQT8rxWo,12468
|
|
78
85
|
ccproxy/config/cors.py,sha256=eNxrNuPN7Ujh9_2fIWu6kmOIeYNuqn0NTuCsBYvctFM,2505
|
|
79
|
-
ccproxy/config/discovery.py,sha256=
|
|
86
|
+
ccproxy/config/discovery.py,sha256=lz5L0YcyVruZnXOxEXOD_4zg0k4W-woOGML9zwpmexQ,2487
|
|
80
87
|
ccproxy/config/docker_settings.py,sha256=5D8eBSyWActgBGE7cIb4HObqlvE-7jxylmUBn5UxLM4,8390
|
|
81
|
-
ccproxy/config/loader.py,sha256=kgeShuaeNjTHI7lX2VWSFlE4ugOJW9HAT-FJesKLegE,3100
|
|
82
88
|
ccproxy/config/observability.py,sha256=5AwQFEFxJLUStGP5gjL_5i8Hk8KdrXKY7ocITYg8jZQ,5466
|
|
83
89
|
ccproxy/config/pricing.py,sha256=RzsNQHYmv5P-BcRDV4GSkSIDImFIFEEC7roFu5jeocE,2613
|
|
84
90
|
ccproxy/config/reverse_proxy.py,sha256=hep4ubV7-4ZgdO1_WqY56b5yrYyHCdQgYayUHKH3tfo,866
|
|
85
|
-
ccproxy/config/scheduler.py,sha256=
|
|
91
|
+
ccproxy/config/scheduler.py,sha256=SFMkFwssu3SiBVrvi3Yh1vRtkOO3iEkt0ltsnaRP8-A,3198
|
|
86
92
|
ccproxy/config/security.py,sha256=luNy1J6xXSKPRjAVTmF1mqSpN4h0I_1CllBJfaYbq0Q,493
|
|
87
93
|
ccproxy/config/server.py,sha256=71Ih6huVn52demV6jNrixM8jqXVqfFrBpIvWIlmhlww,2527
|
|
88
|
-
ccproxy/config/settings.py,sha256=
|
|
94
|
+
ccproxy/config/settings.py,sha256=akemhsi8afRmcGrydkRTpHmlykIERh9kvHMwBMTsspw,18477
|
|
89
95
|
ccproxy/config/validators.py,sha256=EciRiEF7qGBcDp2Ms10VXyfAWXY_2uPPglvGh7EVLDs,5754
|
|
90
96
|
ccproxy/core/__init__.py,sha256=ZreOdlUlCn7R5GlS3EdpvIj5fO9sySbQKnuR8o6vwXI,6400
|
|
91
97
|
ccproxy/core/async_utils.py,sha256=slRQkIGctjZb6ZxridoJscFKVbyW2SYREieQjkpP_e8,19855
|
|
92
98
|
ccproxy/core/constants.py,sha256=mmkcOfKNnvu3h5paZ6GL72ecAK4XdBI4tXlmgImGyzI,2735
|
|
93
99
|
ccproxy/core/errors.py,sha256=gP1rh-k-KpE5OcVbFcdMdZSmDshvcoXdbVynIx864gc,8459
|
|
94
100
|
ccproxy/core/http.py,sha256=pj3UM9TDL13_sU0ULGuA2wvVg58uxOCy-ib3zugjelo,9317
|
|
95
|
-
ccproxy/core/http_transformers.py,sha256=
|
|
101
|
+
ccproxy/core/http_transformers.py,sha256=nIiKMbH9IpQeiaZC8XxxGR_fIYQPw7fI0vEbKBqR3J0,24993
|
|
96
102
|
ccproxy/core/interfaces.py,sha256=zzucgNTvui7fGQ8vjLzCba-itJZh0Fs6GrDAZNJfGXo,6366
|
|
97
|
-
ccproxy/core/logging.py,sha256=
|
|
103
|
+
ccproxy/core/logging.py,sha256=xwWsFTqGLrGrjQzgV2MphrwHg4i8YDW591xlhUGl7l4,10171
|
|
98
104
|
ccproxy/core/middleware.py,sha256=libv7wo-y9nni9hp7GCkYUKlIKihAwG0iHvjcv_RTs8,3355
|
|
99
105
|
ccproxy/core/proxy.py,sha256=6lFqNiGFQFlh61q32imbUD-RJAK2RJHJNyYLwAmUYr0,4615
|
|
100
106
|
ccproxy/core/system.py,sha256=91rMtlRtY4yxSsnPV5qZJaXHNFzvcrRZ1nQwS4CwG68,1019
|
|
101
|
-
ccproxy/core/transformers.py,sha256=
|
|
107
|
+
ccproxy/core/transformers.py,sha256=BpOweWwpuUKEsLe32zqqTN0iNPRVXjyAoW1jBPSO0C8,7884
|
|
102
108
|
ccproxy/core/types.py,sha256=kGRMzb6VI5KWa3aFKWgQ3gChqdHPrPoOyZ0QPT1m18E,3554
|
|
103
109
|
ccproxy/core/validators.py,sha256=k2z71lz-zKhRdtx3tYgJllqFnEcQ-eivj1kf3aVej0s,7367
|
|
104
110
|
ccproxy/docker/__init__.py,sha256=gO9FJepIWneXPANgsAJKx_VL9rt7pcX3hbRcwnSyzJk,1833
|
|
@@ -110,7 +116,8 @@ ccproxy/docker/protocol.py,sha256=uFJvKfTYhO8ROUo_tcMIuXYqhjK-eFIJV-U5Bora-jA,65
|
|
|
110
116
|
ccproxy/docker/stream_process.py,sha256=XahXegGG6B-7RsZAb9J8OA7sz7xi8CmRzEI4vBJLwTI,9071
|
|
111
117
|
ccproxy/docker/validators.py,sha256=OY-dkU88CLIeMBfv4P5QoVB7miQ8BD7kIgaMHxF7TsU,5764
|
|
112
118
|
ccproxy/models/__init__.py,sha256=yaz9lC0roh0u7C33rHrGW46lrwbyyAa_evpAlA5BzYw,3548
|
|
113
|
-
ccproxy/models/claude_sdk.py,sha256=
|
|
119
|
+
ccproxy/models/claude_sdk.py,sha256=T-6HpAPe2a17sd27HE7ttFENh2JxwrFrnGBwMwDwovs,15522
|
|
120
|
+
ccproxy/models/detection.py,sha256=-O1oIMK-8maBO_77ns-MlV82U3TZwh-8oYJd7XuE6dw,4576
|
|
114
121
|
ccproxy/models/errors.py,sha256=B2rbL-17ZI9emDOca2A2fLOcH1-_77t_xqDmiPf6fgY,1329
|
|
115
122
|
ccproxy/models/messages.py,sha256=halc96Yxx3R5Xa9F5Q53iFZs0MJMDRfAA0fSxaij51U,8013
|
|
116
123
|
ccproxy/models/permissions.py,sha256=uhlzHc56rDzekjQMN8ITPCrh-0lamcgzTwx1OA2y67w,3612
|
|
@@ -118,15 +125,16 @@ ccproxy/models/requests.py,sha256=k4oeGbSCsbm3E5_3JT4h7hjrkSsgNgLIlb99BypSoHk,27
|
|
|
118
125
|
ccproxy/models/responses.py,sha256=4rJNCbCoQtjiRzwoQLwK-sVJT2HFsZ2U6Vw63CZ1ztw,7820
|
|
119
126
|
ccproxy/models/types.py,sha256=27MUg7pVGrK5oWzcrtG_IAoScEcrF20thO94bxZXQww,2729
|
|
120
127
|
ccproxy/observability/__init__.py,sha256=5n9yQBbMLAQVAEJZD-2t4CKfI0Wx2aoDH7d2ynPM4bg,1503
|
|
121
|
-
ccproxy/observability/access_logger.py,sha256=
|
|
128
|
+
ccproxy/observability/access_logger.py,sha256=h23GbxRYhPz26-z3rQfFSg12lqwssiXEkJRNmyBJspQ,15755
|
|
122
129
|
ccproxy/observability/context.py,sha256=sfOdhgLY6LxLzOkJuzjqBsZV2e8ozAiYp79bhE2oqG4,14581
|
|
123
|
-
ccproxy/observability/metrics.py,sha256=
|
|
130
|
+
ccproxy/observability/metrics.py,sha256=460SDpwQEpIpHPgg7vA6BhZPcYVhyQEpP20k_qZhUvI,21017
|
|
124
131
|
ccproxy/observability/pushgateway.py,sha256=t7jGCP7dQirBjQyX-nz4S6MKKIHErU9yQMqgfCiP0BQ,12708
|
|
125
132
|
ccproxy/observability/sse_events.py,sha256=CVumUxVlXV5tpqVozymaLW4pBTEM90KBYWS9jAJ6Dzk,10697
|
|
126
133
|
ccproxy/observability/stats_printer.py,sha256=-QSiAMiurQlMzdMQcS0bNcswm5dDaIzTeS1bUqMeVQY,30110
|
|
134
|
+
ccproxy/observability/streaming_response.py,sha256=I9YsCdOMFR6gEkAoDkaGJO0kF1mdZHMrHYvbn45mzyo,4157
|
|
127
135
|
ccproxy/observability/storage/__init__.py,sha256=iAnhODA2PD3PxheoRgJv5KFCTUK_QwxxFa2Ne230RTg,47
|
|
128
|
-
ccproxy/observability/storage/duckdb_simple.py,sha256=
|
|
129
|
-
ccproxy/observability/storage/models.py,sha256=
|
|
136
|
+
ccproxy/observability/storage/duckdb_simple.py,sha256=pHcz8D7fJ0Qrhj4W0iN1TGTOIHxF_HKpyTHruTCTlUQ,25441
|
|
137
|
+
ccproxy/observability/storage/models.py,sha256=Xca4z6rCRB3HjCm50Wwge96MFAUoUKF9f6S_lGdBzHE,2307
|
|
130
138
|
ccproxy/pricing/__init__.py,sha256=8EKUTusWT_URBO8_jzHQ2JWIv11JYZxiyk1WoA_slHE,450
|
|
131
139
|
ccproxy/pricing/cache.py,sha256=j0X0VWICAV2WPWSY8TQTsRZ04fX0_tuegJRp9Lw7Dgk,6506
|
|
132
140
|
ccproxy/pricing/loader.py,sha256=F7Ciu39xBdY6QqUbDNNM2FmX0zqFhrMCed_-YLkLdvI,8633
|
|
@@ -135,12 +143,13 @@ ccproxy/pricing/updater.py,sha256=OKbozb2SIe4yrwWVsQd5ryopZrJ06mIDP6y166-l_tg,10
|
|
|
135
143
|
ccproxy/scheduler/__init__.py,sha256=qVe6NeKPn6NgMqEaG4_K4cYZBCpbFM7g6ptNPEzhi8c,1160
|
|
136
144
|
ccproxy/scheduler/core.py,sha256=Lvhc3i2bfbEnX-2n8lgDBM7YG7TKEnZC3tf8KC5u67M,10344
|
|
137
145
|
ccproxy/scheduler/errors.py,sha256=k7dcid0_te7IwwQaad-Jkj7MWFBgIOdgD_y_n5joio0,817
|
|
138
|
-
ccproxy/scheduler/manager.py,sha256
|
|
146
|
+
ccproxy/scheduler/manager.py,sha256=C6nS7PB9_YHfWiqhXnsHeYsTZKeJ1ZZKSD53JOQfuBY,7811
|
|
139
147
|
ccproxy/scheduler/registry.py,sha256=MaCuOEiJiYjlKS2Yqp3PxeWXpf8AqNPCQ_qeWbWtBCw,4058
|
|
140
|
-
ccproxy/scheduler/tasks.py,sha256=
|
|
148
|
+
ccproxy/scheduler/tasks.py,sha256=ROIRQcrB3zntZDJ53pabK53a18bPaHYJI1TvS9wwRAI,24944
|
|
141
149
|
ccproxy/services/__init__.py,sha256=ZvnelD15eFLlWHsucYXBFGNrdT7ncdP1KLnqzJNGOCs,251
|
|
142
|
-
ccproxy/services/
|
|
143
|
-
ccproxy/services/
|
|
150
|
+
ccproxy/services/claude_detection_service.py,sha256=aRg_aSucpi07DLzIKfDbLGYzjCLUXSpVScYcjLgSKbM,9941
|
|
151
|
+
ccproxy/services/claude_sdk_service.py,sha256=IuT4XP116fXzk20SUiYhKiKRoOxeeo7jlGzKVLH2NEo,25954
|
|
152
|
+
ccproxy/services/proxy_service.py,sha256=3rxemTu2KytC8UNy_rai7XUd2AP8yqYYHKlxH1Ker58,51397
|
|
144
153
|
ccproxy/services/credentials/__init__.py,sha256=fkCWqxlUyGVA1mxGicn4cvdbYJQo09SG9NoGKzUun3s,1394
|
|
145
154
|
ccproxy/services/credentials/config.py,sha256=97W3GqtxZlBv45oDHJ-plsHiSeFvNI-FTMZEw4CsPes,3221
|
|
146
155
|
ccproxy/services/credentials/manager.py,sha256=AnRvl1_v-eSbAEcmHMcUMmo7UpvTnAHe9QO5caL1JMY,19905
|
|
@@ -152,15 +161,18 @@ ccproxy/testing/content_generation.py,sha256=in2F_W1RSnQYKXYCavMrYXPLBrqVn_Bogx8
|
|
|
152
161
|
ccproxy/testing/mock_responses.py,sha256=GaegneKCVJSxoptLCUseriZ_wV_TfRnpD-vB0t60N3M,9200
|
|
153
162
|
ccproxy/testing/response_handlers.py,sha256=TSfBHzHLw8d3Y95zJ8wYewU9f5Wh89bl7DRfa-49ze0,6311
|
|
154
163
|
ccproxy/testing/scenarios.py,sha256=lVTkf1TbqPnWAfY2VbXez6dSFHsohuXerDmh37iC5VU,9200
|
|
155
|
-
ccproxy/utils/__init__.py,sha256=
|
|
164
|
+
ccproxy/utils/__init__.py,sha256=klTwpS5lbhi0Bg6QXIbX01-7oXaLoGjhHf1MKq_4aQQ,431
|
|
156
165
|
ccproxy/utils/cost_calculator.py,sha256=mHquyA_1vnPVZ2smjdPwThCJtGu-rF9n8ZvIrAwTF78,7276
|
|
166
|
+
ccproxy/utils/disconnection_monitor.py,sha256=EOKJoTD_wDZ-l-yoOqx6Z488NZm2fFKW3KOwKlTELkE,3128
|
|
167
|
+
ccproxy/utils/id_generator.py,sha256=k6R_W40lJSPi_it4M99EVg9eRD138oC4bv_8Ua3X8ms,301
|
|
157
168
|
ccproxy/utils/model_mapping.py,sha256=7TA3Jew_lg4IqMvoOvalDo1Vzozjb_Zq4749hPgPZGA,6602
|
|
158
169
|
ccproxy/utils/models_provider.py,sha256=F0_nwNsx-gGhobdTnPQh9zfrhOfw7cBrW2RR09SYY3Q,4434
|
|
159
170
|
ccproxy/utils/simple_request_logger.py,sha256=d54aXW_0P7zewGRzjwDu7QfJ-DGn4zJXu2R5hGXh-rU,8223
|
|
171
|
+
ccproxy/utils/startup_helpers.py,sha256=oR_7DfqXpPKW0Aa0QT-qZydsX7qgqfJK_89LE342YCQ,15253
|
|
160
172
|
ccproxy/utils/streaming_metrics.py,sha256=JkvmWJ9s1fuKi7x1NoSoderUuT-mU6MQfbnN5GmziYE,7761
|
|
161
173
|
ccproxy/utils/version_checker.py,sha256=D-6a5qV9sPTqkTZHucHZ-xCd8Wdy29lxnVgcvdBs10w,4839
|
|
162
|
-
ccproxy_api-0.1.
|
|
163
|
-
ccproxy_api-0.1.
|
|
164
|
-
ccproxy_api-0.1.
|
|
165
|
-
ccproxy_api-0.1.
|
|
166
|
-
ccproxy_api-0.1.
|
|
174
|
+
ccproxy_api-0.1.5.dist-info/METADATA,sha256=SbCiCzP1Ob76Dfr4VEfGUpnPEZxNQ72GxgoyKgcd5z4,13272
|
|
175
|
+
ccproxy_api-0.1.5.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
176
|
+
ccproxy_api-0.1.5.dist-info/entry_points.txt,sha256=XLke7uRmx6c1G3Ejnvm74x_eTKKtCgRRSk1dXIBFyg4,128
|
|
177
|
+
ccproxy_api-0.1.5.dist-info/licenses/LICENSE,sha256=httxSCpTrEOkipisMeGXSrZhTB-4MRIorQU0hS1B6eQ,1066
|
|
178
|
+
ccproxy_api-0.1.5.dist-info/RECORD,,
|