38 Commits

Author SHA1 Message Date
francwa fed83e7d79 chore: bumped fastapi version 2025-12-27 19:42:16 +01:00
francwa 3880a4ec49 chore: ran linter and formatter 2025-12-27 19:41:22 +01:00
francwa 6195abbaa5 chore: fixed imports and tests configuration 2025-12-27 19:39:36 +01:00
francwa b132554631 infra: updated .gitignore 2025-12-27 02:30:14 +01:00
francwa 561796cec1 infra: removed CORE_DIR variable from Makefile (not relevant anymore) 2025-12-24 11:28:28 +01:00
francwa 26d90acc16 infra: moved manifest files in librechat dir 2025-12-24 09:46:25 +01:00
francwa d8234b2958 chore: cleaned up .env.example 2025-12-24 08:17:47 +01:00
francwa 156d1fe567 fix: fixed Dockerfile 2025-12-24 08:17:12 +01:00
francwa f8eee120cf infra: backed up old deploy-compose 2025-12-24 08:16:30 +01:00
francwa c5e4a5e1a7 infra: removed occurences of alfred_api_key (not implemented after all) 2025-12-24 08:11:30 +01:00
francwa d10c9160f3 infra: renamed broken references to alfred 2025-12-24 08:09:26 +01:00
francwa 1f88e99e8b infra: reorganized repo 2025-12-24 07:50:09 +01:00
francwa e097a13221 chore: upgraded to python 3.14 and some dependencies
Reviewed-on: francwa/agent_media#8
2025-12-22 14:04:46 +00:00
francwa 086fff803d feat: configured CI/CD pipeline to allow build for feature branches 2025-12-22 14:48:50 +01:00
francwa 45fbf975b3 feat: improved rules for renovate 2025-12-22 14:25:16 +01:00
francwa b8f2798e29 chore: updated fastapi and uvicorn 2025-12-22 14:20:22 +01:00
francwa c762d91eb1 chore: updated to python 3.14 2025-12-22 14:08:27 +01:00
francwa 35a68387ab infra: use python version from pyproject.toml 2025-12-22 13:46:40 +01:00
francwa 9b13c69631 chore: updated meilisearch 2025-12-22 13:25:54 +01:00
francwa 2ca1ea29b2 infra: added meilisearch to renovate exclusion list 2025-12-22 13:22:55 +01:00
francwa 5e86615bde fix: added renovate token with proper permissions 2025-12-22 12:59:24 +01:00
francwa 6701a4b392 infra: added Renovate bot 2025-12-22 12:50:59 +01:00
francwa 68372405d6 fix: downgraded upload-artifact action to v3 from v4 2025-12-22 12:13:50 +01:00
francwa f1ea0de247 fix: fixed indentation error 2025-12-22 12:04:47 +01:00
francwa 974d008825 feat: finalized CI/CD pipeline setup 2025-12-22 11:59:36 +01:00
francwa 8a87d94e6d fix: use docker image for trivy vulnerability scanner
CI/CD Awesome Pipeline / Test (push) Successful in 1m23s
CI/CD Awesome Pipeline / Build & Push to Registry (push) Failing after 5m9s
2025-12-22 11:38:35 +01:00
francwa ec99a501fc fix! added directive to Dockerfile 2025-12-22 11:37:48 +01:00
francwa c256b26601 fix: fixed vulnerability scanner issue in CI/CD pipeline
CI/CD Awesome Pipeline / Test (push) Successful in 48s
CI/CD Awesome Pipeline / Build & Push to Registry (push) Failing after 6m18s
2025-12-22 10:59:34 +01:00
francwa 56a3c1257d infra: added trivy vulnerability scanner to CI/CD
CI/CD Awesome Pipeline / Test (push) Successful in 1m36s
CI/CD Awesome Pipeline / Build & Push to Registry (push) Failing after 7m10s
2025-12-22 10:01:52 +01:00
francwa 79d23f936a fix: fixed typo 2025-12-22 09:40:43 +01:00
francwa f02e916d33 fix: fixed config gathering in ci.yml
CI/CD Awesome Pipeline / Test (push) Successful in 1m34s
CI/CD Awesome Pipeline / Build & Push to Registry (push) Failing after 14m19s
2025-12-22 09:16:55 +01:00
francwa 4e64c83c4b fix: updated build and push CI/CD configuration
CI/CD Awesome Pipeline / Test (push) Successful in 1m4s
CI/CD Awesome Pipeline / Build & Push to Registry (push) Failing after 2m32s
2025-12-22 08:45:31 +01:00
francwa 07cae9abd1 chore: bump version 0.1.5 → 0.1.6
CI/CD Awesome Pipeline / Test (push) Successful in 1m23s
CI/CD Awesome Pipeline / Build & Push to Registry (push) Successful in 1m4s
2025-12-21 13:54:02 +01:00
francwa 21b2dffc37 fix: added gitea token 2025-12-21 13:53:49 +01:00
francwa 2d1055cccf chore: bump version 0.1.4 → 0.1.5
CI/CD Awesome Pipeline / Test (push) Successful in 40s
CI/CD Awesome Pipeline / Build & Push to Registry (push) Failing after 20s
2025-12-21 13:01:37 +01:00
francwa fdb2447862 debug: tired 2025-12-21 13:01:23 +01:00
francwa 13746ee8cc chore: bump version 0.1.3 → 0.1.4
CI/CD Awesome Pipeline / Test (push) Successful in 37s
CI/CD Awesome Pipeline / Build & Push to Registry (push) Failing after 24s
2025-12-21 12:58:36 +01:00
francwa 49f31e492f debug: boring 2025-12-21 12:58:17 +01:00
121 changed files with 464 additions and 436 deletions
@@ -1,5 +1,5 @@
[tool.bumpversion]
current_version = "0.1.3"
current_version = "0.1.6"
parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)"
serialize = ["{major}.{minor}.{patch}"]
search = "{current_version}"
-4
View File
@@ -41,10 +41,6 @@ docs/
*.md
!README.md
# Tests
tests/
pytest.ini
# Data (will be mounted as volumes)
memory_data/
logs/
+6 -52
View File
@@ -1,68 +1,22 @@
# Agent Media - Environment Variables
# LibreChat Security Keys
# Generate secure keys with: openssl rand -base64 32
JWT_SECRET=your-super-secret-jwt-key-change-this-in-production
JWT_REFRESH_SECRET=your-super-secret-refresh-key-change-this-too
# Generate with: openssl rand -hex 16 (for CREDS_KEY)
CREDS_KEY=your-32-character-secret-key-here
# Generate with: openssl rand -hex 8 (for CREDS_IV)
CREDS_IV=your-16-character-iv-here
# LibreChat Configuration
DOMAIN_CLIENT=http://localhost:3080
DOMAIN_SERVER=http://localhost:3080
# Session expiry (in milliseconds)
# Default: 15 minutes
SESSION_EXPIRY=900000
# Refresh token expiry (in milliseconds)
# Default: 7 days
REFRESH_TOKEN_EXPIRY=604800000
# Meilisearch Configuration
# Master key for Meilisearch (generate with: openssl rand -base64 32)
MEILI_MASTER_KEY=DrhYf7zENyR6AlUCKmnz0eYASOQdl6zxH7s7MKFSfFU
# PostgreSQL Configuration (for RAG API)
POSTGRES_DB=librechat_rag
POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres
# RAG API Configuration (Vector Database)
RAG_COLLECTION_NAME=testcollection
RAG_EMBEDDINGS_PROVIDER=openai
RAG_EMBEDDINGS_MODEL=text-embedding-3-small
# API Keys
# OpenAI API Key (required for RAG embeddings)
OPENAI_API_KEY=your-openai-api-key-here
# Deepseek API Key (for LLM in agent-brain)
DEEPSEEK_API_KEY=your-deepseek-api-key-here
# Agent Brain Configuration
# Deepseek API Key (for LLM in alfred)
DEEPSEEK_API_KEY=
# Alfred Configuration
# LLM Provider (deepseek or ollama)
LLM_PROVIDER=deepseek
# Memory storage directory (inside container)
MEMORY_STORAGE_DIR=/data/memory
# API Key for agent-brain (used by LibreChat custom endpoint)
AGENT_BRAIN_API_KEY=agent-brain-secret-key
# External Services (Optional)
# TMDB API Key (for movie metadata)
TMDB_API_KEY=your-tmdb-key
TMDB_API_KEY=
# qBittorrent Configuration
QBITTORRENT_URL=http://localhost:8080
QBITTORRENT_URL=
QBITTORRENT_USERNAME=admin
QBITTORRENT_PASSWORD=adminpass
QBITTORRENT_PASSWORD=adminadmin
# Debug Options
DEBUG_LOGGING=false
+51 -25
View File
@@ -2,11 +2,10 @@ name: CI/CD Awesome Pipeline
on:
push:
branches: [main]
tags:
- 'v*.*.*'
pull_request:
branches: [main]
workflow_dispatch:
env:
REGISTRY_URL: ${{ vars.REGISTRY_URL || 'gitea.iswearihadsomethingforthis.net' }}
@@ -30,34 +29,61 @@ jobs:
name: Build & Push to Registry
runs-on: ubuntu-latest
needs: test
if: github.ref_type == 'tag' && startsWith(github.ref_name, 'v')
steps:
- name: Debug ref
run: |
echo "github.ref = ${{ github.ref }}"
echo "github.ref_type = ${{ github.ref_type }}"
echo "github.ref_name = ${{ github.ref_name }}"
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Load config from Makefile
id: config
run: |
eval "$(make _ci-image-name)"
echo "image_name=${IMAGE_NAME}" >> $GITHUB_OUTPUT
run: make -s _ci-dump-config >> $GITHUB_OUTPUT
- name: Extract version from tag
id: version
run: echo "version=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
- name: 🏷️ Docker Metadata (Tags & Labels)
id: meta
uses: docker/metadata-action@v5
with:
images: gitea.iswearihadsomethingforthis.net/francwa/${{ steps.config.outputs.image_name }}
tags: |
# Tagged (v1.2.3)
type=semver,pattern={{ version }}
# Latest (main)
type=raw,value=latest,enable={{ is_default_branch }}
# Feature branches
type=ref,event=branch
- name: Build production image
run: make build
- name: Login to Gitea Registry
uses: docker/login-action@v3
with:
registry: gitea.iswearihadsomethingforthis.net
username: ${{ gitea.actor }}
password: ${{ secrets.G1T34_TOKEN }}
- name: Tag and push to registry
run: |
docker tag ${{ steps.config.outputs.image_name }}:latest ${{ env.REGISTRY_URL }}/${{ env.REGISTRY_USER }}/${{ steps.config.outputs.image_name }}:${{ steps.version.outputs.version }}
docker tag ${{ steps.config.outputs.image_name }}:latest ${{ env.REGISTRY_URL }}/${{ env.REGISTRY_USER }}/${{ steps.config.outputs.image_name }}:latest
echo "${{ secrets.GITEA_TOKEN }}" | docker login ${{ env.REGISTRY_URL }} -u ${{ env.REGISTRY_USER }} --password-stdin
docker push ${{ env.REGISTRY_URL }}/${{ env.REGISTRY_USER }}/${{ steps.config.outputs.image_name }}:${{ steps.version.outputs.version }}
docker push ${{ env.REGISTRY_URL }}/${{ env.REGISTRY_USER }}/${{ steps.config.outputs.image_name }}:latest
- name: Build and push
id: docker_build
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
PYTHON_VERSION=${{ steps.config.outputs.python_version }}
PYTHON_VERSION_SHORT=${{ steps.config.outputs.python_version_short }}
RUNNER=${{ steps.config.outputs.runner }}
- name: 🛡️ Run Trivy Vulnerability Scanner
uses: docker://aquasec/trivy:latest
env:
TRIVY_USERNAME: ${{ gitea.actor }}
TRIVY_PASSWORD: ${{ secrets.G1T34_TOKEN }}
# Unset the fake GITHUB_TOKEN injected by Gitea
GITHUB_TOKEN: ""
with:
args: image --format table --output trivy-report.txt --exit-code 0 --ignore-unfixed --severity CRITICAL,HIGH gitea.iswearihadsomethingforthis.net/francwa/${{ steps.config.outputs.image_name }}:latest
- name: 📤 Upload Security Report
uses: actions/upload-artifact@v3
with:
name: security-report
path: trivy-report.txt
retention-days: 7
+22
View File
@@ -0,0 +1,22 @@
name: Renovate Bot
on:
schedule:
# Every Monday 4AM
- cron: '0 4 * * 1'
workflow_dispatch:
jobs:
renovate:
runs-on: ubuntu-latest
steps:
- name: Run Renovate
uses: docker://renovate/renovate:latest
env:
RENOVATE_PLATFORM: "gitea"
RENOVATE_ENDPOINT: "https://gitea.iswearihadsomethingforthis.net/api/v1"
RENOVATE_TOKEN: "${{ secrets.RENOVATE_TOKEN }}"
RENOVATE_REPOSITORIES: '["${{ gitea.repository }}"]'
RENOVATE_GIT_AUTHOR: "Renovate Bot <renovate@bot.local>"
# Might need a free github token if lots of depencies
# RENOVATE_GITHUB_TOKEN: "${{ secrets.GITHUB_COM_TOKEN }}"
+6
View File
@@ -59,3 +59,9 @@ Thumbs.db
# Backup files
*.backup
# Application data dir
data/*
# Application logs
logs/*
+8 -15
View File
@@ -1,5 +1,6 @@
# Dockerfile for Agent Media
# Multi-stage build for smaller image size
# syntax=docker/dockerfile:1
# check=skip=InvalidDefaultArgInFrom
ARG PYTHON_VERSION
ARG PYTHON_VERSION_SHORT
ARG RUNNER
@@ -29,7 +30,7 @@ RUN --mount=type=cache,target=/root/.cache/pip \
WORKDIR /tmp
# Copy dependency files
COPY brain/pyproject.toml brain/poetry.lock* brain/uv.lock* Makefile ./
COPY pyproject.toml poetry.lock* uv.lock* Makefile ./
# Install dependencies as root (to avoid permission issues with system packages)
RUN --mount=type=cache,target=/root/.cache/pip \
@@ -58,12 +59,8 @@ RUN --mount=type=cache,target=/root/.cache/pip \
uv pip install --system -e .[dev]; \
fi
COPY brain/agent/ ./agent/
COPY brain/application/ ./application/
COPY brain/domain/ ./domain/
COPY brain/infrastructure/ ./infrastructure/
COPY brain/tests/ ./tests/
COPY brain/app.py .
COPY alfred/ ./alfred
COPY tests/ ./tests
# ===========================================
# Stage 3: Runtime
@@ -95,18 +92,14 @@ RUN mkdir -p /data/memory /data/logs \
USER appuser
# Set working directory (owned by appuser)
WORKDIR /home/appuser/app
WORKDIR /home/appuser
# Copy Python packages from builder stage
COPY --from=builder /usr/local/lib/python${PYTHON_VERSION_SHORT}/site-packages /usr/local/lib/python${PYTHON_VERSION_SHORT}/site-packages
COPY --from=builder /usr/local/bin /usr/local/bin
# Copy application code (already owned by appuser)
COPY --chown=appuser:appuser brain/agent/ ./agent/
COPY --chown=appuser:appuser brain/application/ ./application/
COPY --chown=appuser:appuser brain/domain/ ./domain/
COPY --chown=appuser:appuser brain/infrastructure/ ./infrastructure/
COPY --chown=appuser:appuser brain/app.py .
COPY --chown=appuser:appuser alfred/ ./alfred
# Create volumes for persistent data
VOLUME ["/data/memory", "/data/logs"]
+37 -24
View File
@@ -3,20 +3,18 @@
.DEFAULT_GOAL := help
# --- SETTINGS ---
PYTHON_VERSION = 3.12.7
IMAGE_NAME = alfred_media_organizer
# renovate: datasource=docker depName=python
PYTHON_VERSION = $(shell grep "python" pyproject.toml | head -n 1 | sed -E 's/.*[=<>^~"]+ *([0-9]+\.[0-9]+(\.[0-9]+)?).*/\1/')
PYTHON_VERSION_SHORT = $(shell echo $(PYTHON_VERSION) | cut -d. -f1,2)
# Change to 'uv' when ready.
RUNNER ?= poetry
SERVICE_NAME = alfred
export IMAGE_NAME
export PYTHON_VERSION
export PYTHON_VERSION_SHORT
export RUNNER
export IMAGE_NAME
# --- VARIABLES ---
CORE_DIR = brain
SERVICE_NAME = agent_media
IMAGE_NAME = agent_media
# --- ADAPTERS ---
# UV uses "sync", Poetry uses "install". Both install DEV deps by default.
@@ -24,20 +22,19 @@ INSTALL_CMD = $(if $(filter uv,$(RUNNER)),sync,install)
# --- MACROS ---
ARGS = $(filter-out $@,$(MAKECMDGOALS))
BUMP_CMD = cd $(CORE_DIR) && $(RUNNER) run bump-my-version bump
BUMP_CMD = $(RUNNER) run bump-my-version bump
COMPOSE_CMD = docker-compose
DOCKER_CMD = docker build \
--build-arg PYTHON_VERSION=$(PYTHON_VERSION) \
--build-arg PYTHON_VERSION_SHORT=$(PYTHON_VERSION_SHORT) \
--build-arg RUNNER=$(RUNNER) \
-f $(CORE_DIR)/Dockerfile \
-t $(IMAGE_NAME):latest .
RUNNER_ADD = cd $(CORE_DIR) && $(RUNNER) add
RUNNER_HOOKS = cd $(CORE_DIR) && $(RUNNER) run pre-commit install -c ../.pre-commit-config.yaml
RUNNER_INSTALL = cd $(CORE_DIR) && $(RUNNER) $(INSTALL_CMD)
RUNNER_RUN = cd $(CORE_DIR) && $(RUNNER) run
RUNNER_UPDATE = cd $(CORE_DIR) && $(RUNNER) update
RUNNER_ADD = $(RUNNER) add
RUNNER_HOOKS = $(RUNNER) run pre-commit install -c ../.pre-commit-config.yaml
RUNNER_INSTALL = $(RUNNER) $(INSTALL_CMD)
RUNNER_RUN = $(RUNNER) run
RUNNER_UPDATE = $(RUNNER) update
# --- STYLES ---
B = \033[1m
@@ -46,7 +43,7 @@ T = \033[36m
R = \033[0m
# --- TARGETS ---
.PHONY: add build build-test check-docker check-runner clean coverage down format help init-dotenv install install-hooks lint logs major minor patch prune ps restart run shell test up update _check_branch _ci-image-name _ci-run-tests
.PHONY: add build build-test check-docker check-runner clean coverage down format help init-dotenv install install-hooks lint logs major minor patch prune ps python-version restart run shell test up update _check_branch _ci-dump-config _ci-run-tests _push_tag
# Catch-all for args
%:
@@ -67,7 +64,6 @@ build-test: check-docker
--build-arg RUNNER=$(RUNNER) \
--build-arg PYTHON_VERSION=$(PYTHON_VERSION) \
--build-arg PYTHON_VERSION_SHORT=$(PYTHON_VERSION_SHORT) \
-f $(CORE_DIR)/Dockerfile \
--target test \
-t $(IMAGE_NAME):test .
@echo "✅ Test image $(IMAGE_NAME):test ready."
@@ -81,10 +77,10 @@ check-runner:
clean:
@echo "$(T)🧹 Cleaning caches...$(R)"
cd $(CORE_DIR) && rm -rf .ruff_cache __pycache__ .pytest_cache
find $(CORE_DIR) -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true
find $(CORE_DIR) -type d -name ".pytest_cache" -exec rm -rf {} + 2>/dev/null || true
find $(CORE_DIR) -type f -name "*.pyc" -delete 2>/dev/null || true
rm -rf .ruff_cache __pycache__ .pytest_cache
find . -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true
find . -type d -name ".pytest_cache" -exec rm -rf {} + 2>/dev/null || true
find . -type f -name "*.pyc" -delete 2>/dev/null || true
@echo "✅ Caches cleaned."
coverage: check-runner
@@ -134,7 +130,7 @@ help:
@echo " $(T)update $(R) Update dependencies."
@echo ""
@echo "$(G)Versioning:$(R)"
@echo " $(T)major/minor/patch $(R) Bump version."
@echo " $(T)major/minor/patch $(R) Bump version and push tag (triggers CI/CD)."
init-dotenv:
@echo "$(T)🔑 Initializing .env file...$(R)"
@@ -158,7 +154,6 @@ init-dotenv:
@sed -i.bak "s|CREDS_KEY=.*|CREDS_KEY=$$(openssl rand -hex 16)|" .env
@sed -i.bak "s|CREDS_IV=.*|CREDS_IV=$$(openssl rand -hex 8)|" .env
@sed -i.bak "s|MEILI_MASTER_KEY=.*|MEILI_MASTER_KEY=$$(openssl rand -base64 32)|" .env
@sed -i.bak "s|AGENT_BRAIN_API_KEY=.*|AGENT_BRAIN_API_KEY=$$(openssl rand -base64 24)|" .env
@rm -f .env.bak
@echo "$(G)✅ .env created with generated secrets!$(R)"
@echo "$(T)⚠️ Don't forget to add your API keys:$(R)"
@@ -187,14 +182,17 @@ logs: check-docker
major: _check_branch
@echo "$(T)💥 Bumping major...$(R)"
SKIP=all $(BUMP_CMD) major
@$(MAKE) -s _push_tag
minor: _check_branch
@echo "$(T)✨ Bumping minor...$(R)"
SKIP=all $(BUMP_CMD) minor
@$(MAKE) -s _push_tag
patch: _check_branch
@echo "$(T)🚀 Bumping patch...$(R)"
SKIP=all $(BUMP_CMD) patch
@$(MAKE) -s _push_tag
prune: check-docker
@echo "$(T)🗑️ Pruning Docker resources...$(R)"
@@ -205,6 +203,12 @@ ps: check-docker
@echo "$(T)📋 Container status:$(R)"
@$(COMPOSE_CMD) ps
python-version:
@echo "🔍 Reading pyproject.toml..."
@echo "✅ Python version : $(PYTHON_VERSION)"
@echo "️ Sera utilisé pour : FROM python:$(PYTHON_VERSION)-slim"
restart: check-docker
@echo "$(T)🔄 Restarting containers...$(R)"
$(COMPOSE_CMD) restart
@@ -237,8 +241,12 @@ _check_branch:
echo "❌ Error: not on the main branch"; exit 1; \
fi
_ci-image-name:
@echo "IMAGE_NAME=$(IMAGE_NAME)"
_ci-dump-config:
@echo "image_name=$(IMAGE_NAME)"
@echo "python_version=$(PYTHON_VERSION)"
@echo "python_version_short=$(PYTHON_VERSION_SHORT)"
@echo "runner=$(RUNNER)"
@echo "service_name=$(SERVICE_NAME)"
_ci-run-tests: build-test
@echo "$(T)🧪 Running tests in Docker...$(R)"
@@ -247,3 +255,8 @@ _ci-run-tests: build-test
-e TMDB_API_KEY \
$(IMAGE_NAME):test pytest
@echo "✅ Tests passed."
_push_tag:
@echo "$(T)📦 Pushing tag...$(R)"
git push --tags
@echo "✅ Tag pushed. Check CI for build status."
View File
@@ -5,7 +5,7 @@ import logging
from collections.abc import AsyncGenerator
from typing import Any
from infrastructure.persistence import get_memory
from alfred.infrastructure.persistence import get_memory
from .config import settings
from .prompts import PromptBuilder
@@ -3,7 +3,7 @@
import json
from typing import Any
from infrastructure.persistence import get_memory
from alfred.infrastructure.persistence import get_memory
from .registry import Tool
@@ -52,7 +52,7 @@ class PromptBuilder:
# Show first 5 results
for i, result in enumerate(result_list[:5]):
name = result.get("name", "Unknown")
lines.append(f" {i+1}. {name}")
lines.append(f" {i + 1}. {name}")
if len(result_list) > 5:
lines.append(f" ... and {len(result_list) - 5} more")
@@ -3,12 +3,12 @@
import logging
from typing import Any
from application.movies import SearchMovieUseCase
from application.torrents import AddTorrentUseCase, SearchTorrentsUseCase
from infrastructure.api.knaben import knaben_client
from infrastructure.api.qbittorrent import qbittorrent_client
from infrastructure.api.tmdb import tmdb_client
from infrastructure.persistence import get_memory
from alfred.application.movies import SearchMovieUseCase
from alfred.application.torrents import AddTorrentUseCase, SearchTorrentsUseCase
from alfred.infrastructure.api.knaben import knaben_client
from alfred.infrastructure.api.qbittorrent import qbittorrent_client
from alfred.infrastructure.api.tmdb import tmdb_client
from alfred.infrastructure.persistence import get_memory
logger = logging.getLogger(__name__)
@@ -2,8 +2,8 @@
from typing import Any
from application.filesystem import ListFolderUseCase, SetFolderPathUseCase
from infrastructure.filesystem import FileManager
from alfred.application.filesystem import ListFolderUseCase, SetFolderPathUseCase
from alfred.infrastructure.filesystem import FileManager
def set_path_for_folder(folder_name: str, path_value: str) -> dict[str, Any]:
@@ -3,7 +3,7 @@
import logging
from typing import Any
from infrastructure.persistence import get_memory
from alfred.infrastructure.persistence import get_memory
logger = logging.getLogger(__name__)
+7 -8
View File
@@ -5,19 +5,18 @@ import logging
import os
import time
import uuid
from typing import Any
from fastapi import FastAPI, HTTPException
from fastapi.responses import JSONResponse, StreamingResponse
from fastapi.staticfiles import StaticFiles
from pydantic import BaseModel, Field, validator
from typing import Any
from agent.agent import Agent
from agent.config import settings
from agent.llm.deepseek import DeepSeekClient
from agent.llm.exceptions import LLMAPIError, LLMConfigurationError
from agent.llm.ollama import OllamaClient
from infrastructure.persistence import get_memory, init_memory
from alfred.agent.agent import Agent
from alfred.agent.config import settings
from alfred.agent.llm.deepseek import DeepSeekClient
from alfred.agent.llm.exceptions import LLMAPIError, LLMConfigurationError
from alfred.agent.llm.ollama import OllamaClient
from alfred.infrastructure.persistence import get_memory, init_memory
logging.basicConfig(
level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
@@ -2,7 +2,7 @@
import logging
from infrastructure.filesystem import FileManager
from alfred.infrastructure.filesystem import FileManager
from .dto import ListFolderResponse
@@ -2,7 +2,7 @@
import logging
from infrastructure.filesystem import FileManager
from alfred.infrastructure.filesystem import FileManager
from .dto import SetFolderPathResponse
@@ -2,7 +2,7 @@
import logging
from infrastructure.api.tmdb import (
from alfred.infrastructure.api.tmdb import (
TMDBAPIError,
TMDBClient,
TMDBConfigurationError,
@@ -2,7 +2,7 @@
import logging
from infrastructure.api.qbittorrent import (
from alfred.infrastructure.api.qbittorrent import (
QBittorrentAPIError,
QBittorrentAuthError,
QBittorrentClient,
@@ -2,7 +2,7 @@
import logging
from infrastructure.api.knaben import KnabenAPIError, KnabenClient, KnabenNotFoundError
from alfred.infrastructure.api.knaben import KnabenAPIError, KnabenClient, KnabenNotFoundError
from .dto import SearchTorrentsResponse
@@ -1,13 +1,12 @@
"""Knaben torrent search API client."""
import logging
from typing import Any
import logging
import requests
from requests.exceptions import HTTPError, RequestException, Timeout
from typing import Any
from agent.config import Settings, settings
from alfred.agent.config import Settings, settings
from .dto import TorrentResult
from .exceptions import KnabenAPIError, KnabenNotFoundError
@@ -1,13 +1,11 @@
"""qBittorrent Web API client."""
import logging
from typing import Any
import requests
from requests.exceptions import HTTPError, RequestException, Timeout
from typing import Any
from agent.config import Settings, settings
from alfred.agent.config import Settings, settings
from .dto import TorrentInfo
from .exceptions import QBittorrentAPIError, QBittorrentAuthError
@@ -1,13 +1,12 @@
"""TMDB (The Movie Database) API client."""
import logging
from typing import Any
import requests
from requests.exceptions import HTTPError, RequestException, Timeout
from typing import Any
from agent.config import Settings, settings
from alfred.agent.config import Settings, settings
from .dto import MediaResult
from .exceptions import (
TMDBAPIError,
@@ -7,7 +7,7 @@ from enum import Enum
from pathlib import Path
from typing import Any
from infrastructure.persistence import get_memory
from alfred.infrastructure.persistence import get_memory
from .exceptions import PathTraversalError
@@ -3,9 +3,9 @@
import logging
from pathlib import Path
from domain.movies.entities import Movie
from domain.tv_shows.entities import Episode, Season, TVShow
from domain.tv_shows.value_objects import SeasonNumber
from alfred.domain.movies.entities import Movie
from alfred.domain.tv_shows.entities import Episode, Season, TVShow
from alfred.domain.tv_shows.value_objects import SeasonNumber
logger = logging.getLogger(__name__)
@@ -6,7 +6,7 @@ without passing it explicitly through all function calls.
Usage:
# At application startup
from infrastructure.persistence import init_memory, get_memory
from alfred.infrastructure.persistence import init_memory, get_memory
init_memory("memory_data")
@@ -4,11 +4,11 @@ import logging
from datetime import datetime
from typing import Any
from domain.movies.entities import Movie
from domain.movies.repositories import MovieRepository
from domain.movies.value_objects import MovieTitle, Quality, ReleaseYear
from domain.shared.value_objects import FilePath, FileSize, ImdbId
from infrastructure.persistence import get_memory
from alfred.domain.movies.entities import Movie
from alfred.domain.movies.repositories import MovieRepository
from alfred.domain.movies.value_objects import MovieTitle, Quality, ReleaseYear
from alfred.domain.shared.value_objects import FilePath, FileSize, ImdbId
from alfred.infrastructure.persistence import get_memory
logger = logging.getLogger(__name__)
@@ -3,11 +3,11 @@
import logging
from typing import Any
from domain.shared.value_objects import FilePath, ImdbId
from domain.subtitles.entities import Subtitle
from domain.subtitles.repositories import SubtitleRepository
from domain.subtitles.value_objects import Language, SubtitleFormat, TimingOffset
from infrastructure.persistence import get_memory
from alfred.domain.shared.value_objects import FilePath, ImdbId
from alfred.domain.subtitles.entities import Subtitle
from alfred.domain.subtitles.repositories import SubtitleRepository
from alfred.domain.subtitles.value_objects import Language, SubtitleFormat, TimingOffset
from alfred.infrastructure.persistence import get_memory
logger = logging.getLogger(__name__)
@@ -4,11 +4,11 @@ import logging
from datetime import datetime
from typing import Any
from domain.shared.value_objects import ImdbId
from domain.tv_shows.entities import TVShow
from domain.tv_shows.repositories import TVShowRepository
from domain.tv_shows.value_objects import ShowStatus
from infrastructure.persistence import get_memory
from alfred.domain.shared.value_objects import ImdbId
from alfred.domain.tv_shows.entities import TVShow
from alfred.domain.tv_shows.repositories import TVShowRepository
from alfred.domain.tv_shows.value_objects import ShowStatus
from alfred.infrastructure.persistence import get_memory
logger = logging.getLogger(__name__)
+8 -12
View File
@@ -1,14 +1,12 @@
version: "3.4"
services:
# Da brain
agent-brain:
alfred:
build:
context: ./brain
dockerfile: Dockerfile
context: .
args:
RUNNER: ${RUNNER} # Get it from Makefile
container_name: agent-brain
container_name: alfred
restart: unless-stopped
env_file: .env
ports:
@@ -18,7 +16,7 @@ services:
- agent-memory:/data/memory
- agent-logs:/data/logs
# Development: mount code for hot reload (comment out in production)
# - ./brain:/app
# - ./alfred:/app
environment:
# LLM Configuration
LLM_PROVIDER: ${LLM_PROVIDER:-deepseek}
@@ -46,7 +44,7 @@ services:
- mongodb
- meilisearch
- rag_api
- agent-brain
- alfred
env_file: .env
environment:
# MongoDB connection (no auth, matching LibreChat default)
@@ -80,9 +78,6 @@ services:
# Endpoints
ENDPOINTS: custom
# Custom endpoint pointing to agent-brain
CUSTOM_API_KEY: ${AGENT_BRAIN_API_KEY:-agent-brain-secret-key}
# Debug (optional)
DEBUG_LOGGING: ${DEBUG_LOGGING:-false}
DEBUG_CONSOLE: ${DEBUG_CONSOLE:-false}
@@ -107,8 +102,9 @@ services:
- agent-network
# Meilisearch - Search engine for LibreChat
#TODO: Follow currently used version on librechat's github
meilisearch:
image: getmeili/meilisearch:v1.11.3
image: getmeili/meilisearch:v1.12.3
container_name: librechat-meilisearch
restart: unless-stopped
volumes:
@@ -194,7 +190,7 @@ volumes:
librechat-logs:
driver: local
# Agent Brain data
# Alfred data
agent-memory:
driver: local
agent-logs:
+9 -9
View File
@@ -22,7 +22,7 @@ endpoints:
manifest:
schema:
type: openapi
url: "http://agent-brain:8000/manifests/find_media_imdb_id.json"
url: "http://alfred:8000/manifests/find_media_imdb_id.json"
auth:
type: none
@@ -32,7 +32,7 @@ endpoints:
manifest:
schema:
type: openapi
url: "http://agent-brain:8000/manifests/find_torrent.json"
url: "http://alfred:8000/manifests/find_torrent.json"
auth:
type: none
@@ -42,7 +42,7 @@ endpoints:
manifest:
schema:
type: openapi
url: "http://agent-brain:8000/manifests/add_torrent_by_index.json"
url: "http://alfred:8000/manifests/add_torrent_by_index.json"
auth:
type: none
@@ -52,7 +52,7 @@ endpoints:
manifest:
schema:
type: openapi
url: "http://agent-brain:8000/manifests/set_language.json"
url: "http://alfred:8000/manifests/set_language.json"
auth:
type: none
@@ -60,7 +60,7 @@ endpoints:
# Backend Local Agent
- name: "Local Agent"
apiKey: "dummy_key"
baseURL: "http://agent-brain:8000/v1"
baseURL: "http://alfred:8000/v1"
models:
default: ["local-deepseek-agent"]
fetch: false
@@ -75,7 +75,7 @@ endpoints:
manifest:
schema:
type: openapi
url: "http://agent-brain:8000/manifests/find_media_imdb_id.json"
url: "http://alfred:8000/manifests/find_media_imdb_id.json"
auth:
type: none
@@ -85,7 +85,7 @@ endpoints:
manifest:
schema:
type: openapi
url: "http://agent-brain:8000/manifests/find_torrent.json"
url: "http://alfred:8000/manifests/find_torrent.json"
auth:
type: none
@@ -95,7 +95,7 @@ endpoints:
manifest:
schema:
type: openapi
url: "http://agent-brain:8000/manifests/add_torrent_by_index.json"
url: "http://alfred:8000/manifests/add_torrent_by_index.json"
auth:
type: none
@@ -105,6 +105,6 @@ endpoints:
manifest:
schema:
type: openapi
url: "http://agent-brain:8000/manifests/set_language.json"
url: "http://alfred:8000/manifests/set_language.json"
auth:
type: none
+39 -41
View File
@@ -35,7 +35,6 @@ files = [
[package.dependencies]
idna = ">=2.8"
typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""}
[package.extras]
trio = ["trio (>=0.31.0)", "trio (>=0.32.0)"]
@@ -373,25 +372,25 @@ testing = ["hatch", "pre-commit", "pytest", "tox"]
[[package]]
name = "fastapi"
version = "0.121.3"
version = "0.127.1"
description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production"
optional = false
python-versions = ">=3.8"
python-versions = ">=3.9"
files = [
{file = "fastapi-0.121.3-py3-none-any.whl", hash = "sha256:0c78fc87587fcd910ca1bbf5bc8ba37b80e119b388a7206b39f0ecc95ebf53e9"},
{file = "fastapi-0.121.3.tar.gz", hash = "sha256:0055bc24fe53e56a40e9e0ad1ae2baa81622c406e548e501e717634e2dfbc40b"},
{file = "fastapi-0.127.1-py3-none-any.whl", hash = "sha256:31d670a4f9373cc6d7994420f98e4dc46ea693145207abc39696746c83a44430"},
{file = "fastapi-0.127.1.tar.gz", hash = "sha256:946a87ee5d931883b562b6bada787d6c8178becee2683cb3f9b980d593206359"},
]
[package.dependencies]
annotated-doc = ">=0.0.2"
pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0"
pydantic = ">=2.7.0"
starlette = ">=0.40.0,<0.51.0"
typing-extensions = ">=4.8.0"
[package.extras]
all = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.8)", "httpx (>=0.23.0,<1.0.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=3.1.5)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.18)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"]
standard = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.8)", "httpx (>=0.23.0,<1.0.0)", "jinja2 (>=3.1.5)", "python-multipart (>=0.0.18)", "uvicorn[standard] (>=0.12.0)"]
standard-no-fastapi-cloud-cli = ["email-validator (>=2.0.0)", "fastapi-cli[standard-no-fastapi-cloud-cli] (>=0.0.8)", "httpx (>=0.23.0,<1.0.0)", "jinja2 (>=3.1.5)", "python-multipart (>=0.0.18)", "uvicorn[standard] (>=0.12.0)"]
standard = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.8)", "httpx (>=0.23.0,<1.0.0)", "jinja2 (>=3.1.5)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.18)", "uvicorn[standard] (>=0.12.0)"]
standard-no-fastapi-cloud-cli = ["email-validator (>=2.0.0)", "fastapi-cli[standard-no-fastapi-cloud-cli] (>=0.0.8)", "httpx (>=0.23.0,<1.0.0)", "jinja2 (>=3.1.5)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.18)", "uvicorn[standard] (>=0.12.0)"]
[[package]]
name = "filelock"
@@ -535,13 +534,13 @@ files = [
[[package]]
name = "nodeenv"
version = "1.9.1"
version = "1.10.0"
description = "Node.js virtual environment builder"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
files = [
{file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"},
{file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"},
{file = "nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827"},
{file = "nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb"},
]
[[package]]
@@ -1037,13 +1036,13 @@ jupyter = ["ipywidgets (>=7.5.1,<9)"]
[[package]]
name = "rich-click"
version = "1.9.4"
version = "1.9.5"
description = "Format click help output nicely with rich"
optional = false
python-versions = ">=3.8"
files = [
{file = "rich_click-1.9.4-py3-none-any.whl", hash = "sha256:d70f39938bcecaf5543e8750828cbea94ef51853f7d0e174cda1e10543767389"},
{file = "rich_click-1.9.4.tar.gz", hash = "sha256:af73dc68e85f3bebb80ce302a642b9fe3b65f3df0ceb42eb9a27c467c1b678c8"},
{file = "rich_click-1.9.5-py3-none-any.whl", hash = "sha256:9b195721a773b1acf0e16ff9ec68cef1e7d237e53471e6e3f7ade462f86c403a"},
{file = "rich_click-1.9.5.tar.gz", hash = "sha256:48120531493f1533828da80e13e839d471979ec8d7d0ca7b35f86a1379cc74b6"},
]
[package.dependencies]
@@ -1057,30 +1056,30 @@ docs = ["markdown-include (>=0.8.1)", "mike (>=2.1.3)", "mkdocs-github-admonitio
[[package]]
name = "ruff"
version = "0.14.9"
version = "0.14.10"
description = "An extremely fast Python linter and code formatter, written in Rust."
optional = false
python-versions = ">=3.7"
files = [
{file = "ruff-0.14.9-py3-none-linux_armv6l.whl", hash = "sha256:f1ec5de1ce150ca6e43691f4a9ef5c04574ad9ca35c8b3b0e18877314aba7e75"},
{file = "ruff-0.14.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ed9d7417a299fc6030b4f26333bf1117ed82a61ea91238558c0268c14e00d0c2"},
{file = "ruff-0.14.9-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d5dc3473c3f0e4a1008d0ef1d75cee24a48e254c8bed3a7afdd2b4392657ed2c"},
{file = "ruff-0.14.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84bf7c698fc8f3cb8278830fb6b5a47f9bcc1ed8cb4f689b9dd02698fa840697"},
{file = "ruff-0.14.9-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:aa733093d1f9d88a5d98988d8834ef5d6f9828d03743bf5e338bf980a19fce27"},
{file = "ruff-0.14.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6a1cfb04eda979b20c8c19550c8b5f498df64ff8da151283311ce3199e8b3648"},
{file = "ruff-0.14.9-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:1e5cb521e5ccf0008bd74d5595a4580313844a42b9103b7388eca5a12c970743"},
{file = "ruff-0.14.9-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cd429a8926be6bba4befa8cdcf3f4dd2591c413ea5066b1e99155ed245ae42bb"},
{file = "ruff-0.14.9-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ab208c1b7a492e37caeaf290b1378148f75e13c2225af5d44628b95fd7834273"},
{file = "ruff-0.14.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72034534e5b11e8a593f517b2f2f2b273eb68a30978c6a2d40473ad0aaa4cb4a"},
{file = "ruff-0.14.9-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:712ff04f44663f1b90a1195f51525836e3413c8a773574a7b7775554269c30ed"},
{file = "ruff-0.14.9-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:a111fee1db6f1d5d5810245295527cda1d367c5aa8f42e0fca9a78ede9b4498b"},
{file = "ruff-0.14.9-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:8769efc71558fecc25eb295ddec7d1030d41a51e9dcf127cbd63ec517f22d567"},
{file = "ruff-0.14.9-py3-none-musllinux_1_2_i686.whl", hash = "sha256:347e3bf16197e8a2de17940cd75fd6491e25c0aa7edf7d61aa03f146a1aa885a"},
{file = "ruff-0.14.9-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:7715d14e5bccf5b660f54516558aa94781d3eb0838f8e706fb60e3ff6eff03a8"},
{file = "ruff-0.14.9-py3-none-win32.whl", hash = "sha256:df0937f30aaabe83da172adaf8937003ff28172f59ca9f17883b4213783df197"},
{file = "ruff-0.14.9-py3-none-win_amd64.whl", hash = "sha256:c0b53a10e61df15a42ed711ec0bda0c582039cf6c754c49c020084c55b5b0bc2"},
{file = "ruff-0.14.9-py3-none-win_arm64.whl", hash = "sha256:8e821c366517a074046d92f0e9213ed1c13dbc5b37a7fc20b07f79b64d62cc84"},
{file = "ruff-0.14.9.tar.gz", hash = "sha256:35f85b25dd586381c0cc053f48826109384c81c00ad7ef1bd977bfcc28119d5b"},
{file = "ruff-0.14.10-py3-none-linux_armv6l.whl", hash = "sha256:7a3ce585f2ade3e1f29ec1b92df13e3da262178df8c8bdf876f48fa0e8316c49"},
{file = "ruff-0.14.10-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:674f9be9372907f7257c51f1d4fc902cb7cf014b9980152b802794317941f08f"},
{file = "ruff-0.14.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d85713d522348837ef9df8efca33ccb8bd6fcfc86a2cde3ccb4bc9d28a18003d"},
{file = "ruff-0.14.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6987ebe0501ae4f4308d7d24e2d0fe3d7a98430f5adfd0f1fead050a740a3a77"},
{file = "ruff-0.14.10-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:16a01dfb7b9e4eee556fbfd5392806b1b8550c9b4a9f6acd3dbe6812b193c70a"},
{file = "ruff-0.14.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7165d31a925b7a294465fa81be8c12a0e9b60fb02bf177e79067c867e71f8b1f"},
{file = "ruff-0.14.10-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:c561695675b972effb0c0a45db233f2c816ff3da8dcfbe7dfc7eed625f218935"},
{file = "ruff-0.14.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4bb98fcbbc61725968893682fd4df8966a34611239c9fd07a1f6a07e7103d08e"},
{file = "ruff-0.14.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f24b47993a9d8cb858429e97bdf8544c78029f09b520af615c1d261bf827001d"},
{file = "ruff-0.14.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59aabd2e2c4fd614d2862e7939c34a532c04f1084476d6833dddef4afab87e9f"},
{file = "ruff-0.14.10-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:213db2b2e44be8625002dbea33bb9c60c66ea2c07c084a00d55732689d697a7f"},
{file = "ruff-0.14.10-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:b914c40ab64865a17a9a5b67911d14df72346a634527240039eb3bd650e5979d"},
{file = "ruff-0.14.10-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:1484983559f026788e3a5c07c81ef7d1e97c1c78ed03041a18f75df104c45405"},
{file = "ruff-0.14.10-py3-none-musllinux_1_2_i686.whl", hash = "sha256:c70427132db492d25f982fffc8d6c7535cc2fd2c83fc8888f05caaa248521e60"},
{file = "ruff-0.14.10-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:5bcf45b681e9f1ee6445d317ce1fa9d6cba9a6049542d1c3d5b5958986be8830"},
{file = "ruff-0.14.10-py3-none-win32.whl", hash = "sha256:104c49fc7ab73f3f3a758039adea978869a918f31b73280db175b43a2d9b51d6"},
{file = "ruff-0.14.10-py3-none-win_amd64.whl", hash = "sha256:466297bd73638c6bdf06485683e812db1c00c7ac96d4ddd0294a338c62fdc154"},
{file = "ruff-0.14.10-py3-none-win_arm64.whl", hash = "sha256:e51d046cf6dda98a4633b8a8a771451107413b0f07183b2bef03f075599e44e6"},
{file = "ruff-0.14.10.tar.gz", hash = "sha256:9a2e830f075d1a42cd28420d7809ace390832a490ed0966fe373ba288e77aaf4"},
]
[[package]]
@@ -1096,7 +1095,6 @@ files = [
[package.dependencies]
anyio = ">=3.6.2,<5"
typing-extensions = {version = ">=4.10.0", markers = "python_version < \"3.13\""}
[package.extras]
full = ["httpx (>=0.27.0,<0.29.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.18)", "pyyaml"]
@@ -1156,13 +1154,13 @@ zstd = ["backports-zstd (>=1.0.0)"]
[[package]]
name = "uvicorn"
version = "0.38.0"
version = "0.40.0"
description = "The lightning-fast ASGI server."
optional = false
python-versions = ">=3.9"
python-versions = ">=3.10"
files = [
{file = "uvicorn-0.38.0-py3-none-any.whl", hash = "sha256:48c0afd214ceb59340075b4a052ea1ee91c16fbc2a9b1469cca0e54566977b02"},
{file = "uvicorn-0.38.0.tar.gz", hash = "sha256:fd97093bdd120a2609fc0d3afe931d4d4ad688b6e75f0f929fde1bc36fe0e91d"},
{file = "uvicorn-0.40.0-py3-none-any.whl", hash = "sha256:c6c8f55bc8bf13eb6fa9ff87ad62308bbbc33d0b67f84293151efe87e0d5f2ee"},
{file = "uvicorn-0.40.0.tar.gz", hash = "sha256:839676675e87e73694518b5574fd0f24c9d97b46bea16df7b8c05ea1a51071ea"},
]
[package.dependencies]
@@ -1219,5 +1217,5 @@ files = [
[metadata]
lock-version = "2.0"
python-versions = "^3.12"
content-hash = "b6cec0647accef2c235cededb06cab49f30033fb5e5ce1f6b589a4da5d2a2d8d"
python-versions = "==3.14.2"
content-hash = "7046b2edca4660e38f5f14ef0282854a4bb7892af5028c4af9e968f2c65590c5"
+7 -5
View File
@@ -1,18 +1,18 @@
[tool.poetry]
name = "agent-media"
version = "0.1.3"
name = "alfred"
version = "0.1.6"
description = "AI agent for managing a local media library"
authors = ["Francwa <francois.hodiaumont@gmail.com>"]
readme = "README.md"
package-mode = false
[tool.poetry.dependencies]
python = "^3.12"
python = "==3.14.2"
python-dotenv = "^1.0.0"
requests = "^2.32.5"
fastapi = "^0.121.1"
fastapi = "^0.127.0"
pydantic = "^2.12.4"
uvicorn = "^0.38.0"
uvicorn = "^0.40.0"
pytest-xdist = "^3.8.0"
httpx = "^0.28.1"
@@ -31,6 +31,8 @@ build-backend = "poetry.core.masonry.api"
[tool.pytest.ini_options]
# Chemins où pytest cherche les tests
testpaths = ["tests"]
# Ajouter le répertoire racine au PYTHONPATH pour les imports
pythonpath = ["."]
# Patterns de fichiers/classes/fonctions à considérer comme tests
python_files = ["test_*.py"] # Fichiers commençant par "test_"
+38
View File
@@ -0,0 +1,38 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:base",
":disableRateLimiting",
":semanticCommits"
],
"labels": ["dependencies", "renovate"],
"packageRules": [
{
"matchLanguages": ["python"],
"matchUpdateTypes": ["patch"],
"automerge": true,
"groupName": "Python Security Patches"
},
{
"matchPackageNames": ["python"],
"matchUpdateTypes": ["major", "minor"],
"dependencyDashboardApproval": true,
"groupName": "Python Update(s) (Manual Action Required)"
},
{
"matchPackageNames": ["getmeili/meilisearch"],
"enabled": false
}
],
"regexManagers": [
{
"description": "Update Docker variables in the Makefile",
"fileMatch": ["^Makefile$"],
"matchStrings": [
"# renovate: datasource=(?<datasource>.*?) depName=(?<depName>.*?)( versioning=(?<versioning>.*?))?\\s[A-Z_]+_VERSION [?:]?= (?<currentValue>.*)"
]
}
]
}
@@ -1,19 +1,16 @@
"""Pytest configuration and shared fixtures."""
import sys
from pathlib import Path
# TODO: Moved directory, should not be necessary anymore but need to check !!
# Ajouter le dossier parent (brain) au PYTHONPATH
sys.path.insert(0, str(Path(__file__).parent.parent))
# sys.path.insert(0, str(Path(__file__).parent.parent))
import pytest
import shutil
import sys
import tempfile
from pathlib import Path
from unittest.mock import MagicMock, Mock
import pytest
from infrastructure.persistence import Memory, set_memory
from alfred.infrastructure.persistence import Memory, set_memory
@pytest.fixture
@@ -254,7 +251,6 @@ def mock_deepseek():
def test_something(mock_deepseek):
# Your test code here
"""
import sys
from unittest.mock import Mock
# Save the original module if it exists
@@ -2,8 +2,8 @@
from unittest.mock import Mock
from agent.agent import Agent
from infrastructure.persistence import get_memory
from alfred.agent.agent import Agent
from alfred.infrastructure.persistence import get_memory
class TestAgentInit:

Some files were not shown because too many files have changed in this diff Show More