Skip to content

Wire LLM-extracted kg triples into the TripleStore (#840, contract) #2372

Wire LLM-extracted kg triples into the TripleStore (#840, contract)

Wire LLM-extracted kg triples into the TripleStore (#840, contract) #2372

Workflow file for this run

name: CI
on:
push:
branches: [main, master]
pull_request:
branches: [main, master]
jobs:
docs-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
- name: Set up Python
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065
with:
python-version: "3.11"
# No pip install on purpose: the generator parses the source with ast
# rather than importing mnemosyne, so this job stays dependency-free.
# If that ever changes, this job needs the package installed.
- name: Report the surface the code declares
run: python3 scripts/generate-docs.py --check 2>&1
# Verifies the committed docs/api/*.mdx against freshly generated
# output, in-process. The previous implementation resolved a sibling
# repo that is never checked out here and exited 0, so this gate
# passed unconditionally and checked nothing.
- name: Verify generated docs are up to date
run: python3 scripts/verify-docs.py 2>&1
lint:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
# Fetch enough history for `git diff origin/main...HEAD` to
# work on PR builds. Default depth=1 breaks this — `Actions
# checkout@4+` exposes `fetch-depth` explicitly.
fetch-depth: 0
# Persist the auto-issued GITHUB_TOKEN so the F-rules step
# can `git fetch origin base-ref` on fork PRs (the default
# `persist-credentials: false` would block that with a 403).
persist-credentials: true
- name: Set up Python
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065
with:
python-version: "3.11"
- name: Install Ruff
run: python -m pip install ruff==0.15.22
# ------------------------------------------------------------------
# Step A: project-wide fatal gate.
#
# Pure syntax / undefined-name / unparsable cases. These are the
# ones that have always been enforced and would ship broken code
# otherwise — they stay fatal across the whole tree.
# ------------------------------------------------------------------
- name: Check fatal Python errors
run: ruff check --select E9,F63,F7,F82 mnemosyne tests integrations/hermes/src integrations/hermes/tests hermes_memory_provider
# ------------------------------------------------------------------
# Step B: PR-scoped F/RUF022 sweep over CHANGED files only.
#
# Why scoped: turning the F-ruleset on tree-wide would surface
# ~423 legacy violations on current `main`, fail every open PR,
# and reintroduce the original problem this job was supposed to
# prevent (any push can stop the project). The family we're
# adding — F401/F841/F541/RUF022 — is cheap to write, so we
# enforce it on new code and let historical violations get
# cleaned up via dedicated PRs.
#
# Behavior:
# - pull_request: list .py files changed vs the PR base, run
# ruff with the broader rubric. Fails if any DIFF file has
# new F/RUF022 violations.
# - push to main: skip. The F-rules live in PR-only land until
# someone files the cleanup PR that brings main itself under
# the same rubric.
#
# See PR #483 followup for context.
# ------------------------------------------------------------------
- name: Check F-rules on changed files (PRs only)
if: github.event_name == 'pull_request'
env:
# Pin the PR base ref from the workflow event into the shell
# environment so we don't have to splice it through ${{ }}
# inside the bash script (which interacts poorly with quoting
# and would let a hostile base.ref break out of the string).
PR_BASE_REF: ${{ github.event.pull_request.base.ref }}
run: |
set -euo pipefail
# Fetch the base branch explicitly (shallow — we only need
# the diff walker) and resolve BASE_REF after the fetch so
# `origin/${PR_BASE_REF}` exists locally.
git fetch --depth=1 origin "${PR_BASE_REF}"
BASE_REF="origin/${PR_BASE_REF}"
# NUL-delimited so paths with spaces / newlines survive.
# No `|| true` — if the diff walker itself breaks, the step
# should fail loudly rather than silently skipping lint.
#
# Why a temp file instead of a process substitution feeding
# `mapfile`: mapfile reports the exit code of the array
# *assignment*, not the substituted command, so a failing
# `git diff` would leave `CHANGED` empty and exit 0 — silently
# bypassing the PR lint gate. Writing to a file first lets
# `set -e` observe and propagate the failure (the script
# aborts before `mapfile` runs).
changed_files="$(mktemp)"
trap 'rm -f "${changed_files}"' EXIT
git diff --name-only --diff-filter=ACMRT -z \
"${BASE_REF}...HEAD" -- '*.py' > "${changed_files}"
mapfile -d '' -t CHANGED < "${changed_files}"
if [ "${#CHANGED[@]}" -eq 0 ]; then
echo "No Python files changed — skipping F-rules sweep."
exit 0
fi
echo "Python files changed on this PR:"
printf ' - %s\n' "${CHANGED[@]}"
# `--` so a path like `--something.py` is treated as a
# positional argument rather than a ruff option.
ruff check --select F,RUF022 -- "${CHANGED[@]}"
test:
runs-on: ubuntu-latest
permissions:
contents: read
strategy:
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13"]
env:
# Force lexical-only retrieval in CI. Sleep / consolidation /
# recall tests exercise the no-embeddings degradation path, which
# is the same code path the production system takes when the
# model download fails or the user opts out. This eliminates the
# Hugging Face 429 cascade that previously caused 48+ failures
# on the test (3.11) job. Set MNEMOSYNE_EMBEDDINGS_FORCE_DOWNLOAD=1
# in a follow-up job if you want to exercise the real model path.
MNEMOSYNE_NO_EMBEDDINGS: "1"
# Cache dir for the fastembed model (only used when embeddings
# are enabled, but pre-create it so the cache step has a stable
# path to restore from).
MNEMOSYNE_FASTEMBED_CACHE_DIR: ${{ github.workspace }}/.cache/fastembed
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065
with:
python-version: ${{ matrix.python-version }}
cache: pip
cache-dependency-path: pyproject.toml
- name: Cache embedding model
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: ${{ env.MNEMOSYNE_FASTEMBED_CACHE_DIR }}
key: fastembed-bge-small-en-v1.5-${{ matrix.python-version }}-${{ hashFiles('pyproject.toml') }}
restore-keys: |
fastembed-bge-small-en-v1.5-${{ matrix.python-version }}-
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -e ".[embeddings,mcp,sync,test]"
pip install -e ./integrations/hermes
- name: Pre-download embedding model
# Only runs when the cache missed and embeddings are enabled.
# The env override above disables embeddings, so this is a no-op
# for the default job. To run the real embedding path in CI,
# unset MNEMOSYNE_NO_EMBEDDINGS in a follow-up workflow and
# this step will populate the cache on first run.
if: env.MNEMOSYNE_NO_EMBEDDINGS != '1'
run: |
mkdir -p "$MNEMOSYNE_FASTEMBED_CACHE_DIR"
python -c "
from fastembed import TextEmbedding
TextEmbedding(
model_name='BAAI/bge-small-en-v1.5',
cache_dir='$MNEMOSYNE_FASTEMBED_CACHE_DIR',
)
print('embedding model cached')
"
- name: Run core tests
run: pytest tests/ -v --tb=short
- name: Run Hermes integration tests
run: pytest integrations/hermes/tests/ -v --tb=short
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
- name: Set up Python
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065
with:
python-version: "3.11"
- name: Install build dependencies
run: |
python -m pip install --upgrade pip
pip install build twine
- name: Build package
run: python -m build
- name: Check package with twine
run: twine check dist/*