fix: forgot to lint/format
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
"""Agent module for media library management."""
|
||||
|
||||
from .agent import Agent
|
||||
from alfred.settings import settings
|
||||
|
||||
from .agent import Agent
|
||||
|
||||
__all__ = ["Agent", "settings"]
|
||||
|
||||
@@ -6,8 +6,8 @@ from collections.abc import AsyncGenerator
|
||||
from typing import Any
|
||||
|
||||
from alfred.infrastructure.persistence import get_memory
|
||||
|
||||
from alfred.settings import settings
|
||||
|
||||
from .prompts import PromptBuilder
|
||||
from .registry import Tool, make_tools
|
||||
|
||||
|
||||
@@ -6,7 +6,8 @@ from typing import Any
|
||||
import requests
|
||||
from requests.exceptions import HTTPError, RequestException, Timeout
|
||||
|
||||
from alfred.settings import settings, Settings
|
||||
from alfred.settings import Settings, settings
|
||||
|
||||
from .exceptions import LLMAPIError, LLMConfigurationError
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
"""Ollama LLM client with robust error handling."""
|
||||
|
||||
import logging
|
||||
import os
|
||||
from typing import Any
|
||||
|
||||
import requests
|
||||
from requests.exceptions import HTTPError, RequestException, Timeout
|
||||
|
||||
from alfred.settings import Settings, settings
|
||||
from alfred.settings import Settings
|
||||
|
||||
from .exceptions import LLMAPIError, LLMConfigurationError
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -2,23 +2,21 @@
|
||||
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import time
|
||||
import uuid
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from fastapi import FastAPI, HTTPException
|
||||
from fastapi.responses import JSONResponse, StreamingResponse
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from pathlib import Path
|
||||
from pydantic import BaseModel, Field, validator
|
||||
|
||||
from alfred.agent.agent import Agent
|
||||
from alfred.agent.llm.deepseek import DeepSeekClient
|
||||
from alfred.agent.llm.exceptions import LLMAPIError, LLMConfigurationError
|
||||
from alfred.agent.llm.ollama import OllamaClient
|
||||
from alfred.settings import settings
|
||||
from alfred.infrastructure.persistence import get_memory, init_memory
|
||||
from alfred.settings import settings
|
||||
|
||||
logging.basicConfig(
|
||||
level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
||||
@@ -55,7 +53,9 @@ except LLMConfigurationError as e:
|
||||
raise
|
||||
|
||||
# Initialize agent
|
||||
agent = Agent(settings=settings, llm=llm, max_tool_iterations=settings.max_tool_iterations)
|
||||
agent = Agent(
|
||||
settings=settings, llm=llm, max_tool_iterations=settings.max_tool_iterations
|
||||
)
|
||||
logger.info("Agent Media API initialized")
|
||||
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import secrets
|
||||
import tomllib
|
||||
from pathlib import Path
|
||||
from typing import NamedTuple
|
||||
|
||||
import tomllib
|
||||
from pydantic import Field, computed_field, field_validator
|
||||
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||
from typing import NamedTuple, Optional
|
||||
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
ENV_FILE_PATH = BASE_DIR / ".env"
|
||||
@@ -12,13 +13,16 @@ toml_path = BASE_DIR / "pyproject.toml"
|
||||
|
||||
class ConfigurationError(Exception):
|
||||
"""Raised when configuration is invalid."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class ProjectVersions(NamedTuple):
|
||||
"""
|
||||
Immutable structure for project versions.
|
||||
Forces explicit naming and prevents accidental swaps.
|
||||
"""
|
||||
|
||||
librechat: str
|
||||
rag: str
|
||||
|
||||
@@ -37,20 +41,22 @@ def get_versions_from_toml() -> ProjectVersions:
|
||||
try:
|
||||
return ProjectVersions(
|
||||
librechat=data["tool"]["alfred"]["settings"]["librechat_version"],
|
||||
rag = data["tool"]["alfred"]["settings"]["rag_version"]
|
||||
rag=data["tool"]["alfred"]["settings"]["rag_version"],
|
||||
)
|
||||
except KeyError as e:
|
||||
raise KeyError(f"Error: Missing key {e} in pyproject.toml")
|
||||
raise KeyError(f"Error: Missing key {e} in pyproject.toml") from e
|
||||
|
||||
|
||||
# Load versions once
|
||||
VERSIONS: ProjectVersions = get_versions_from_toml()
|
||||
|
||||
|
||||
class Settings(BaseSettings):
|
||||
model_config = SettingsConfigDict(
|
||||
env_file=ENV_FILE_PATH,
|
||||
env_file_encoding="utf-8",
|
||||
extra="ignore",
|
||||
case_sensitive=False
|
||||
case_sensitive=False,
|
||||
)
|
||||
# --- GENERAL SETTINGS ---
|
||||
host: str = "0.0.0.0"
|
||||
@@ -71,11 +77,11 @@ class Settings(BaseSettings):
|
||||
deepseek_model: str = "deepseek-chat"
|
||||
|
||||
# --- API KEYS ---
|
||||
anthropic_api_key: Optional[str] = Field(None, description="Claude API key")
|
||||
deepseek_api_key: Optional[str] = Field(None, description="Deepseek API key")
|
||||
google_api_key: Optional[str] = Field(None, description="Gemini API key")
|
||||
kimi_api_key: Optional[str] = Field(None, description="Kimi API key")
|
||||
openai_api_key: Optional[str] = Field(None, description="ChatGPT API key")
|
||||
anthropic_api_key: str | None = Field(None, description="Claude API key")
|
||||
deepseek_api_key: str | None = Field(None, description="Deepseek API key")
|
||||
google_api_key: str | None = Field(None, description="Gemini API key")
|
||||
kimi_api_key: str | None = Field(None, description="Kimi API key")
|
||||
openai_api_key: str | None = Field(None, description="ChatGPT API key")
|
||||
|
||||
# --- SECURITY KEYS ---
|
||||
# Generated automatically if not in .env to ensure "Secure by Default"
|
||||
@@ -93,8 +99,9 @@ class Settings(BaseSettings):
|
||||
|
||||
mongo_host: str = "mongodb"
|
||||
mongo_user: str = "alfred"
|
||||
mongo_password: str = Field(default_factory=lambda: secrets.token_urlsafe(24),
|
||||
repr=False, exclude=True)
|
||||
mongo_password: str = Field(
|
||||
default_factory=lambda: secrets.token_urlsafe(24), repr=False, exclude=True
|
||||
)
|
||||
mongo_port: int = 27017
|
||||
mongo_db_name: str = "alfred"
|
||||
|
||||
@@ -109,8 +116,9 @@ class Settings(BaseSettings):
|
||||
|
||||
postgres_host: str = "vectordb"
|
||||
postgres_user: str = "alfred"
|
||||
postgres_password: str = Field(default_factory=lambda: secrets.token_urlsafe(24),
|
||||
repr=False, exclude=True)
|
||||
postgres_password: str = Field(
|
||||
default_factory=lambda: secrets.token_urlsafe(24), repr=False, exclude=True
|
||||
)
|
||||
postgres_port: int = 5432
|
||||
postgres_db_name: str = "alfred"
|
||||
|
||||
@@ -122,7 +130,7 @@ class Settings(BaseSettings):
|
||||
f"@{self.postgres_host}:{self.postgres_port}/{self.postgres_db_name}"
|
||||
)
|
||||
|
||||
tmdb_api_key: Optional[str] = Field(None, description="The Movie Database API key")
|
||||
tmdb_api_key: str | None = Field(None, description="The Movie Database API key")
|
||||
tmdb_base_url: str = "https://api.themoviedb.org/3"
|
||||
|
||||
# --- LLM PICKER & CONFIG ---
|
||||
@@ -147,7 +155,7 @@ class Settings(BaseSettings):
|
||||
meili_master_key: str = Field(
|
||||
default_factory=lambda: secrets.token_urlsafe(32),
|
||||
description="Master key for Meilisearch",
|
||||
repr=False
|
||||
repr=False,
|
||||
)
|
||||
|
||||
# --- VALIDATORS ---
|
||||
@@ -155,21 +163,27 @@ class Settings(BaseSettings):
|
||||
@classmethod
|
||||
def validate_temperature(cls, v: float) -> float:
|
||||
if not 0.0 <= v <= 2.0:
|
||||
raise ConfigurationError(f"Temperature must be between 0.0 and 2.0, got {v}")
|
||||
raise ConfigurationError(
|
||||
f"Temperature must be between 0.0 and 2.0, got {v}"
|
||||
)
|
||||
return v
|
||||
|
||||
@field_validator("max_tool_iterations")
|
||||
@classmethod
|
||||
def validate_max_iterations(cls, v: int) -> int:
|
||||
if not 1 <= v <= 20:
|
||||
raise ConfigurationError(f"max_tool_iterations must be between 1 and 50, got {v}")
|
||||
raise ConfigurationError(
|
||||
f"max_tool_iterations must be between 1 and 50, got {v}"
|
||||
)
|
||||
return v
|
||||
|
||||
@field_validator("request_timeout")
|
||||
@classmethod
|
||||
def validate_timeout(cls, v: int) -> int:
|
||||
if not 1 <= v <= 300:
|
||||
raise ConfigurationError(f"request_timeout must be between 1 and 300 seconds, got {v}")
|
||||
raise ConfigurationError(
|
||||
f"request_timeout must be between 1 and 300 seconds, got {v}"
|
||||
)
|
||||
return v
|
||||
|
||||
@field_validator("deepseek_base_url", "tmdb_base_url")
|
||||
@@ -188,4 +202,5 @@ class Settings(BaseSettings):
|
||||
def dump_safe(self):
|
||||
return self.model_dump(exclude_none=False)
|
||||
|
||||
|
||||
settings = Settings()
|
||||
|
||||
@@ -11,9 +11,8 @@ from unittest.mock import MagicMock, Mock
|
||||
|
||||
import pytest
|
||||
|
||||
from alfred.settings import Settings, settings
|
||||
from alfred.infrastructure.persistence import Memory, set_memory
|
||||
|
||||
from alfred.settings import settings
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
from unittest.mock import Mock
|
||||
|
||||
from conftest import mock_llm
|
||||
from alfred.agent.agent import Agent
|
||||
from alfred.infrastructure.persistence import get_memory
|
||||
|
||||
@@ -142,7 +141,9 @@ class TestStep:
|
||||
assert history[0]["content"] == "Hi there"
|
||||
assert history[1]["role"] == "assistant"
|
||||
|
||||
def test_step_with_tool_call(self, memory, mock_settings, mock_llm_with_tool_call, real_folder):
|
||||
def test_step_with_tool_call(
|
||||
self, memory, mock_settings, mock_llm_with_tool_call, real_folder
|
||||
):
|
||||
"""Should execute tool and continue."""
|
||||
memory.ltm.set_config("download_folder", str(real_folder["downloads"]))
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ import pytest
|
||||
from alfred.agent.agent import Agent
|
||||
from alfred.infrastructure.persistence import get_memory
|
||||
from alfred.settings import settings
|
||||
from conftest import mock_llm
|
||||
|
||||
|
||||
class TestExecuteToolCallEdgeCases:
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
"""Edge case tests for FastAPI endpoints."""
|
||||
|
||||
import pytest
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
import pytest
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import pytest
|
||||
|
||||
from alfred.settings import Settings, ConfigurationError
|
||||
from alfred.settings import ConfigurationError, Settings
|
||||
|
||||
|
||||
class TestConfigValidation:
|
||||
|
||||
@@ -5,13 +5,13 @@ from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from alfred.settings import Settings, ConfigurationError
|
||||
from alfred.agent.parameters import (
|
||||
REQUIRED_PARAMETERS,
|
||||
ParameterSchema,
|
||||
format_parameters_for_prompt,
|
||||
get_missing_required_parameters,
|
||||
)
|
||||
from alfred.settings import ConfigurationError, Settings
|
||||
|
||||
|
||||
class TestSettingsEdgeCases:
|
||||
|
||||
@@ -4,6 +4,7 @@ from alfred.agent.prompts import PromptBuilder
|
||||
from alfred.agent.registry import make_tools
|
||||
from alfred.settings import settings
|
||||
|
||||
|
||||
class TestPromptBuilderEdgeCases:
|
||||
"""Edge case tests for PromptBuilder."""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user