Python-only compatibility chain for the current FastAPI/recipe surface.
| 463 | |
| 464 | |
| 465 | class Switchyard: |
| 466 | """Python-only compatibility chain for the current FastAPI/recipe surface.""" |
| 467 | |
| 468 | state_key: ClassVar[str] = "switchyard" |
| 469 | |
| 470 | def __init__( |
| 471 | self, |
| 472 | *, |
| 473 | request_processors: Iterable[Any] | None = None, |
| 474 | backend: Any, |
| 475 | response_processors: Iterable[Any] | None = None, |
| 476 | translator: Any, |
| 477 | fallback_target_on_evict: str | None = None, |
| 478 | ) -> None: |
| 479 | if not isinstance(backend, LLMBackend): |
| 480 | actual = _role_type_name(backend) |
| 481 | raise TypeError(f"Switchyard backend must be LLMBackend, got {actual}") |
| 482 | self._request_components = tuple(request_processors or ()) |
| 483 | self._backend = backend |
| 484 | self._response_components = tuple(response_processors or ()) |
| 485 | self._translator = translator |
| 486 | self._fallback_target_on_evict = fallback_target_on_evict |
| 487 | |
| 488 | def iter_components(self) -> list[Any]: |
| 489 | """Return lifecycle components in startup order.""" |
| 490 | return [ |
| 491 | *self._request_components, |
| 492 | self._backend, |
| 493 | *self._response_components, |
| 494 | self._translator, |
| 495 | ] |
| 496 | |
| 497 | async def call( |
| 498 | self, |
| 499 | request: Any, |
| 500 | *, |
| 501 | ctx: Any | None = None, |
| 502 | ) -> Any: |
| 503 | """Run the compatibility chain and translate the final response.""" |
| 504 | context = ctx if ctx is not None else ProxyContext() |
| 505 | processed_request = await self._process_request_components(context, request) |
| 506 | try: |
| 507 | response = await self._call_backend_stage(context, processed_request) |
| 508 | except _load_native().SwitchyardContextWindowExceededError as error: |
| 509 | if self._fallback_target_on_evict is None: |
| 510 | raise |
| 511 | response = await self._retry_after_context_overflow( |
| 512 | context, |
| 513 | processed_request, |
| 514 | error, |
| 515 | ) |
| 516 | return await self._translator.translate(context, processed_request, response) |
| 517 | |
| 518 | async def _call_backend_stage( |
| 519 | self, |
| 520 | ctx: Any, |
| 521 | request: Any, |
| 522 | ) -> Any: |
no outgoing calls