diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..d31f593 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,25 @@ +version: 2 +updates: + - package-ecosystem: "uv" + directory: "/" + schedule: + interval: "weekly" + day: "monday" + timezone: "Europe/Rome" + commit-message: + prefix: "chore(deps)" + groups: + python-minor-patch: + update-types: ["minor", "patch"] + + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + day: "monday" + timezone: "Europe/Rome" + commit-message: + prefix: "chore(ci)" + groups: + actions-minor-patch: + update-types: ["minor", "patch"] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..9b6f91c --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,79 @@ +name: CI + +on: + pull_request: + push: + branches: [main] + +concurrency: + group: ci-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + - uses: astral-sh/setup-uv@v6 + with: + enable-cache: true + - run: uv sync --locked + - name: Ruff lint + run: uv run ruff check . + - name: Ruff format + run: uv run ruff format --check . + + typecheck: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + - uses: astral-sh/setup-uv@v6 + with: + enable-cache: true + - run: uv sync --locked + - name: mypy + run: uv run mypy + + import-contracts: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + - uses: astral-sh/setup-uv@v6 + with: + enable-cache: true + - run: uv sync --locked + - name: import-linter + run: uv run lint-imports + + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + - uses: astral-sh/setup-uv@v6 + with: + enable-cache: true + - run: uv sync --locked + - name: pytest + run: uv run pytest + - name: Coverage summary + if: always() + run: uv run coverage report --format=markdown >> "$GITHUB_STEP_SUMMARY" + + quality-gate: + if: always() + needs: [lint, typecheck, import-contracts, test] + runs-on: ubuntu-latest + steps: + - name: Fail unless every required job succeeded + if: >- + contains(needs.*.result, 'failure') || + contains(needs.*.result, 'cancelled') || + contains(needs.*.result, 'skipped') + run: | + echo "Required job results: ${{ join(needs.*.result, ', ') }}" + exit 1 + - name: All required jobs succeeded + run: echo "quality-gate passed" diff --git a/packages/engine/src/agentic_rag/adapters/__init__.py b/packages/engine/src/agentic_rag/adapters/__init__.py new file mode 100644 index 0000000..26e2a7e --- /dev/null +++ b/packages/engine/src/agentic_rag/adapters/__init__.py @@ -0,0 +1 @@ +"""Backend adapters implementing the ports, each behind an optional extra.""" diff --git a/packages/engine/src/agentic_rag/agent/__init__.py b/packages/engine/src/agentic_rag/agent/__init__.py new file mode 100644 index 0000000..3be43c5 --- /dev/null +++ b/packages/engine/src/agentic_rag/agent/__init__.py @@ -0,0 +1 @@ +"""Declarative agent runtime: task graphs, tools and retrieval policies.""" diff --git a/packages/engine/src/agentic_rag/eval/__init__.py b/packages/engine/src/agentic_rag/eval/__init__.py new file mode 100644 index 0000000..03cd792 --- /dev/null +++ b/packages/engine/src/agentic_rag/eval/__init__.py @@ -0,0 +1 @@ +"""Evaluation: golden sets, IR metrics and the eval runner.""" diff --git a/packages/engine/src/agentic_rag/evidence/__init__.py b/packages/engine/src/agentic_rag/evidence/__init__.py new file mode 100644 index 0000000..eee429b --- /dev/null +++ b/packages/engine/src/agentic_rag/evidence/__init__.py @@ -0,0 +1 @@ +"""Evidence pack construction: deduplication, ordering and token budgeting.""" diff --git a/packages/engine/src/agentic_rag/generation/__init__.py b/packages/engine/src/agentic_rag/generation/__init__.py new file mode 100644 index 0000000..33465e5 --- /dev/null +++ b/packages/engine/src/agentic_rag/generation/__init__.py @@ -0,0 +1 @@ +"""Generation helpers: prompt registry, context formatting and citation checks.""" diff --git a/packages/engine/src/agentic_rag/ingest/__init__.py b/packages/engine/src/agentic_rag/ingest/__init__.py new file mode 100644 index 0000000..d874bb3 --- /dev/null +++ b/packages/engine/src/agentic_rag/ingest/__init__.py @@ -0,0 +1 @@ +"""Ingestion pipeline: parsing, cleaning, chunking and section trees.""" diff --git a/packages/engine/src/agentic_rag/ports/__init__.py b/packages/engine/src/agentic_rag/ports/__init__.py new file mode 100644 index 0000000..bea0835 --- /dev/null +++ b/packages/engine/src/agentic_rag/ports/__init__.py @@ -0,0 +1 @@ +"""Protocol definitions for every swappable backend.""" diff --git a/packages/engine/src/agentic_rag/retrieval/__init__.py b/packages/engine/src/agentic_rag/retrieval/__init__.py new file mode 100644 index 0000000..7f24582 --- /dev/null +++ b/packages/engine/src/agentic_rag/retrieval/__init__.py @@ -0,0 +1 @@ +"""Retrieval pipeline: hybrid search, fusion, reranking and parent expansion.""" diff --git a/packages/engine/src/agentic_rag/types/__init__.py b/packages/engine/src/agentic_rag/types/__init__.py new file mode 100644 index 0000000..026f4bb --- /dev/null +++ b/packages/engine/src/agentic_rag/types/__init__.py @@ -0,0 +1 @@ +"""Domain-neutral data model: documents, chunks, citations and evidence.""" diff --git a/pyproject.toml b/pyproject.toml index 9ae8402..570c31a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,3 +17,51 @@ members = ["packages/*"] [tool.uv.sources] agentic-rag = { workspace = true } agentic-rag-code = { workspace = true } + +[tool.ruff] +target-version = "py311" +line-length = 100 + +[tool.ruff.lint] +select = ["E", "F", "W", "I", "B", "UP", "SIM", "RUF", "D"] + +[tool.ruff.lint.pydocstyle] +convention = "google" + +[tool.ruff.lint.per-file-ignores] +"**/tests/**" = ["D"] + +[tool.mypy] +strict = true +files = ["packages"] +python_version = "3.11" + +[tool.pytest.ini_options] +testpaths = ["packages"] +addopts = "--cov=agentic_rag --cov=agentic_rag_code --cov-report=term-missing --cov-fail-under=80" + +[tool.importlinter] +root_packages = ["agentic_rag", "agentic_rag_code"] + +[[tool.importlinter.contracts]] +name = "Types and ports never import adapters" +type = "forbidden" +source_modules = ["agentic_rag.types", "agentic_rag.ports"] +forbidden_modules = ["agentic_rag.adapters"] + +[[tool.importlinter.contracts]] +name = "The engine never imports the code-rag extension" +type = "forbidden" +source_modules = ["agentic_rag"] +forbidden_modules = ["agentic_rag_code"] + +[[tool.importlinter.contracts]] +name = "Engine layers" +type = "layers" +layers = [ + "agentic_rag.adapters", + "agentic_rag.ingest : agentic_rag.retrieval : agentic_rag.generation : agentic_rag.agent : agentic_rag.eval", + "agentic_rag.evidence", + "agentic_rag.ports", + "agentic_rag.types", +]