Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
ARG PYTHON_IMAGE=3.13-slim@sha256:1020ca463dc51c26bbad49de85dbb2986d93b71050102f3fa2a7f0fc4c2ea81e
ARG PYTHON_IMAGE=3.14-slim@sha256:4ed33101ee7ec299041cc41dd268dae17031184be94384b1ce7936dc4e5dead3

# --------------- `base` stage ---------------
FROM python:${PYTHON_IMAGE} AS base
Expand Down
5 changes: 4 additions & 1 deletion eval/classifier.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import logging
import time
from concurrent.futures import ThreadPoolExecutor
from typing import TYPE_CHECKING

from lightman_ai.ai.base.agent import BaseAgent
from lightman_ai.ai.gemini.agent import GeminiAgent
from lightman_ai.ai.openai.agent import OpenAIAgent
from lightman_ai.article.models import Article, ArticlesList, SelectedArticle, SelectedArticlesList
Expand All @@ -11,6 +11,9 @@
from eval.constants import MAX_WORKERS, MISSED_ARTICLE_REASON, MISSED_ARTICLE_RELEVANCE_SCORE
from eval.utils import ClassifiedArticleResults

if TYPE_CHECKING:
from lightman_ai.ai.base.agent import BaseAgent

logger = logging.getLogger("eval")


Expand Down
5 changes: 4 additions & 1 deletion eval/evaluator.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import logging
from typing import TYPE_CHECKING

from lightman_ai.ai.utils import get_agent_class_from_agent_name
from lightman_ai.article.models import Article

from eval.classifier import Classifier
from eval.templates import ResultsFileBuilder
from eval.utils import ResultsMetrics

if TYPE_CHECKING:
from lightman_ai.article.models import Article

logger = logging.getLogger("eval")


Expand Down
7 changes: 5 additions & 2 deletions eval/templates.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import logging
from datetime import date
from decimal import Decimal
from pathlib import Path
from typing import TYPE_CHECKING

from eval.utils import ClassifiedArticleResults, ResultsMetrics
if TYPE_CHECKING:
from decimal import Decimal

from eval.utils import ClassifiedArticleResults, ResultsMetrics

RESULTS_DIR = "eval/results/"

Expand Down
11 changes: 7 additions & 4 deletions eval/utils.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import inspect
from collections.abc import Iterable
from dataclasses import dataclass
from decimal import Decimal
from typing import Any
from typing import TYPE_CHECKING, Any

from lightman_ai.article.models import SelectedArticle
from lightman_ai.core.config import FileConfig, FinalConfig
from lightman_ai.core.settings import Settings
from pydantic import PositiveInt
from pydantic import PositiveInt # noqa: TC002

if TYPE_CHECKING:
from collections.abc import Iterable

from lightman_ai.article.models import SelectedArticle


class EvalSettings(Settings):
Expand Down
2 changes: 1 addition & 1 deletion justfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# VARIABLE DEFINITIONS
venv := ".venv"
python_version :="3.13"
python_version :="3.14"
run := "uv run"
eval_path := "eval/cli.py"

Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ authors = [
{name = "sdn4z", email = "imsdn4z@gmail.com"},
{name = "scastlara", email = "s.cast.lara@gmail.com"}
]
requires-python = "<4,>=3.13"
requires-python = "==3.14.*"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • I would honestly leave it like it was, what do we gain by dropping 3.13 support? If we really want to drop support, then I would do like before <4,>=3.14, because pinning requires-python can be problematic, and does not reflect reality anyway (if it works on python 3.14, it will work on python 3.15).

  • If we decide to drop support for 3.13 in the end, then this is a breaking change.

dependencies = [
"httpx<1.0.0,>=0.28.0",
"python-dotenv<2.0.0,>=1.1.1",
Expand Down Expand Up @@ -60,7 +60,7 @@ asyncio_default_fixture_loop_scope = "session"


[tool.ruff]
target-version = "py312"
target-version = "py314"
line-length = 120
src = ["src", "tests"]

Expand Down
14 changes: 7 additions & 7 deletions src/lightman_ai/ai/base/agent.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
import logging
from abc import ABC, abstractmethod
from typing import Never
from typing import TYPE_CHECKING

from lightman_ai.article.models import SelectedArticlesList
from pydantic_ai import Agent
from pydantic_ai.models.google import GoogleModel
from pydantic_ai.models.openai import OpenAIModel

if TYPE_CHECKING:
from pydantic_ai.models.google import GoogleModel
from pydantic_ai.models.openai import OpenAIChatModel


class BaseAgent(ABC):
_class: type[OpenAIModel] | type[GoogleModel]
_class: type[OpenAIChatModel] | type[GoogleModel]
_default_model_name: str

def __init__(self, system_prompt: str, model: str | None = None, logger: logging.Logger | None = None) -> None:
agent_model = self._class(model or self._default_model_name)
self.agent: Agent[Never, SelectedArticlesList] = Agent(
model=agent_model, output_type=SelectedArticlesList, system_prompt=system_prompt
)
self.agent = Agent(model=agent_model, output_type=SelectedArticlesList, system_prompt=system_prompt)
self.logger = logger or logging.getLogger("lightman")

def get_prompt_result(self, prompt: str) -> SelectedArticlesList:
Expand Down
6 changes: 4 additions & 2 deletions src/lightman_ai/ai/gemini/agent.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
from typing import override
from typing import TYPE_CHECKING, override

from lightman_ai.ai.base.agent import BaseAgent
from lightman_ai.ai.gemini.exceptions import map_gemini_exceptions
from lightman_ai.article.models import SelectedArticlesList
from pydantic_ai.models.google import GoogleModel

if TYPE_CHECKING:
from lightman_ai.article.models import SelectedArticlesList


class GeminiAgent(BaseAgent):
"""Class that provides an interface to operate with the Gemini model."""
Expand Down
6 changes: 4 additions & 2 deletions src/lightman_ai/ai/gemini/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
from collections.abc import Generator
from contextlib import contextmanager
from typing import Any
from typing import TYPE_CHECKING, Any

from lightman_ai.core.exceptions import BaseLightmanError

if TYPE_CHECKING:
from collections.abc import Generator


class BaseGeminiError(BaseLightmanError): ...

Expand Down
12 changes: 7 additions & 5 deletions src/lightman_ai/ai/openai/agent.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import time
from typing import override
from typing import TYPE_CHECKING, override

from lightman_ai.ai.base.agent import BaseAgent
from lightman_ai.ai.openai.exceptions import LimitTokensExceededError, map_openai_exceptions
from lightman_ai.article.models import SelectedArticlesList
from pydantic_ai.agent import AgentRunResult
from pydantic_ai.models.openai import OpenAIModel
from pydantic_ai.models.openai import OpenAIChatModel

if TYPE_CHECKING:
from lightman_ai.article.models import SelectedArticlesList
from pydantic_ai.agent import AgentRunResult


class OpenAIAgent(BaseAgent):
"""Class that provides an interface to operate with the OpenAI model."""

_class = OpenAIModel
_class = OpenAIChatModel
_default_model_name = "gpt-4.1"

def _execute_agent(self, prompt: str) -> AgentRunResult[SelectedArticlesList]:
Expand Down
6 changes: 4 additions & 2 deletions src/lightman_ai/ai/openai/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import math
import re
from collections.abc import Generator
from contextlib import contextmanager
from typing import Any, override
from typing import TYPE_CHECKING, Any, override

from lightman_ai.core.exceptions import BaseLightmanError
from pydantic_ai.exceptions import ModelHTTPError

from openai import RateLimitError

if TYPE_CHECKING:
from collections.abc import Generator


class BaseOpenAIError(BaseLightmanError): ...

Expand Down
6 changes: 5 additions & 1 deletion src/lightman_ai/ai/utils.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
from lightman_ai.ai.base.agent import BaseAgent
from typing import TYPE_CHECKING

from lightman_ai.ai.gemini.agent import GeminiAgent
from lightman_ai.ai.openai.agent import OpenAIAgent

if TYPE_CHECKING:
from lightman_ai.ai.base.agent import BaseAgent

AGENT_MAPPING = {"openai": OpenAIAgent, "gemini": GeminiAgent}


Expand Down
2 changes: 1 addition & 1 deletion src/lightman_ai/article/models.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from abc import ABC
from datetime import datetime
from datetime import datetime # noqa: TC003
from typing import Self, override

from lightman_ai.article.exceptions import NoTimeZoneError
Expand Down
5 changes: 4 additions & 1 deletion src/lightman_ai/cli.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import logging
from datetime import date
from importlib import metadata
from typing import TYPE_CHECKING

import click
from dotenv import load_dotenv
Expand All @@ -14,6 +14,9 @@
from lightman_ai.main import lightman
from lightman_ai.utils import get_start_date

if TYPE_CHECKING:
from datetime import date

logger = logging.getLogger("lightman")


Expand Down
6 changes: 4 additions & 2 deletions src/lightman_ai/core/config.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import logging
from dataclasses import dataclass
from pathlib import Path
from typing import Any, Self, cast
from typing import TYPE_CHECKING, Any, Self, cast

import tomlkit
from lightman_ai.core.exceptions import ConfigNotFoundError, InvalidConfigError, PromptNotFoundError
from pydantic import BaseModel, ConfigDict, PositiveInt, ValidationError, field_validator
from pydantic_core.core_schema import FieldValidationInfo

if TYPE_CHECKING:
from pydantic_core.core_schema import FieldValidationInfo

PROMPTS_SECTION = "prompts"
logger = logging.getLogger("lightman")
Expand Down
6 changes: 4 additions & 2 deletions src/lightman_ai/integrations/service_desk/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import logging
from collections.abc import AsyncGenerator
from contextlib import asynccontextmanager
from typing import Any
from typing import TYPE_CHECKING, Any

import httpx
from lightman_ai.core.exceptions import BaseLightmanError

if TYPE_CHECKING:
from collections.abc import AsyncGenerator

logger = logging.getLogger("lightman")


Expand Down
10 changes: 7 additions & 3 deletions src/lightman_ai/main.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
import asyncio
import logging
from datetime import datetime
from typing import TYPE_CHECKING

from lightman_ai.ai.base.agent import BaseAgent
from lightman_ai.ai.utils import get_agent_class_from_agent_name
from lightman_ai.article.models import ArticlesList, SelectedArticle, SelectedArticlesList
from lightman_ai.integrations.service_desk.integration import (
ServiceDeskIntegration,
)
from lightman_ai.sources.the_hacker_news import TheHackerNewsSource

if TYPE_CHECKING:
from datetime import datetime

from lightman_ai.ai.base.agent import BaseAgent
from lightman_ai.article.models import ArticlesList, SelectedArticle, SelectedArticlesList

logger = logging.getLogger("lightman")


Expand Down
7 changes: 5 additions & 2 deletions src/lightman_ai/sources/base.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
from abc import ABC, abstractmethod
from datetime import datetime
from typing import TYPE_CHECKING

from lightman_ai.article.models import ArticlesList
if TYPE_CHECKING:
from datetime import datetime

from lightman_ai.article.models import ArticlesList


class BaseSource(ABC):
Expand Down
5 changes: 4 additions & 1 deletion src/lightman_ai/utils.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
from datetime import date, datetime, time, timedelta
from typing import TYPE_CHECKING
from zoneinfo import ZoneInfo

from lightman_ai.core.settings import Settings
from lightman_ai.exceptions import MultipleDateSourcesError

if TYPE_CHECKING:
from lightman_ai.core.settings import Settings


def get_start_date(settings: Settings, yesterday: bool, today: bool, start_date: date | None) -> datetime | None:
mutually_exclusive_date_fields = [x for x in [start_date, today, yesterday] if x]
Expand Down
11 changes: 7 additions & 4 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import os
from collections.abc import Generator, Iterator
from contextlib import contextmanager
from datetime import UTC, datetime
from typing import Any
from typing import TYPE_CHECKING, Any
from unittest.mock import AsyncMock, Mock, patch

import pytest
Expand All @@ -11,7 +10,11 @@
from lightman_ai.core.settings import Settings
from lightman_ai.integrations.service_desk.integration import ServiceDeskIntegration
from lightman_ai.sources.the_hacker_news import TheHackerNewsSource
from stamina._core import _RetryContextIterator

if TYPE_CHECKING:
from collections.abc import Generator, Iterator

from stamina._core import _RetryContextIterator


def pytest_configure() -> None:
Expand All @@ -20,7 +23,7 @@ def pytest_configure() -> None:


@pytest.fixture
def patch_service_desk_retry_wait_max() -> Generator[None, Any, None]:
def patch_service_desk_retry_wait_max() -> Generator[None, Any]:
original_retry_context = stamina.retry_context

def patched_retry_context(*args: Any, **kwargs: Any) -> _RetryContextIterator:
Expand Down
5 changes: 4 additions & 1 deletion tests/core/test_config.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import pathlib
from typing import TYPE_CHECKING

import pytest
from lightman_ai.constants import DEFAULT_CONFIG_FILE, DEFAULT_CONFIG_SECTION
Expand All @@ -7,6 +7,9 @@
from pydantic import ValidationError
from tests.conftest import patch_config_file

if TYPE_CHECKING:
import pathlib


class TestConfig:
def test_get_from_file(self) -> None:
Expand Down
8 changes: 5 additions & 3 deletions tests/utils.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
from collections.abc import Generator, Iterator
from contextlib import contextmanager
from typing import Any
from typing import TYPE_CHECKING, Any
from unittest.mock import AsyncMock, MagicMock, Mock, patch

from lightman_ai.article.models import Article, SelectedArticlesList
if TYPE_CHECKING:
from collections.abc import Generator, Iterator

from lightman_ai.article.models import Article, SelectedArticlesList


@contextmanager
Expand Down
Loading
Loading