Skip to content
Merged
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
29 changes: 28 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,31 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [1.1.4] - 2026-07-20

### Added

- **Langfuse integration example** — added an OpenTelemetry-based wrapper for
tracing EverOS add, flush/extract, search, and reflection operations, with a
built-in mock and support for connecting to a real EverOS server.

### Fixed

- **Cascade delete/modify race** — when a file disappears after its modified
event is queued, the worker now processes it as a deletion instead of leaving
a stale indexed row and permanently failed queue item.
- **Langfuse live-server traces use only real telemetry** — synthetic child
spans are now limited to responses that provide stage details, while real
servers emit accurate top-level latency, output, and recall-quality scores.

## [1.1.3] - 2026-07-10

### Fixed

- **LanceDB FTS optimize crash and disk growth** — disabled unused positional
data in OR-mode BM25 indexes, automatically rebuilds affected indexes, and
escalates repeated optimize failures so cleanup cannot fail silently.

## [1.1.2] - 2026-07-07

### Fixed
Expand Down Expand Up @@ -226,7 +251,9 @@ for AI agents.
- **Decoupled algorithms** — memory extraction algorithms live in the standalone
`everalgo-*` libraries published on PyPI.

[Unreleased]: https://github.com/EverMind-AI/everos/compare/v1.1.2...HEAD
[Unreleased]: https://github.com/EverMind-AI/everos/compare/v1.1.4...HEAD
[1.1.4]: https://github.com/EverMind-AI/everos/compare/v1.1.3...v1.1.4
[1.1.3]: https://github.com/EverMind-AI/everos/compare/v1.1.2...v1.1.3
[1.1.2]: https://github.com/EverMind-AI/everos/compare/v1.1.1...v1.1.2
[1.1.1]: https://github.com/EverMind-AI/everos/compare/v1.1.0...v1.1.1
[1.1.0]: https://github.com/EverMind-AI/everos/compare/v1.0.1...v1.1.0
Expand Down
2 changes: 1 addition & 1 deletion CITATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ To cite the software itself:

```
EverOS: local-first memory runtime for AI agents
Version: 1.1.0
Version: 1.1.4
URL: https://github.com/EverMind-AI/EverOS
License: Apache 2.0
```
Expand Down
2 changes: 1 addition & 1 deletion docs/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"info": {
"title": "everos",
"description": "md-first memory extraction framework",
"version": "1.1.2"
"version": "1.1.4"
},
"paths": {
"/health": {
Expand Down
2 changes: 1 addition & 1 deletion docs/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,4 @@ Strict single-direction dependency, enforced by `import-linter` in CI.

## Status

**Latest stable release: v1.1.0** (PyPI) — the v1 API is stable.
**Latest stable release: v1.1.4** (PyPI) — the v1 API is stable.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "everos"
version = "1.1.2"
version = "1.1.4"
description = "EverOS — local-first markdown memory framework for AI agents and user chats; lightweight, dev-friendly, small-team"
license = {text = "Apache-2.0"}
readme = "README.md"
Expand Down
5 changes: 4 additions & 1 deletion src/everos/memory/cascade/worker.py
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,10 @@ async def _process_one(self, row: MdChangeState) -> str | None:
if row.change_type == "deleted":
outcome = await handler.handle_deleted(row.md_path)
else:
outcome = await handler.handle_added_or_modified(row.md_path)
try:
outcome = await handler.handle_added_or_modified(row.md_path)
except FileNotFoundError:
outcome = await handler.handle_deleted(row.md_path)
except RecoverableError as exc:
last_error = f"{type(exc).__name__}: {exc}"
logger.warning(
Expand Down
29 changes: 29 additions & 0 deletions tests/unit/test_memory/test_cascade/test_worker.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,20 @@ async def handle_added_or_modified(self, md_path: str) -> HandlerOutcome:
raise RuntimeError("unexpected boom")


class _VanishedFileHandler(_OkHandler):
"""Simulate a file removed after its modified event was queued."""

def __init__(self) -> None:
self.deleted_paths: list[str] = []

async def handle_added_or_modified(self, md_path: str) -> HandlerOutcome:
raise FileNotFoundError(md_path)

async def handle_deleted(self, md_path: str) -> HandlerOutcome:
self.deleted_paths.append(md_path)
return await super().handle_deleted(md_path)


@pytest.fixture
def patched_repo(monkeypatch: pytest.MonkeyPatch) -> _FakeRepo:
"""Drop a fake repo onto the module the worker imports."""
Expand Down Expand Up @@ -157,6 +171,21 @@ async def test_bare_exception_marked_permanent(patched_repo: _FakeRepo) -> None:
assert retryable is False


async def test_modified_event_for_vanished_file_is_processed_as_delete(
patched_repo: _FakeRepo,
) -> None:
"""A stale modified event must not leave the indexed row behind."""
patched_repo.batch = [_Row(md_path="vanished.md", change_type="modified")]
handler = _VanishedFileHandler()
w = CascadeWorker({"episode": handler}, retry_backoff_seconds=0)

await w.drain_once()

assert handler.deleted_paths == ["vanished.md"]
assert patched_repo.done == ["vanished.md"]
assert patched_repo.failed == []


async def test_unknown_kind_marks_permanent_without_handler(
patched_repo: _FakeRepo,
) -> None:
Expand Down
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading