feat!: migrate to OpenAI native tool calls and fix circular deps (#fuck-gemini)
- Fix circular dependencies in agent/tools - Migrate from custom JSON to OpenAI tool calls format - Add async streaming (step_stream, complete_stream) - Simplify prompt system and remove token counting - Add 5 new API endpoints (/health, /v1/models, /api/memory/*) - Add 3 new tools (get_torrent_by_index, add_torrent_by_index, set_language) - Fix all 500 tests and add coverage config (80% threshold) - Add comprehensive docs (README, pytest guide) BREAKING: LLM interface changed, memory injection via get_memory()
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
"""Movie use cases."""
|
||||
from .search_movie import SearchMovieUseCase
|
||||
|
||||
from .dto import SearchMovieResponse
|
||||
from .search_movie import SearchMovieUseCase
|
||||
|
||||
__all__ = [
|
||||
"SearchMovieUseCase",
|
||||
|
||||
+14
-13
@@ -1,26 +1,27 @@
|
||||
"""Movie application DTOs."""
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Optional
|
||||
|
||||
|
||||
@dataclass
|
||||
class SearchMovieResponse:
|
||||
"""Response from searching for a movie."""
|
||||
|
||||
status: str
|
||||
imdb_id: Optional[str] = None
|
||||
title: Optional[str] = None
|
||||
media_type: Optional[str] = None
|
||||
tmdb_id: Optional[int] = None
|
||||
overview: Optional[str] = None
|
||||
release_date: Optional[str] = None
|
||||
vote_average: Optional[float] = None
|
||||
error: Optional[str] = None
|
||||
message: Optional[str] = None
|
||||
|
||||
imdb_id: str | None = None
|
||||
title: str | None = None
|
||||
media_type: str | None = None
|
||||
tmdb_id: int | None = None
|
||||
overview: str | None = None
|
||||
release_date: str | None = None
|
||||
vote_average: float | None = None
|
||||
error: str | None = None
|
||||
message: str | None = None
|
||||
|
||||
def to_dict(self):
|
||||
"""Convert to dict for agent compatibility."""
|
||||
result = {"status": self.status}
|
||||
|
||||
|
||||
if self.error:
|
||||
result["error"] = self.error
|
||||
result["message"] = self.message
|
||||
@@ -39,5 +40,5 @@ class SearchMovieResponse:
|
||||
result["release_date"] = self.release_date
|
||||
if self.vote_average:
|
||||
result["vote_average"] = self.vote_average
|
||||
|
||||
|
||||
return result
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
"""Search movie use case."""
|
||||
import logging
|
||||
from typing import Optional
|
||||
|
||||
from infrastructure.api.tmdb import TMDBClient, TMDBNotFoundError, TMDBAPIError, TMDBConfigurationError
|
||||
import logging
|
||||
|
||||
from infrastructure.api.tmdb import (
|
||||
TMDBAPIError,
|
||||
TMDBClient,
|
||||
TMDBConfigurationError,
|
||||
TMDBNotFoundError,
|
||||
)
|
||||
|
||||
from .dto import SearchMovieResponse
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -11,33 +17,33 @@ logger = logging.getLogger(__name__)
|
||||
class SearchMovieUseCase:
|
||||
"""
|
||||
Use case for searching a movie and retrieving its IMDb ID.
|
||||
|
||||
|
||||
This orchestrates the TMDB API client to find movie information.
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self, tmdb_client: TMDBClient):
|
||||
"""
|
||||
Initialize use case.
|
||||
|
||||
|
||||
Args:
|
||||
tmdb_client: TMDB API client
|
||||
"""
|
||||
self.tmdb_client = tmdb_client
|
||||
|
||||
|
||||
def execute(self, media_title: str) -> SearchMovieResponse:
|
||||
"""
|
||||
Search for a movie by title.
|
||||
|
||||
|
||||
Args:
|
||||
media_title: Title of the movie to search for
|
||||
|
||||
|
||||
Returns:
|
||||
SearchMovieResponse with movie information or error
|
||||
"""
|
||||
try:
|
||||
# Use the TMDB client to search for media
|
||||
result = self.tmdb_client.search_media(media_title)
|
||||
|
||||
|
||||
# Check if IMDb ID was found
|
||||
if result.imdb_id:
|
||||
logger.info(f"IMDb ID found for '{media_title}': {result.imdb_id}")
|
||||
@@ -49,7 +55,7 @@ class SearchMovieUseCase:
|
||||
tmdb_id=result.tmdb_id,
|
||||
overview=result.overview,
|
||||
release_date=result.release_date,
|
||||
vote_average=result.vote_average
|
||||
vote_average=result.vote_average,
|
||||
)
|
||||
else:
|
||||
logger.warning(f"No IMDb ID available for '{media_title}'")
|
||||
@@ -59,37 +65,29 @@ class SearchMovieUseCase:
|
||||
media_type=result.media_type,
|
||||
tmdb_id=result.tmdb_id,
|
||||
error="no_imdb_id",
|
||||
message=f"No IMDb ID available for '{result.title}'"
|
||||
message=f"No IMDb ID available for '{result.title}'",
|
||||
)
|
||||
|
||||
|
||||
except TMDBNotFoundError as e:
|
||||
logger.info(f"Media not found: {e}")
|
||||
return SearchMovieResponse(
|
||||
status="error",
|
||||
error="not_found",
|
||||
message=str(e)
|
||||
status="error", error="not_found", message=str(e)
|
||||
)
|
||||
|
||||
|
||||
except TMDBConfigurationError as e:
|
||||
logger.error(f"TMDB configuration error: {e}")
|
||||
return SearchMovieResponse(
|
||||
status="error",
|
||||
error="configuration_error",
|
||||
message=str(e)
|
||||
status="error", error="configuration_error", message=str(e)
|
||||
)
|
||||
|
||||
|
||||
except TMDBAPIError as e:
|
||||
logger.error(f"TMDB API error: {e}")
|
||||
return SearchMovieResponse(
|
||||
status="error",
|
||||
error="api_error",
|
||||
message=str(e)
|
||||
status="error", error="api_error", message=str(e)
|
||||
)
|
||||
|
||||
|
||||
except ValueError as e:
|
||||
logger.error(f"Validation error: {e}")
|
||||
return SearchMovieResponse(
|
||||
status="error",
|
||||
error="validation_failed",
|
||||
message=str(e)
|
||||
status="error", error="validation_failed", message=str(e)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user