Spaces:
Sleeping
Sleeping
| """FastAPI streaming response wrappers for public API wire formats.""" | |
| import asyncio | |
| from collections.abc import ( | |
| AsyncIterator, | |
| Awaitable, | |
| Callable, | |
| Mapping, | |
| ) | |
| from typing import Any, Literal | |
| from fastapi.responses import JSONResponse, Response, StreamingResponse | |
| from starlette.background import BackgroundTask | |
| from starlette.responses import ContentStream | |
| from starlette.types import Receive, Scope, Send | |
| from free_claude_code.core.anthropic import anthropic_error_type_for_failure | |
| from free_claude_code.core.anthropic.streaming import ( | |
| ANTHROPIC_SSE_RESPONSE_HEADERS, | |
| anthropic_terminal_error_frame, | |
| anthropic_terminal_failure_frame, | |
| ) | |
| from free_claude_code.core.async_iterators import try_close_async_iterator | |
| from free_claude_code.core.diagnostics import safe_exception_message | |
| from free_claude_code.core.failures import find_execution_failure | |
| from free_claude_code.core.trace import close_stream_input, trace_event | |
| TERMINAL_EXECUTION_ERROR_HEADERS = {"x-should-retry": "false"} | |
| PreStartErrorResponse = Callable[[BaseException], Response] | |
| TerminalFrameEmitter = Callable[[BaseException], str] | |
| TerminalFailureObserver = Callable[[BaseException], None] | |
| ReleaseResponseResource = Callable[[], Awaitable[None]] | |
| WireApi = Literal["messages", "responses"] | |
| class EmptyStreamError(RuntimeError): | |
| """Raised when a public stream ends before emitting any protocol chunk.""" | |
| class ManagedStreamingResponse(StreamingResponse): | |
| """Own body closure and one response-scoped runtime release callback.""" | |
| def __init__( | |
| self, | |
| content: ContentStream, | |
| status_code: int = 200, | |
| headers: Mapping[str, str] | None = None, | |
| media_type: str | None = None, | |
| background: BackgroundTask | None = None, | |
| ) -> None: | |
| super().__init__( | |
| content, | |
| status_code=status_code, | |
| headers=headers, | |
| media_type=media_type, | |
| background=background, | |
| ) | |
| self._release: ReleaseResponseResource | None = None | |
| self._cleanup_task: asyncio.Task[None] | None = None | |
| def bind_release(self, release: ReleaseResponseResource) -> None: | |
| """Bind the resource retained for this response before ASGI execution.""" | |
| if self._release is not None: | |
| raise RuntimeError("A response resource release is already bound.") | |
| if self._cleanup_task is not None: | |
| raise RuntimeError("Cannot bind a resource after response cleanup started.") | |
| self._release = release | |
| async def aclose(self) -> None: | |
| """Close the body and release its runtime resource exactly once.""" | |
| await self._close(preserved_error=None) | |
| async def _close(self, *, preserved_error: BaseException | None) -> None: | |
| task = self._cleanup_task | |
| if task is None: | |
| task = asyncio.create_task( | |
| self._cleanup(preserved_error=preserved_error), | |
| name="fcc-api-response-cleanup", | |
| ) | |
| self._cleanup_task = task | |
| await _wait_for_cleanup(task) | |
| async def __call__( | |
| self, | |
| scope: Scope, | |
| receive: Receive, | |
| send: Send, | |
| ) -> None: | |
| preserved_error: BaseException | None = None | |
| try: | |
| await super().__call__(scope, receive, send) | |
| except BaseException as exc: | |
| preserved_error = exc | |
| raise | |
| finally: | |
| await self._close(preserved_error=preserved_error) | |
| async def _cleanup(self, *, preserved_error: BaseException | None) -> None: | |
| try: | |
| await close_stream_input( | |
| self.body_iterator, | |
| owner="ManagedStreamingResponse", | |
| source="api", | |
| preserved_error=preserved_error, | |
| ) | |
| except Exception as exc: | |
| _trace_response_cleanup_failure("close_body", exc) | |
| release = self._release | |
| if release is None: | |
| return | |
| try: | |
| await release() | |
| except Exception as exc: | |
| _trace_response_cleanup_failure("release_resource", exc) | |
| async def _wait_for_cleanup(task: asyncio.Task[None]) -> None: | |
| """Wait through repeated caller cancellation, then restore cancellation.""" | |
| cancellation: asyncio.CancelledError | None = None | |
| while not task.done(): | |
| try: | |
| await asyncio.shield(task) | |
| except asyncio.CancelledError as exc: | |
| cancellation = exc | |
| # Ordinary defensive failures are trace-only; cancellation remains control flow. | |
| try: | |
| task.result() | |
| except asyncio.CancelledError: | |
| if cancellation is not None: | |
| raise cancellation from None | |
| raise | |
| except Exception as exc: | |
| _trace_response_cleanup_failure("cleanup_task", exc) | |
| if cancellation is not None: | |
| raise cancellation | |
| def _trace_response_cleanup_failure(operation: str, exc: BaseException) -> None: | |
| trace_event( | |
| stage="egress", | |
| event="free_claude_code.api.response.cleanup_failed", | |
| source="api", | |
| operation=operation, | |
| exc_type=type(exc).__name__, | |
| ) | |
| async def bind_response_lifetime( | |
| response: object, | |
| release: ReleaseResponseResource, | |
| ) -> object: | |
| """Retain a runtime resource until a response body is fully consumed.""" | |
| if isinstance(response, ManagedStreamingResponse): | |
| response.bind_release(release) | |
| return response | |
| if isinstance(response, StreamingResponse): | |
| error = TypeError("Streaming API responses must use ManagedStreamingResponse.") | |
| try: | |
| await close_stream_input( | |
| response.body_iterator, | |
| owner="bind_response_lifetime", | |
| source="api", | |
| preserved_error=error, | |
| ) | |
| finally: | |
| await release() | |
| raise error | |
| await release() | |
| return response | |
| def terminal_execution_error_response( | |
| *, status_code: int, content: dict[str, Any] | |
| ) -> JSONResponse: | |
| """Return a final provider-execution error without enabling client retries.""" | |
| return JSONResponse( | |
| status_code=status_code, | |
| content=content, | |
| headers=dict(TERMINAL_EXECUTION_ERROR_HEADERS), | |
| ) | |
| def trace_terminal_execution_error( | |
| *, | |
| wire_api: WireApi, | |
| request_id: str, | |
| status_code: int, | |
| error_type: str, | |
| error: BaseException | None = None, | |
| ) -> None: | |
| """Record one correlated terminal-execution decision at the HTTP boundary.""" | |
| fields: dict[str, object] = { | |
| "stage": "egress", | |
| "event": "free_claude_code.api.response.terminal_execution_error", | |
| "source": "api", | |
| "wire_api": wire_api, | |
| "request_id": request_id, | |
| "status_code": status_code, | |
| "error_type": error_type, | |
| "client_should_retry": False, | |
| } | |
| failure = find_execution_failure(error) if error is not None else None | |
| if error is not None: | |
| fields["exc_type"] = type(failure or error).__name__ | |
| if failure is not None: | |
| fields["failure_kind"] = failure.kind.value | |
| fields["provider_retryable"] = failure.retryable | |
| trace_event(**fields) | |
| async def _first_chunk_streaming_response( | |
| body: AsyncIterator[str], | |
| *, | |
| headers: Mapping[str, str], | |
| pre_start_error_response: PreStartErrorResponse, | |
| terminal_frame: TerminalFrameEmitter | None, | |
| terminal_failure_observer: TerminalFailureObserver | None, | |
| ) -> Response: | |
| try: | |
| first_chunk = await anext(body) | |
| except StopAsyncIteration: | |
| error = EmptyStreamError("Stream ended before emitting a response.") | |
| await _close_pre_start_body(body, preserved_error=error) | |
| return pre_start_error_response(error) | |
| except GeneratorExit as exc: | |
| await _close_pre_start_body(body, preserved_error=exc) | |
| raise | |
| except asyncio.CancelledError as exc: | |
| await _close_pre_start_body(body, preserved_error=exc) | |
| raise | |
| except BaseExceptionGroup as exc: | |
| await _close_pre_start_body(body, preserved_error=exc) | |
| return pre_start_error_response(exc) | |
| except Exception as exc: | |
| await _close_pre_start_body(body, preserved_error=exc) | |
| return pre_start_error_response(exc) | |
| return ManagedStreamingResponse( | |
| _PrefetchedStream( | |
| first_chunk, | |
| body, | |
| terminal_frame=terminal_frame, | |
| terminal_failure_observer=terminal_failure_observer, | |
| ), | |
| media_type="text/event-stream", | |
| headers=dict(headers), | |
| ) | |
| async def _close_pre_start_body( | |
| body: AsyncIterator[str], | |
| *, | |
| preserved_error: BaseException, | |
| ) -> None: | |
| task = asyncio.create_task( | |
| close_stream_input( | |
| body, | |
| owner="first_chunk_streaming_response", | |
| source="api", | |
| preserved_error=preserved_error, | |
| ), | |
| name="fcc-api-pre-start-stream-cleanup", | |
| ) | |
| await _wait_for_cleanup(task) | |
| class _PrefetchedStream(AsyncIterator[str]): | |
| """Replay one prefetched frame while retaining ownership of the tail.""" | |
| def __init__( | |
| self, | |
| first_chunk: str, | |
| body: AsyncIterator[str], | |
| *, | |
| terminal_frame: TerminalFrameEmitter | None, | |
| terminal_failure_observer: TerminalFailureObserver | None, | |
| ) -> None: | |
| self._first_chunk: str | None = first_chunk | |
| self._body = body | |
| self._terminal_frame = terminal_frame | |
| self._terminal_failure_observer = terminal_failure_observer | |
| self._done = False | |
| self._closed = False | |
| def __aiter__(self) -> "_PrefetchedStream": | |
| return self | |
| async def __anext__(self) -> str: | |
| if self._closed or self._done: | |
| raise StopAsyncIteration | |
| if self._first_chunk is not None: | |
| first_chunk = self._first_chunk | |
| self._first_chunk = None | |
| return first_chunk | |
| try: | |
| return await anext(self._body) | |
| except StopAsyncIteration: | |
| self._done = True | |
| raise | |
| except BaseExceptionGroup as exc: | |
| return self._terminal_chunk(find_execution_failure(exc) or exc) | |
| except Exception as exc: | |
| return self._terminal_chunk(exc) | |
| async def aclose(self) -> None: | |
| if self._closed: | |
| return | |
| self._closed = True | |
| self._done = True | |
| close_error = await try_close_async_iterator(self._body) | |
| if close_error is not None: | |
| raise close_error | |
| def _terminal_chunk(self, exc: BaseException) -> str: | |
| terminal_frame = self._terminal_frame | |
| if terminal_frame is None: | |
| raise exc | |
| self._done = True | |
| if self._terminal_failure_observer is not None: | |
| self._terminal_failure_observer(exc) | |
| return terminal_frame(exc) | |
| async def anthropic_sse_streaming_response( | |
| body: AsyncIterator[str], | |
| *, | |
| pre_start_error_response: PreStartErrorResponse, | |
| request_id: str, | |
| ) -> Response: | |
| """Return a streaming response for Anthropic-style SSE streams.""" | |
| return await _first_chunk_streaming_response( | |
| body, | |
| headers=ANTHROPIC_SSE_RESPONSE_HEADERS, | |
| pre_start_error_response=pre_start_error_response, | |
| terminal_frame=_anthropic_terminal_frame, | |
| terminal_failure_observer=lambda exc: _trace_anthropic_terminal_failure( | |
| exc, | |
| request_id=request_id, | |
| ), | |
| ) | |
| def _anthropic_terminal_frame(exc: BaseException) -> str: | |
| failure = find_execution_failure(exc) | |
| if failure is not None: | |
| return anthropic_terminal_failure_frame(failure) | |
| return anthropic_terminal_error_frame(safe_exception_message(exc)) | |
| def _trace_anthropic_terminal_failure( | |
| exc: BaseException, | |
| *, | |
| request_id: str, | |
| ) -> None: | |
| failure = find_execution_failure(exc) | |
| trace_terminal_execution_error( | |
| wire_api="messages", | |
| request_id=request_id, | |
| status_code=failure.status_code if failure is not None else 500, | |
| error_type=( | |
| anthropic_error_type_for_failure(failure) | |
| if failure is not None | |
| else "api_error" | |
| ), | |
| error=exc, | |
| ) | |
| async def openai_responses_sse_streaming_response( | |
| body: AsyncIterator[str], | |
| *, | |
| headers: Mapping[str, str], | |
| pre_start_error_response: PreStartErrorResponse, | |
| ) -> Response: | |
| """Return a streaming response for OpenAI Responses-style SSE.""" | |
| return await _first_chunk_streaming_response( | |
| body, | |
| headers=headers, | |
| pre_start_error_response=pre_start_error_response, | |
| terminal_frame=None, | |
| terminal_failure_observer=None, | |
| ) | |