Spaces:
Sleeping
Sleeping
| """FastAPI route handlers.""" | |
| from fastapi import APIRouter, Depends, HTTPException, Request, Response | |
| from loguru import logger | |
| from free_claude_code.application.errors import ApplicationError | |
| from free_claude_code.application.ports import ProviderResolver, RequestRuntimeLease | |
| from free_claude_code.config.model_refs import parse_provider_type | |
| from free_claude_code.config.settings import Settings | |
| from free_claude_code.core.anthropic import ( | |
| MessagesRequest, | |
| TokenCountRequest, | |
| get_token_count, | |
| ) | |
| from free_claude_code.core.openai_responses import OpenAIResponsesRequest | |
| from free_claude_code.core.trace import trace_event | |
| from .dependencies import ( | |
| get_services, | |
| get_settings, | |
| require_proxy_auth, | |
| resolve_provider, | |
| ) | |
| from .handlers import MessagesHandler, ResponsesHandler, TokenCountHandler | |
| from .model_catalog import ModelsListResponse, build_models_list_response | |
| from .ports import ApiServices | |
| from .request_errors import ordinary_application_error_response | |
| from .request_ids import get_request_id | |
| from .response_streams import bind_response_lifetime | |
| router = APIRouter() | |
| def _provider_resolver(lease: RequestRuntimeLease) -> ProviderResolver: | |
| return lambda provider_type: resolve_provider(provider_type, lease=lease) | |
| async def _create_messages_response( | |
| services: ApiServices, | |
| request_data: MessagesRequest, | |
| *, | |
| request_id: str, | |
| ) -> object: | |
| lease: RequestRuntimeLease | None = None | |
| try: | |
| lease = await services.requests.acquire() | |
| handler = MessagesHandler( | |
| lease.settings, | |
| provider_resolver=_provider_resolver(lease), | |
| token_counter=get_token_count, | |
| generation_id=lease.generation_id, | |
| ) | |
| response = await handler.create(request_data, request_id=request_id) | |
| except ApplicationError as exc: | |
| if lease is not None: | |
| await lease.release() | |
| return ordinary_application_error_response( | |
| exc, | |
| wire_api="messages", | |
| request_id=request_id, | |
| ) | |
| except BaseException: | |
| if lease is not None: | |
| await lease.release() | |
| raise | |
| assert lease is not None | |
| return await bind_response_lifetime(response, lease.release) | |
| async def _create_responses_response( | |
| services: ApiServices, | |
| request_data: OpenAIResponsesRequest, | |
| *, | |
| request_id: str, | |
| ) -> object: | |
| lease: RequestRuntimeLease | None = None | |
| try: | |
| lease = await services.requests.acquire() | |
| handler = ResponsesHandler( | |
| lease.settings, | |
| provider_resolver=_provider_resolver(lease), | |
| generation_id=lease.generation_id, | |
| ) | |
| response = await handler.create(request_data, request_id=request_id) | |
| except ApplicationError as exc: | |
| if lease is not None: | |
| await lease.release() | |
| return ordinary_application_error_response( | |
| exc, | |
| wire_api="responses", | |
| request_id=request_id, | |
| ) | |
| except BaseException: | |
| if lease is not None: | |
| await lease.release() | |
| raise | |
| assert lease is not None | |
| return await bind_response_lifetime(response, lease.release) | |
| def _probe_response(allow: str) -> Response: | |
| return Response(status_code=204, headers={"Allow": allow}) | |
| async def create_message( | |
| request: Request, | |
| request_data: MessagesRequest, | |
| services: ApiServices = Depends(get_services), | |
| _auth=Depends(require_proxy_auth), | |
| ): | |
| """Create a message (JSON by default; stream=true returns Anthropic SSE).""" | |
| return await _create_messages_response( | |
| services, | |
| request_data, | |
| request_id=get_request_id(request), | |
| ) | |
| async def probe_messages(_auth=Depends(require_proxy_auth)): | |
| return _probe_response("POST, HEAD, OPTIONS") | |
| async def create_response( | |
| request: Request, | |
| request_data: OpenAIResponsesRequest, | |
| services: ApiServices = Depends(get_services), | |
| _auth=Depends(require_proxy_auth), | |
| ): | |
| """Create an OpenAI Responses-compatible response through this proxy.""" | |
| return await _create_responses_response( | |
| services, | |
| request_data, | |
| request_id=get_request_id(request), | |
| ) | |
| async def probe_responses(_auth=Depends(require_proxy_auth)): | |
| return _probe_response("POST, HEAD, OPTIONS") | |
| async def count_tokens( | |
| request: Request, | |
| request_data: TokenCountRequest, | |
| settings: Settings = Depends(get_settings), | |
| _auth=Depends(require_proxy_auth), | |
| ): | |
| """Count tokens for a request.""" | |
| handler = TokenCountHandler(settings, token_counter=get_token_count) | |
| return handler.count(request_data, request_id=get_request_id(request)) | |
| async def probe_count_tokens(_auth=Depends(require_proxy_auth)): | |
| return _probe_response("POST, HEAD, OPTIONS") | |
| async def root( | |
| settings: Settings = Depends(get_settings), | |
| ): | |
| return { | |
| "status": "ok", | |
| "provider": parse_provider_type(settings.model), | |
| "model": settings.model, | |
| } | |
| async def probe_root(): | |
| return _probe_response("GET, HEAD, OPTIONS") | |
| async def health(): | |
| return {"status": "healthy"} | |
| async def probe_health(): | |
| return _probe_response("GET, HEAD, OPTIONS") | |
| async def list_models( | |
| services: ApiServices = Depends(get_services), | |
| settings: Settings = Depends(get_settings), | |
| _auth=Depends(require_proxy_auth), | |
| ): | |
| """List the model ids this proxy advertises to compatible clients.""" | |
| trace_event(stage="ingress", event="free_claude_code.api.models.list", source="api") | |
| return build_models_list_response(settings, services.requests) | |
| async def stop_cli( | |
| services: ApiServices = Depends(get_services), | |
| _auth=Depends(require_proxy_auth), | |
| ): | |
| """Stop all CLI sessions and pending tasks.""" | |
| result = await services.tasks.stop_all() | |
| if result is None: | |
| raise HTTPException(status_code=503, detail="Messaging system not initialized") | |
| if result.source is not None: | |
| logger.info("STOP_CLI: source={} cancelled_count=N/A", result.source) | |
| return {"status": "stopped", "source": result.source} | |
| count = result.cancelled_count or 0 | |
| trace_event( | |
| stage="ingress", | |
| event="free_claude_code.api.cli.stop_via_messaging_workflow", | |
| source="api", | |
| cancelled_nodes=count, | |
| ) | |
| logger.info("STOP_CLI: source=messaging_workflow cancelled_count={}", count) | |
| return {"status": "stopped", "cancelled_count": count} | |