Skip to content

Releases: antonyrag/ragleap-core

ragleap-graph-v0.6.9

Choose a tag to compare

@antonyrag antonyrag released this 03 Sep 10:12
4020339

[0.6.9]

Fixed

  • RELATES_AS relationship-MERGE race - a real, previously-undocumented bug found while reviewing this code (distinct from the deferred "RelationWeight stress test" item from the v0.6.7 handoff - the RelationWeight NODE already had its composite_key fix; this relationship was never touched until now). MERGE (es)-[r:RELATES_AS {relation_type: $relation_type}]->(eo) matched only on the two Entity endpoints plus relation_type - not atomic against concurrent writers, same class of bug as the v0.6.7/v0.6.8 node- and relationship-level races.
  • Fix: a composite_key property (namespace/user_id/subject/relation_type/object) is now MERGE'd on the RELATES_AS relationship, backed by a relationship-level uniqueness constraint. RELATES_AS is directed (subject -> object via a specific relation_type), unlike CO_OCCURS_WITH, so no pair-sorting/canonicalization was needed. relation_type is kept as a real property via ON CREATE SET (not removed) since find_relations() and find_lineage() read it directly.

Verified

  • Live concurrency test using real Ollama (qwen2.5:0.5b) extraction: 4 concurrent upsert_document() calls, 4 different document_ids, same real relation-bearing sentence. Deliberately does not assert an exact relationship count, since real LLM extraction can legitimately produce more than one distinct relation_type string for the same input; instead asserts the property the fix actually guarantees - no two relationships share a composite_key. Passed against real Neo4j + real Ollama.
  • Full suite: 79 passed, 13 skipped - zero regressions.

ragleap-vectorstores v0.2.1

Choose a tag to compare

@antonyrag antonyrag released this 01 Sep 03:53
67d9f85

[0.2.1] - Fixed

  • README's Install section was missing uv add variants for both extras (only pip install was shown) - caught by checking the real rendered PyPI project page after the v0.2.0 publish.

[0.2.0] - Added

  • LanceDBBackend - second vector backend, via LanceDB's embedded/local connection mode (a directory path, no server required). Available via the lancedb optional extra (pip install ragleap-vectorstores[lancedb]).
  • Real upsert semantics via merge_insert() - re-inserting the same document_id/chunk_index updates the row in place rather than duplicating it.
  • supports_sparse() correctly reports False for LanceDB - it does support full-text search via tantivy, but that surface wasn't implemented or tested in this release, so hybrid search honestly falls back to dense-only.

Install

pip install ragleap-vectorstores[chroma]
# or, with uv
uv add ragleap-vectorstores[chroma]

pip install ragleap-vectorstores[lancedb]
# or, with uv
uv add ragleap-vectorstores[lancedb]

25/25 tests passing (11 Chroma + 13 LanceDB + smoke). Full changelog: packages/ragleap-vectorstores/CHANGELOG.md

ragleap-ops v0.2.0

Choose a tag to compare

@antonyrag antonyrag released this 31 Aug 07:40
dc5fe29

Added

  • Helm chart (helm/ragleap-ops/) wrapping all four k8s/ manifests (db, app, voice, neo4j) with real configurable values.yaml — image tags, resource limits, storage sizes, probe timings, credentials.
  • Real database schema (db/schema.sql) is packaged into the chart via Helm's .Files.Get, copied verbatim from the repo's real schema file, not reproduced from memory.

Fixed

  • neo4j's liveness probe had no explicit failureThreshold in the Helm template (unlike the raw k8s manifest, which was already correctly set) — defaulted to Kubernetes' built-in 3, too tight for JVM startup under CPU contention. Found via live helm install/helm upgrade testing on a real kind cluster (not caught by helm lint or helm template, since those don't exercise runtime behavior). Fixed to match the readiness probe's more generous timing (initialDelaySeconds: 60, failureThreshold: 6).

Verified

  • All four services (db, app, voice, neo4j) independently reached 1/1 Running with zero restarts for extended periods (60+ minutes) on a real kind cluster via helm install.
  • Added explicit resources.requests/limits for neo4j (512Mi memory request, 1Gi limit; CPU tuned to 50m during testing) after live testing on this session's VPS surfaced real host-level CPU/memory contention (the test VPS runs several other production services concurrently) — this is a permanent, worthwhile chart improvement, not a workaround specific to this host.

Known limitations

  • Full 4-service stack was demonstrated stable in bounded windows (60+ min) on a resource-constrained single-node test host that was also running unrelated production services. Extended (multi-hour) concurrent-stack stability was not verified on this specific host due to genuine host-level memory/CPU exhaustion (swap fully exhausted at points during testing) — not a chart defect, but an honest scope boundary on what was tested. A dedicated cluster (not sharing a host with other production workloads) is expected to have materially more headroom.
  • CPU resource values (cpu: 50m for neo4j) were tuned against a heavily constrained single-vCPU-allocatable test node and should be reviewed against real target-cluster capacity before production use, not assumed as a universal recommendation.
  • Same limitations as v0.1.0 still apply: app-env-secret.yaml/db-schema-configmap.yaml's real content are environment-specific and not shipped; PVC storage sizes remain placeholder defaults.

ragleap-ops v0.1.0

Choose a tag to compare

@antonyrag antonyrag released this 30 Aug 08:43
86bc12a

Added

  • Initial release: Kubernetes Deployment + Service manifests for all four docker-compose.yml services (db, app, voice, neo4j), translated field-by-field from the real compose file rather than assumed.
  • Live-tested end-to-end on a local kind cluster: all four pods reached 1/1 Running with zero restarts. A db liveness-probe timing bug was found live (the original initialDelaySeconds: 10 was too short for first-boot image pull + PVC attach, causing kubelet to kill a still-starting container) and fixed (initialDelaySeconds: 45, failureThreshold: 6), then re-verified clean.
  • app/voice pull a real image (ghcr.io/antonyrag/ragleap-app:latest, built from the existing repo-root Dockerfile and pushed to GHCR) via a ghcr-pull-secret imagePullSecret.
  • Python package scaffold (pyproject.toml, src/ragleap_ops/) added purely so this content can be versioned and released via the existing release.yml automation — the package itself ships no functional Python code, only the k8s/ manifests.

Known limitations

  • No Helm chart yet — raw manifests were proven first via live cluster testing; Helm wrapping is planned next.
  • app-env-secret.yaml and the real contents of db-schema-configmap.yaml's referenced schema.sql are environment-specific and intentionally not shipped in this package — see README for how to regenerate them locally via kubectl create secret/kubectl create configmap.
  • PVC storage sizes (5Gi) are placeholder defaults, not derived from any real capacity planning — docker-compose.yml's named volumes are unbounded, so there was no real size to translate from.

ragleap-vectorstores v0.1.0

Choose a tag to compare

@antonyrag antonyrag released this 29 Aug 07:10
68a03d9

First release of ragleap-vectorstores - pluggable vector backends beyond ragleap-rag core's 6 (PgVector, FAISS, Pinecone, Weaviate, Qdrant, Milvus).

Added

  • Initial package scaffold - pyproject.toml, package layout matching ragleap-graph's src/ragleap_vectorstores convention.
  • ChromaBackend - first vector backend, implementing the full VectorBackend interface via chromadb's embedded PersistentClient (no server required). Available via the chroma optional extra (pip install ragleap-vectorstores[chroma]).
  • supports_sparse() correctly reports False for Chroma - no native keyword/BM25 search as of chromadb 1.5.9, so hybrid search honestly falls back to dense-only rather than claiming unimplemented capability.

Install

pip install ragleap-vectorstores[chroma]

Full changelog: packages/ragleap-vectorstores/CHANGELOG.md

Merge pull request #228 from antonyrag/release/ragleap-graph-v0.6.8

Choose a tag to compare

@antonyrag antonyrag released this 29 Aug 11:20
8e94c69

[0.6.8]

Fixed

  • CO_OCCURS_WITH relationship-MERGE race, noticed but deliberately left open in the v0.6.7 fix (that release closed the four NODE-level races for Document/Entity/PairWeight/RelationWeight; this closes the equivalent race at the relationship level). MERGE (ea)-[r:CO_OCCURS_WITH]-(eb) matched only on the two Entity endpoints and relationship type - not atomic against concurrent writers, same class of bug as the v0.6.7 node-level races.
  • Fix: a composite_key property (same _composite_key() helper as the four node types) is now MERGE'd on the CO_OCCURS_WITH relationship, backed by a relationship-level uniqueness constraint (FOR ()-[r:CO_OCCURS_WITH]-() REQUIRE r.composite_key IS UNIQUE), created idempotently alongside the existing four node constraints. CO_OCCURS_WITH is undirected and entity-pair order wasn't canonicalized anywhere in the existing code, so the composite_key is computed from a sorted (a, b) pair - without this, the same logical entity pair extracted in different orders across different documents would compute two different keys and MERGE could still create a duplicate relationship.
  • Added backfill_co_occurs_with_composite_key(namespace=None, batch_size=500) - the same one-time, idempotent migration pattern as backfill_composite_key() (v0.6.7), for CO_OCCURS_WITH relationships written before this version. Deduplicates on relationship identity (WITH DISTINCT r) before reading endpoint names via startNode(r)/endNode(r), since Neo4j's undirected-match semantics can otherwise surface the same relationship via more than one traversal direction.

Verified

  • Live concurrency test (8 concurrent upsert_document() calls, 8 different document_ids, all mentioning the same two entities) against real Neo4j: exactly 1 CO_OCCURS_WITH relationship resulted, with composite_key correctly set - confirming the fix under real contention, not just code review. This is a different race shape than v0.6.7's Document-race test (same document_id, concurrent calls), since CO_OCCURS_WITH deliberately aggregates across DIFFERENT documents by design.
  • Full suite: 79 passed, 12 skipped - zero regressions.

v0.3.0 — Outcome-weighted memory, autonomy escalation, channel routing, Slack connector

Choose a tag to compare

@antonyrag antonyrag released this 28 Aug 05:25
2ea4e17

Everything merged since v0.2.0:

AI Employees / autonomy

  • Outcome-weighted memory (feedback commands across WhatsApp/Telegram/Discord/Voice)
  • Role-to-autonomy escalation trigger (deterministic, off by default)
  • Channel-to-role routing — all 9 roles now reachable, not just support

Integrations

  • Slack connector (Phase A)

Infra

  • Background sync via APScheduler (external contribution)
  • README overhaul: real logo, dynamic version badge, cleaner layout

Merge pull request #215 from antonyrag/release/ragleap-rag-v0.12.4

Choose a tag to compare

@antonyrag antonyrag released this 27 Aug 19:19
7defe77

[0.12.4] - 2026-08-27

Fixed

  • chunk_text()'s token_count field now reflects a real LLM token count via tiktoken (cl100k_base) when available, instead of always being a whitespace-split word count. The previous behavior was a documented, known limitation (token_count internally consistent but not what the field name implied). _tokenize() itself — which determines chunk windowing (chunk_size/chunk_overlap are still measured in whitespace-split words) — is unchanged; only what token_count reports about the resulting chunk text has changed. A new token_count_is_exact: bool field is added alongside the existing token_count field: True when a real tiktoken count was used, False when tiktoken wasn't installed or its encoding couldn't be loaded (e.g. no network egress to fetch the BPE rank file on first use), in which case token_count falls back to the previous word-count behavior exactly, never reporting an estimate as exact. New tests (test_chunk_text_token_count_matches_tiktoken_when_exact, test_chunk_text_fallback_word_count_when_tiktoken_unavailable, test_chunk_text_fallback_on_encoding_load_failure) cover both the real-tokenization and fallback paths. tiktoken is now a declared core dependency rather than an incidental transitive one. This is a breaking change to token_count's values for any caller depending on the previous word-count numbers specifically — acceptable pre-1.0, and this was already a documented, known limitation rather than a silent surprise.

ragleap-graph v0.6.7

Choose a tag to compare

@antonyrag antonyrag released this 25 Aug 04:46
03afd3a

Fixed

Real, confirmed concurrency bug (closes #183): concurrent upsert_document() calls with identical document_id/user_id/namespace could create duplicate Document/Entity/PairWeight/RelationWeight nodes. MERGE on multiple plain properties is not atomic against concurrent writers without a uniqueness constraint, and Neo4j Community Edition only supports single-property uniqueness constraints (no composite constraints, unlike Enterprise Edition). Reproduced live before fixing: 8 duplicate Document nodes from 6 'successful' concurrent upserts of the same document.

Fix: a single hashed composite_key property (SHA256 over each label's real identity fields) is now MERGE'd on instead of the multiple plain properties, backed by a single-property (Community-compatible) uniqueness constraint created idempotently on every GraphIndex connect. Existing plain properties remain unchanged - every existing read/query keeps working.

Added retry-with-backoff for Neo4j transient deadlocks (documented by Neo4j as expected/retryable under concurrency, not corruption). Added backfill_composite_key() - a one-time, idempotent migration for pre-existing data, matching v0.6.5's backfill_user_id_defaults() pattern.

Verified

Live regression test (8-16 concurrent threads against real Neo4j, merged into the permanent suite): real deadlocks directly observed and transparently recovered via the retry logic - zero duplicates across dozens of runs, including a 16-thread stress test where 3 real deadlocks fired mid-run and all recovered.

The migration was live-verified end-to-end against a real legacy-style node.

Full suite: 88 passed, 1 skipped (unrelated, no GEMINI_API_KEY) - zero regressions.

Known residual gap: RelationWeight's composite_key fix uses the identical pattern as PairWeight and passes the full suite, but is not independently concurrency-stress-tested (requires an LLM-based relation extractor not configured in this test environment). Documented honestly, not silently claimed as fully proven.

Published to PyPI, verified via the version-specific JSON endpoint.

See CHANGELOG.md for full detail.

ragleap-rag v0.12.3

Choose a tag to compare

@antonyrag antonyrag released this 24 Aug 05:07
4865139

Fixed

Milvus backend's similarity_score is now normalized to [0, 1], matching pgvector/weaviate's convention.

Milvus with metric_type="COSINE" returns raw cosine similarity in the field it labels "distance" - verified against Milvus's own documentation, this was already correctly ordered (higher = more similar), not backwards, but its range was inconsistent: raw cosine similarity spans [-1, 1], while pgvector and weaviate_backend.py already normalize to [0, 1]. A caller filtering on similarity_score (e.g. score > 0.5) would behave correctly for those two backends but break silently for Milvus's negative scores.

Fixed via the standard (x + 1) / 2 linear transform - preserves exact ranking order, adds consistent range.

New regression test (test_search_dense_normalizes_cosine_similarity_to_unit_range) confirms the transform at all three boundaries (identical/orthogonal/opposite vectors -> 1.0/0.5/0.0).

Breaking change note: this changes real output values for anyone depending on Milvus's previous raw [-1, 1] scores. Acceptable pre-1.0; this inconsistency was already a documented, known limitation rather than a silent surprise.

Full 245-test suite passes. Published to PyPI, verified via the version-specific JSON endpoint.

See CHANGELOG.md for full detail.