Skip to content

EverOS 1.4.2

Latest

Choose a tag to compare

@github-actions github-actions released this 14 Oct 13:49
· 5 commits to main since this release
5d9fd4d

A server that stays healthy for days, not hours. Three faults in this
release compounded on exactly the deployments that ran longest: a long-lived
index leaked file descriptors until searches took seconds, interactive searches
queued behind the cascade's background embedding, and a memory root holding more
than one project had each project's index rows overwrite the other's. All three
are fixed, and a LanceDB root that the last fault already damaged repairs itself
on the first start after upgrading.

Changed

  • [embedding].max_concurrent defaults to 10 instead of 5. The
    EmbeddingSettings class default (50) is aligned to the same value; the
    shipped default.toml always overrode it, so the effective default moves
    from 5 to 10. (#486)

  • Milvus collections must be rebuilt once after upgrading. They gain the
    __pk primary-key column; the server refuses to start on an old
    collection and names everos cascade rebuild, which recreates them from
    markdown.

  • Response ids are unique within (app_id, project_id), not globally; the
    shape of id is unchanged.

  • The cascade optimizes a LanceDB table at most once a minute, not once
    every ten seconds.
    Each optimize pass leaves an _indices/<uuid>/
    directory behind until cleanup reclaims it, so the old 10 s floor set the
    ceiling on how many could pile up: about 126k directories a day and ~1.8M
    at the retention horizon. The 60 s default costs a sixth of that (~21k a
    day, ~300k at the horizon, roughly 1.2 GB) and keeps a full index sweep
    inside its 60 s deadline. The interval is a built-in floor on how often a
    table may be optimized, not a setting; a write-heavy deployment sees an
    index that trails its markdown by up to a minute longer than before.

Fixed

  • A long-running server no longer leaks file descriptors on LanceDB index
    readers.
    Every optimize() mints a new index version whose reader is
    kept in a session cache, and that reader holds the descriptors of its
    _indices/<uuid>/ files. Lance keys those cache entries by dataset
    version and never evicts them when cleanup deletes the files underneath
    (lance-format/lance#7718), so the count grew for the life of the
    process: a 65-minute soak went from 74 to 558 index descriptors with no
    plateau, and a deployment on a 1024-descriptor limit exhausts it in
    hours. EverOS capped only one of the session's two caches and left the
    metadata cache unbounded, which is the one that decides whether the count
    converges. Both are now capped ([lancedb].metadata_cache_size_bytes,
    default 1 MB): the same soak holds between 6 and 82 descriptors, falling
    as often as it rises. Reported upstream as lance-format/lance#9934.

  • An interactive search no longer queues behind the cascade's embedding
    work.
    Query embeddings and background write embeddings shared one
    process-wide semaphore, so a burst of writes put the query a user was
    waiting on at the back of the queue. Under three concurrent writers,
    vector search p50 measured 46 s and p95 112 s, while the keyword leg —
    which needs no embedding — answered in 0.35 s. Queries now draw on their
    own budget ([embedding].query_max_concurrent, default 4): vector p50
    drops to 0.60 s and p95 to 3.70 s under the identical load. Total
    in-flight requests to the endpoint become max_concurrent + query_max_concurrent rather than a silently shared bound. (#473)

  • The same owner's memories in two projects no longer overwrite each other
    in the derived index.
    Index rows were merged on id alone, and id is
    unique only within one (app_id, project_id): a user's episodes, atomic
    facts, agent cases, foresights, skills and profile written under a second
    project replaced the first project's rows (markdown was never affected).
    Every table now declares PRIMARY_KEY = ("app_id", "project_id", "id");
    LanceDB merges on it and Milvus keys its collections on the composed
    __pk column. Profile search and get, the handlers' change detection and
    the vector backfill address rows by the full key; the backfill also keeps
    each row's own vector within a batch, and reflection deprecates atomic
    facts only inside the project it merged.

  • A multi-project LanceDB root indexed before this release gets its
    overwritten rows back by itself.
    The first full pass over the root
    after upgrading (server start, or everos cascade sync) re-reconciles
    every indexed markdown file against the index once and records that in
    .index/.index_reconcile_version. Entries whose rows are present and
    unchanged are skipped by digest, so a healthy root pays one read pass
    and no embedding; only the rows that were lost are re-embedded.
    everos cascade sync --force-all runs the same pass on demand. Two
    roots need that command instead: a server started with
    EVEROS_DISABLE_CASCADE=1 never runs the pass (stop it and run
    everos cascade sync --force-all once), and a multi-project root where
    reflection ran before this release needs everos cascade rebuild once,
    because the pass does not clear the deprecated_by stamps one project's
    reflection left on another project's rows.

  • POST /cascade/quiesce freezes a complete index. Its drain stopped
    at the worker's per-drain bound, and inside a server it could also stop
    while the background worker still held the last batch, which the stop
    that follows then orphaned in processing; the ledger an upgrade
    re-queues made both routine. The drain now runs until the ledger holds
    nothing pending, waiting for the worker's in-flight batch, and
    everos cascade sync / rebuild use the same loop.

  • A cascade pass embeds a file's changed entries in one batched request,
    not one request per entry.
    The four daily-log handlers (episode, atomic
    fact, foresight, agent case) each called the embedding endpoint once per
    entry, so a turn that wrote ~20 atomic facts queued ~20 single-input
    requests on the process-wide embedding semaphore, and the next search's
    query embedding waited behind all of them: about five times the
    endpoint's latency at the previous default max_concurrent = 5. The
    handlers now
    send every text of a file through embed_batch, which
    [embedding].batch_size splits into requests (23 entries become 3
    requests at the default 10), so after a single turn's writes the query
    embedding waits for one request; a large backlog still queues ahead of
    it (#473). (#486)

  • Changing a knowledge document's category keeps it inside knowledge/.
    PATCH /knowledge/documents/{doc_id} with category_id set to .. moved
    the document's directory up into the project directory, where the markdown
    scan no longer finds it. The category now goes through the same rule as
    document creation, so . and .. fall back to Others, and the move is
    refused if its target would leave knowledge/. A document an earlier move
    left outside is moved back on its next category change. Reported by
    White0xdi3.

Upgrade

pip install --upgrade everos   # or: uv sync

pip install --upgrade everos is enough for most roots: the first full pass
after the upgrade (server start, or everos cascade sync) re-reconciles every
indexed markdown file against the index once, re-embeds only the rows that were
lost, and records that it ran in .index/.index_reconcile_version. A healthy
root pays one read pass and no embedding.

Three roots need a command instead:

  • A root where reflection already ran across projects — everos cascade rebuild once. The automatic pass does not clear the deprecated_by stamps
    one project's reflection left on another project's rows.
  • A server started with EVEROS_DISABLE_CASCADE=1 — it never runs the
    pass. Stop it and run everos cascade sync --force-all once.
  • A Milvus derived index — everos cascade rebuild once. Collections gain
    the __pk primary-key column and the server refuses to start on an old
    collection.

Full changelog: v1.4.1...v1.4.2