| """Provider execution shared by inbound API adapters.""" |
|
|
| import sys |
| import time |
| from collections.abc import AsyncIterator, Callable |
| from typing import Literal |
|
|
| from loguru import logger |
|
|
| from free_claude_code.core.anthropic import ( |
| Message, |
| SystemContent, |
| Tool, |
| anthropic_request_snapshot, |
| get_token_count, |
| ) |
| from free_claude_code.core.trace import ( |
| close_stream_input, |
| trace_event, |
| traced_async_stream, |
| ) |
| from free_claude_code.core.usage_tracking import ( |
| PendingUsageRecord, |
| UsageTrackingStream, |
| extract_prompt, |
| get_buffer, |
| ) |
|
|
| from .ports import ProviderResolver |
| from .routing import RoutedMessagesRequest |
|
|
| TokenCounter = Callable[ |
| [list[Message], str | list[SystemContent] | None, list[Tool] | None], |
| int, |
| ] |
| WireApi = Literal["messages", "responses"] |
|
|
|
|
| class ProviderExecutor: |
| """Resolve a provider and execute one routed Anthropic Messages stream.""" |
|
|
| def __init__( |
| self, |
| provider_resolver: ProviderResolver, |
| *, |
| token_counter: TokenCounter = get_token_count, |
| generation_id: int | None = None, |
| log_raw_payloads: bool = False, |
| ) -> None: |
| self._provider_resolver = provider_resolver |
| self._token_counter = token_counter |
| self._generation_id = generation_id |
| self._log_raw_payloads = log_raw_payloads |
|
|
| def stream( |
| self, |
| routed: RoutedMessagesRequest, |
| *, |
| wire_api: WireApi, |
| raw_log_label: str, |
| raw_log_payload: object, |
| request_id: str, |
| ) -> AsyncIterator[str]: |
| """Preflight synchronously, then return the traced provider stream.""" |
| provider = self._provider_resolver(routed.resolved.provider_id) |
| provider.preflight_stream( |
| routed.request, |
| reasoning=routed.reasoning, |
| ) |
|
|
| gateway_model = routed.resolved.original_model |
| route_trace: dict[str, object] = { |
| "stage": "routing", |
| "event": "free_claude_code.api.route.resolved", |
| "source": "api", |
| "request_id": request_id, |
| "provider_id": routed.resolved.provider_id, |
| "provider_model": routed.resolved.provider_model, |
| "provider_model_ref": routed.resolved.provider_model_ref, |
| "gateway_model": gateway_model, |
| "reasoning_control": routed.reasoning.control.value, |
| "reasoning_effort": ( |
| routed.reasoning.effort.value |
| if routed.reasoning.effort is not None |
| else None |
| ), |
| "reasoning_budget_tokens": routed.reasoning.budget_tokens, |
| } |
| if wire_api == "responses": |
| route_trace["wire_api"] = "responses" |
| if self._generation_id is not None: |
| route_trace["generation_id"] = self._generation_id |
| trace_event(**route_trace) |
|
|
| request_snapshot = anthropic_request_snapshot(routed.request) |
| request_snapshot["model"] = gateway_model |
| trace_event( |
| stage="ingress", |
| event=( |
| "free_claude_code.api.responses.request.received" |
| if wire_api == "responses" |
| else "free_claude_code.api.request.received" |
| ), |
| source="api", |
| message_count=len(routed.request.messages), |
| snapshot=request_snapshot, |
| request_id=request_id, |
| ) |
|
|
| if self._log_raw_payloads: |
| logger.debug(f"{raw_log_label} [{{}}]: {{}}", request_id, raw_log_payload) |
|
|
| input_tokens = self._token_counter( |
| routed.request.messages, |
| routed.request.system, |
| routed.request.tools, |
| ) |
|
|
| usage_tracking = get_buffer() is not None |
| pending = ( |
| PendingUsageRecord( |
| request_id=request_id, |
| started_at=time.time(), |
| provider=routed.resolved.provider_id, |
| provider_model=routed.resolved.provider_model, |
| gateway_model=gateway_model, |
| wire_api=wire_api, |
| input_tokens=input_tokens, |
| prompt=extract_prompt(routed.request), |
| ) |
| if usage_tracking |
| else None |
| ) |
|
|
| async def provider_body() -> AsyncIterator[str]: |
| provider_stream: AsyncIterator[str] | None = None |
| try: |
| provider_stream = provider.stream_response( |
| routed.request, |
| input_tokens=input_tokens, |
| request_id=request_id, |
| response_model=gateway_model, |
| reasoning=routed.reasoning, |
| ) |
| async for chunk in provider_stream: |
| yield chunk |
| finally: |
| if provider_stream is not None: |
| await close_stream_input( |
| provider_stream, |
| owner="provider_executor", |
| source="api", |
| preserved_error=sys.exception(), |
| ) |
|
|
| stream_trace: dict[str, object] = { |
| "request_id": request_id, |
| "provider_id": routed.resolved.provider_id, |
| "gateway_model": gateway_model, |
| } |
| if self._generation_id is not None: |
| stream_trace["generation_id"] = self._generation_id |
|
|
| capture_stream: AsyncIterator[str] = provider_body() |
| if pending is not None: |
| capture_stream = UsageTrackingStream(capture_stream, pending) |
|
|
| return traced_async_stream( |
| capture_stream, |
| stage="egress", |
| source="api", |
| complete_event=( |
| "free_claude_code.api.responses.stream_completed" |
| if wire_api == "responses" |
| else "free_claude_code.api.response.stream_completed" |
| ), |
| interrupted_event=( |
| "free_claude_code.api.responses.stream_interrupted" |
| if wire_api == "responses" |
| else "free_claude_code.api.response.stream_interrupted" |
| ), |
| chunk_event=None, |
| extra=stream_trace, |
| ) |
|
|