"""Wire schemas for the discovery API: requests and streamed events.""" from typing import Literal from pydantic import BaseModel, Field NDJSON_CONTENT_TYPE = "application/x-ndjson" class HistoryTurn(BaseModel): """One prior chat turn; conversation state lives client-side.""" role: Literal["user", "assistant"] content: str = Field(min_length=1, max_length=2000) class PriorRecommendation(BaseModel): """A track from an earlier response that follow-up turns can refer to.""" rank: int = Field(ge=1, le=50) track_id: str title: str artists: list[str] = Field(max_length=10) class RecommendationRequest(BaseModel): """A discovery query with bounded client-side conversation state.""" schema_version: Literal[1] = 1 query: str = Field(min_length=1, max_length=1000) history: list[HistoryTurn] = Field(default_factory=list, max_length=12) prior_recommendations: list[PriorRecommendation] = Field(default_factory=list, max_length=50) class TrackCard(BaseModel): """The wire shape of one recommended track.""" id: str uri: str title: str artists: list[str] album_name: str album_art_url: str | None external_url: str | None class MetadataEvent(BaseModel): """First stream event: how the query was understood.""" type: Literal["metadata"] = "metadata" request_id: str intent_summary: str candidate_count: int class TrackEvent(BaseModel): """One recommended track, streamed as soon as it validates.""" type: Literal["track"] = "track" rank: int track: TrackCard justification: str class WarningEvent(BaseModel): """A non-fatal degradation, surfaced honestly instead of hidden.""" type: Literal["warning"] = "warning" code: str message: str class ErrorEvent(BaseModel): """A terminal failure; no further events follow it.""" type: Literal["error"] = "error" code: str message: str class DoneEvent(BaseModel): """Final stream event with response-level counters.""" type: Literal["done"] = "done" track_count: int total_ms: int StreamEvent = MetadataEvent | TrackEvent | WarningEvent | ErrorEvent | DoneEvent class PlaylistCreateRequest(BaseModel): """A request to save recommended tracks as a real Spotify playlist.""" schema_version: Literal[1] = 1 name: str = Field(min_length=1, max_length=100) track_uris: list[str] = Field(min_length=1, max_length=50) class PlaylistCreateResponse(BaseModel): """The created playlist's public location.""" url: str