Skip to content

Commit 2b3cce7

Browse files
gloryfromcaclaude
andauthored
feat(*): upgrade everos to 1.4.1, lift the windows gate, guard the embedding width (#791)
## Summary EverOS 1.4.0 runs natively on Windows and 1.4.1 pins `openai` below 3, so the memory plugin's exact pin moves from `everos[multimodal]==1.2.3` to `==1.4.1`. The lock follows: `pyarrow` 24.0.0 -> 25.0.1 (EverOS's new floor), `everalgo-boundary` 0.2.0 -> 0.2.1, `everalgo-core` 0.4.0 -> 0.3.0 (EverOS now pins its everalgo layer with `==`), and `msvc-runtime` on `win32` only. `lancedb` stays at 0.34.0. Every internal everos symbol the adapter reaches is present in 1.4.1 with the same signature, so the adapter itself is unchanged. The plugin manifest and package version move to 1.4.0. **The Windows gate is gone.** `everos_platform_note` (#737) and its five call sites, `ServiceState.UNSUPPORTED`, the import.scan refusal (#750), the wizard's WSL notice and its zh catalogue line are removed; `_everos_executable` looks for `everos.exe` on `win32`. Spawning, probing and reusing the server were already portable. Identifying and stopping a stale server was not: `_cmdline_of` asked `ps`, and the marker `everos server start` never matched a Windows command line (`...\Scripts\everos.exe server start`). The command line now comes from WMI through PowerShell on `win32` and the marker accepts both shapes; `_listening_port` asks the TCP table through PowerShell there, walking the launcher's descendants: the socket belongs to the base interpreter two launchers below `everos.exe`. The server is spawned in a process group of its own (the Windows counterpart of `start_new_session`, which also keeps a Ctrl-C at the gateway off it) and stopped with Ctrl-Break, which uvicorn takes as a shutdown; one that ignores it for ten seconds, or one no group can be addressed to, gets `TerminateProcess` as before. And because Windows cannot replace a running executable, the upgrade helper stops whatever still runs from under the tool environment before it installs (the server outlives the gateway by design); without that, `uv` failed on `Scripts\everos.exe` with os error 32. Recorded in `docs/memory-plugin-architecture.md` section 7.4. **Two guards, found while verifying against a copy of a real 1.2.x store:** - `set_embedding_endpoint` measures the model's vector width before writing the pin and refuses anything narrower than the 1024-wide memory index (`REQUIRED_EMBEDDING_DIMENSIONS`), but only where an EverOS backend will read the pin: the `everos-memory` distribution is installed and the config names `everos` as the memory backend (an absent key is the schema default; an explicit `null` or another backend is not gated, and a knowledge base sizes itself to whatever width the model returns). The wizard's own check imports the same constant and probe. A 768-dimension model pinned through the settings page had left every memory store and search answering 500 about a mismatched width, with nothing on the page saying why. A probe that cannot reach the provider is not a verdict: the pin is written and a warning logged. The two RPC writers run the (now network-touching) writer in a thread. - `ensure_everos_server` reads the running server's `/health` version and, for a root raven owns, sends a mismatch with the installed everos through the same precheck / stop / spawn chain a rotated credential takes (`stale_reason`). Raven used to reuse whatever answered on the port, so an upgrade left the old server serving until something unrelated restarted it. A root the user manages is never touched. **The wire contract is pinned.** Every request body the plugin and the memory page send (`/add` with a tool exchange, `/flush`, the four `/search` shapes, the four `/get` kinds) is validated against everos 1.4.1's own request models in `TestRequestBodiesMatchEverosModels`, so a schema move on the next upgrade fails in the suite rather than as a 422 in a gateway log. **A six-angle review then hardened the degraded paths** (turn survival under every EverOS failure, Windows lifecycle, upgrade paths, the embedding guard, the wire contract, concurrency). The rule: memory degrades with a notice and never blocks a turn, a start or an upgrade. - A gateway starts the server again when it finds nothing listening (or a probe that timed out) and nothing holding the OME lock: only for a root raven owns, never over a child of its own, at most once per thirty seconds. The only spawn used to be in `start()`, so a server that went away left a running gateway without memory until restarted by hand. A stop that was sent and did not finish is not adopted (uvicorn closes the port at once and finishes what it had), so the version-mismatch restart after an upgrade cannot leave the gateway on a dying server. - A command-line lookup that failed (no `ps`, PowerShell blocked, WMI wedged, timeout) is distinct from a process that is gone: the stop keeps waiting, the lock names nothing, and a settings save over a server that answers but cannot be identified is reported as not applied. A losing spawn no longer overwrites the live server's pidfile. `stop_pid` counts wall time and takes a grace; on Windows a backend drains the server it started at `stop()`. - The upgrade helper asks again after `Stop-Process` and refuses to run `uv` while anything from the environment survives (an elevated or another user's process): `--force` removes the environment before writing and would have left every file but the one that could not go. - An embedding pin narrower than the index is measured at backend start (once per pin per process) and withheld from the spawn: EverOS runs keyword recall and keeps storing, and the notice names the model and width. This covers a pin written around the write-time check (before memory was on, unreachable at save time, edited by hand). The probe no longer raises on an odd response, times out at ten seconds, honours `plugins.disabled`; `migrate_roles` runs off the event loop it had put a provider round-trip onto. - The memory page uses the `/api/v2` routes (v1 is EverOS's legacy alias), asks `/health` before a search the way the chat adapter does, and shows the server's own sentence on a refusal. The recalled profile is rendered as lines rather than a `namespace(...)` repr with its evidence fields; a tool-call-only row stores empty content, not `"None"`; `top_k` stays within 1..100; an empty query asks nothing; a failed capability probe is not cached. The wizard accepts a model wider than 1024 (EverOS keeps the first 1024, as the settings page already allowed) and re-prompts on the host's refusal instead of a traceback. `docs/memory-plugin-architecture.md` section 7 records the upgrade (7.4) the way 7.3 recorded 1.2.1 -> 1.2.3. ## Type - [ ] Fix - [x] Feature - [ ] Docs - [ ] CI / tooling - [ ] Refactor - [ ] Other ## Verification Unit and RPC tests over every touched area: ``` env -u SERPER_API_KEY uv run --frozen --python 3.12 --extra dev pytest -q tests/test_everos_server.py tests/test_everos_backend.py tests/test_cli_onboard_commands.py tests/test_everos_discover.py tests/test_rpc_settings.py tests/test_everos_config.py tests/test_everos_plugin_discovery.py tests/test_cli_plugin_commands.py tests/test_core_plugin_stack.py tests/test_rpc_memory.py tests/test_rpc_import_sync.py tests/test_everos_http_adapter.py tests/test_memory_backend_protocol.py tests/test_memory_backend_contract.py tests/test_plugin_boundary.py tests/test_i18n_boundary.py tests/test_config_update*.py # 1312 passed, 1 skipped (inotify is Linux-only) on the first commit; 960 passed after the review round; full suite 26214 passed, 2 failed, 120 skipped, the 2 failing on an untouched github/main checkout too (LibreOffice path, background child env) uv run --frozen --python 3.12 --extra dev ruff check <changed files> # All checks passed! uv run --frozen --python 3.12 --extra dev ruff format --check <changed files> # 20 files already formatted ``` Against a 46 MB copy of a store written by everos 1.2.x (568 episodes, 5528 atomic facts, seven LanceDB tables), never touching the live one: - `everos server start` on 1.4.1 opens it with no schema complaint; `/health` reports `version 1.4.1`, `cascade.healthy true`. - The same four `/api/v2/memory/search` requests on 1.2.3 and 1.4.1 return the same ids in the same order; BM25 scores drift in the third decimal place. - `raven agent -m` on this branch spawns everos 1.4.1, a "remember this" turn lands in `episodes/episode-2026-09-24.md` and `.atomic_facts/`, a fresh one-shot session recalls it, and a third session recalls episodes written under 1.2.x months earlier. - With a 1.2.3 server left on the port, the next `raven agent -m` logs `runs everos 1.2.3 while this raven installs 1.4.1; restarting`, the old pid exits and `/health` reports 1.4.1. The 1.2.3 server had opened the index 1.4.1 wrote with no complaint. - Windows 11 box, this branch checked out and synced: `raven serve` spawns `everos.exe` natively, the Memory page shows its four tabs instead of the platform sentence, a chat turn lands as an episode (`/add` 200, `/flush` 200, cascade `upserted=1`), and after a memory role change the next start logs `holds credentials raven has since changed; restarting`, the old everos pid exits and the new one answers `/health` 1.4.1. - The settings page refuses `BAAI/bge-base-en-v1.5` on deepinfra with `returns 768-dimension vectors and the memory index is 1024 wide` (real probe), and the pin stays unchanged. - Adapter import smoke against 1.4.1: all 13 internal symbols present, signatures unchanged. - Windows 11 box, second round: with the server up, `uv pip install --reinstall --no-deps everos==1.4.1` fails on `Scripts\everos.exe` (os error 32, exit 2); after the helper's sweep (`Stopped what was still running from the old install (pid ...)`) the same command succeeds and the relaunched gateway spawns a fresh 1.4.1. A stop from the spawning console runs the full uvicorn shutdown (`Shutting down` ... `Finished server process`) in 3 s; a stop from another console falls back and the process is gone in 2 s. `lock_holder(root).port` reads 18997 (launcher -> venv python -> base python). - `tests/test_everos_server.py tests/test_updates_upgrade.py`: 261 passed, 1 skipped; `tests/test_everos_backend.py -k RequestBodies`: 7 passed. - Review round (`env -u SERPER_API_KEY uv run --frozen --python 3.12 --extra dev pytest` over the everos, config, settings, memory page, import, onboard, plugin-stack, boundary, cycle-budget and contract files): 1225 passed, 1 skipped; `test_everos_server.py` 124, `test_everos_backend.py` 188. - Windows 11 box, review round: with the gateway serving, the everos launcher was terminated by hand (`Stop-Process`, nothing on 18997); the next turn answered without memory (`recall failed ... state=unresponsive`), and six seconds after it began the gateway logged `started everos server` / `everos server ready`, the pidfile named the new pid and `/health` answered 1.4.1. The first attempt did not fire because a dead port there takes 2-4 s to be refused, longer than the 1 s probe; the respawn now fires on a timed-out probe as well, guarded by the lock holder. The memory page's four counts and a search on the Cases tab went through the v2 routes. - [x] Relevant tests pass locally - [x] Relevant lint / type checks pass locally - [x] User-facing docs or screenshots are updated when needed ## Risk - Windows installs that used to read "long-term memory is not available on Windows yet" now spawn EverOS, and a stale server is identified and replaced there too. The stop there is Ctrl-Break with a ten-second fallback to `TerminateProcess`. An upgrade on Windows first stops every process whose executable lives under the tool environment: raven's own gateway, sub-agents and server, nothing outside that directory. - An embedding pin narrower than 1024 dimensions is refused at the settings page and the wizard, with the width in the message, only for an install whose memory runs on EverOS (plugin installed, backend `everos` or the default). Knowledge-only installs, memory off, and other backends keep any width. Existing pins are not touched. - An owned EverOS server whose version differs from the installed package is restarted on the next session start. A root the user manages is never restarted. - A gateway may now start an EverOS server on its own when its probe finds nothing listening and nothing holding the lock (owned roots only, at most every thirty seconds). On Windows a backend stops the server it started when it shuts down (Ctrl-Break, sixty seconds to drain), so a settings change or an upgrade there restarts the server rather than leaving it. An upgrade on Windows refuses to proceed while a process from the tool environment cannot be stopped, and says which pid. - An embedding pin narrower than 1024 that reached the config around the settings check is no longer handed to EverOS: recall runs on keywords with a notice naming the model, until a 1024-dimension model is pinned. - Rollback: revert the commit and `uv sync`. `lancedb` did not move, so an index written by 1.4.1 opens under 1.2.3 (exercised on the copy). - [x] Security impact considered - [x] Backward compatibility considered - [x] Rollback path is clear for risky changes ## Related Issues N/A --------- Co-authored-by: gloryfromca <23442919+gloryfromca@users.noreply.github.com> Co-authored-by: Claude (claude-fable-5-1) <noreply@anthropic.com>
1 parent e176941 commit 2b3cce7

32 files changed

Lines changed: 2299 additions & 429 deletions

‎docs/memory-plugin-architecture.md‎

Lines changed: 136 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ imported.
315315

316316
## 7. EverOS version pinning & upgrade SOP
317317

318-
### 7.1 Exact pin is mandatory **[DONE: `everos[multimodal]==1.2.3`]**
318+
### 7.1 Exact pin is mandatory **[DONE: `everos[multimodal]==1.4.1`]**
319319

320320
The adapter is written against EverOS **internal** APIs, not a stable
321321
public surface:
@@ -333,8 +333,8 @@ is pinned to an exact version (`==X.Y.Z`), not a range: upgrades are
333333
deliberate, re-validated events, never something `uv lock --upgrade`
334334
can do silently.
335335

336-
Single pin: with `raven_everos` removed, EverOS is pinned in **one**
337-
place (raven's `pyproject.toml`). The upgrade surface is one line.
336+
Single pin: EverOS is pinned in **one** place, the plugin's own
337+
`plugins-dist/everos-memory/pyproject.toml`. The upgrade surface is one line.
338338

339339
### 7.2 Upgrade procedure
340340

@@ -343,7 +343,7 @@ place (raven's `pyproject.toml`). The upgrade surface is one line.
343343
(`~/.everos/.index/` sqlite + lancedb) changed.
344344
1. **Bump the pin (uv only — never hand-edit pyproject/lock)**:
345345
```bash
346-
uv add 'everos[multimodal]==1.2.3' && uv sync
346+
uv add --package everos-memory 'everos[multimodal]==1.4.1' && uv sync
347347
```
348348
Always keep the `[multimodal]` extra. Skip `1.2.0`: it shipped a
349349
path-traversal regression fixed in `1.2.1`.
@@ -418,6 +418,138 @@ until the session restarts. And `everos cascade rebuild`, now the
418418
supported index recovery, refuses to run while a server holds the OME
419419
lock — while raven exposes no way to stop the server it started.
420420

421+
### 7.4 Record: `1.2.3` -> `1.4.1`
422+
423+
Five packages moved: `everos` `1.2.3` -> `1.4.1`, `pyarrow` `24.0.0` ->
424+
`25.0.1` (EverOS's new floor), `everalgo-boundary` `0.2.0` -> `0.2.1` and
425+
`everalgo-core` `0.4.0` -> `0.3.0` (EverOS now pins its everalgo transitive
426+
layer with `==`, so the resolver follows it down), and `msvc-runtime` joins
427+
on `win32` only. `lancedb` stays at `0.34.0`.
428+
429+
**No adapter change.** Every internal symbol the adapter reaches
430+
(`MemoryRoot`, `episode_repo` / `agent_skill_repo`, `EpisodeWriter` /
431+
`AgentSkillWriter`, the `init_cmd` templates, the multimodal parser and
432+
client, the two error classes) is present in `1.4.1` with the same
433+
signature.
434+
435+
**No data migration.** A copy of a 46 MB store written by `1.2.x` (568
436+
episodes, 5528 atomic facts, seven LanceDB tables at table schema version 2)
437+
started under `1.4.1` with no schema complaint and a healthy cascade. The same
438+
keyword searches returned the same ids in the same order on both versions;
439+
BM25 scores drift in the third decimal place. First start builds an IVF_FLAT
440+
index on any vector column past 2000 rows (`atomic_fact` here) -- seconds, and
441+
searches keep working meanwhile. A real turn through raven then wrote a new
442+
episode into that store and a fresh session recalled it, alongside episodes
443+
written months earlier under `1.2.x`. Rollback was not exercised this time;
444+
`lancedb` did not move, so the file format is the one `1.2.3` already reads.
445+
446+
**A running server from before the upgrade is replaced.** raven used to
447+
reuse whatever answered on the configured port, so an EverOS `1.2.3` left
448+
running kept serving after the pin moved, with every surface green.
449+
`ensure_everos_server` now reads the running server's `/health` version and,
450+
for a root raven owns, sends a mismatch through the same precheck / stop /
451+
spawn chain a rotated credential takes (`stale_reason`). A root the user
452+
manages is theirs to restart. `everos cascade sync`, `cascade fix --apply` and
453+
`cascade rebuild` refuse to run beside a running server (exit code 3).
454+
455+
**Windows.** `1.4.0` runs natively on Windows, so the platform gate raven
456+
carried (`everos_platform_note`, `ServiceState.UNSUPPORTED`, the wizard's
457+
WSL notice) is gone and `_everos_executable` looks for `everos.exe` there.
458+
Spawning, probing and reusing the server were already portable. Identifying
459+
and stopping a stale server was not: `_cmdline_of` asked `ps`, and the marker
460+
`everos server start` never matched a Windows command line, which prints the
461+
executable as `...\Scripts\everos.exe server start`. The command line now
462+
comes from WMI through PowerShell on `win32` and the marker accepts both
463+
shapes; the pidfile raven writes at spawn already named the pid. Verified on
464+
a Windows 11 box: a changed memory role sent the running server through
465+
"holds credentials raven has since changed; restarting", the old pid exited
466+
and the new one answered `/health`. `_listening_port` asks the TCP table
467+
through PowerShell there (no `lsof`, no `/proc`), walking the launcher's
468+
descendants because the socket belongs to the base interpreter two launchers
469+
below `everos.exe`. The stop is Ctrl-Break: the child is spawned in a process
470+
group of its own (`CREATE_NEW_PROCESS_GROUP`, the Windows counterpart of
471+
`start_new_session`, and what keeps a Ctrl-C at the gateway off the server),
472+
uvicorn takes the event as a shutdown, and a server that has not acted on it
473+
in ten seconds -- one another console started, which the event cannot reach
474+
-- gets `TerminateProcess`, the stop every server there had before. Verified
475+
on the same box: a stop from the spawning console runs the full uvicorn
476+
shutdown (`Shutting down` ... `Finished server process`) in three seconds; a
477+
stop from another console falls back and the process is gone in two.
478+
479+
**The upgrade helper sweeps the environment on Windows.** Windows cannot
480+
replace an executable that is running, and the server outlives the gateway
481+
by design, on the environment's own python: with it up, `uv` failed to
482+
replace `Scripts\everos.exe` (`os error 32`). After waiting for the parent,
483+
the helper now stops every process whose executable lives under the tool
484+
environment -- that directory and nothing wider -- and only then installs.
485+
Verified on the box: the same reinstall that failed with the server up
486+
succeeds after the sweep, and the relaunched gateway spawns a fresh server.
487+
488+
**What a six-angle review of the branch then changed.** Each item is a
489+
scenario a real install can reach; the rule behind them is that memory
490+
degrades with a notice and never blocks a turn, a start or an upgrade.
491+
492+
- A gateway starts the server again when it finds nothing listening
493+
(`EverosBackend._may_respawn` / `_respawn`): only for a root raven owns, only
494+
when no child of its own still runs, only when nothing holds the OME lock,
495+
at most once per thirty seconds. Before, the only spawn was in `start()`,
496+
which a running gateway never passes through again, so a server that went
497+
away -- an upgrade's sweep, a crash, a stop another process sent -- left the
498+
gateway without memory until it was restarted by hand.
499+
- A stop that was sent and did not finish (`STILL_DRAINING`: uvicorn closes
500+
the port at once and finishes the requests it had, an extraction included)
501+
is no longer adopted by `ensure_everos_server`; it raises, the backend keeps
502+
probing, and the probe above starts a replacement once the lock is free.
503+
Adopting it reported memory over a process that no longer answered.
504+
- A command-line lookup that failed (`_cmdline_of` -> `None`: no `ps`,
505+
PowerShell blocked, WMI wedged, the timeout hit) is distinct from a process
506+
that is gone. A stop keeps waiting on it; `lock_holder` identifies nothing;
507+
`restart_for_config_change` reports "could not be identified" instead of
508+
applied when something still answers on the address.
509+
- A spawn that loses the boot race no longer overwrites the pidfile of the
510+
live server (`_start_server_if_unlocked`): on Windows the pidfile is the
511+
only way back to it.
512+
- `stop_pid` counts wall time (each Windows poll launches PowerShell) and takes
513+
a `grace`; on Windows a backend drains the server it started itself at
514+
`stop()` (Ctrl-Break, sixty seconds), so an upgrade finds nothing to
515+
terminate mid-write and a settings change restarts it cleanly.
516+
- The helper's sweep asks again after `Stop-Process` and refuses to run `uv`
517+
while anything from the environment survives (elevated or another user's
518+
process): `uv tool install --force` removes the environment before it
519+
writes, and would have left every file but the one that could not go.
520+
- An embedding pin narrower than the index is measured at backend start
521+
(`configured_embedding_width`, once per pin per process) and withheld from
522+
the spawn (`withhold_role`): EverOS runs keyword recall and keeps storing,
523+
and the notice names the model and the width. The write-time check covers a
524+
pin written through raven; this covers one written around it. The probe no
525+
longer raises on an odd response, times out at ten seconds, and an install
526+
with the plugin on `plugins.disabled` is not gated. `migrate_roles` runs off
527+
the event loop, which the probe had put a provider round-trip onto.
528+
- The memory page calls the `/api/v2` routes (v1 is EverOS's legacy alias),
529+
asks `/health` before a search the way the chat adapter does (keyword
530+
without embedding, the LLM rerank on the agent track without a
531+
cross-encoder, the profile opted in), and shows the server's own sentence
532+
on a refusal instead of "unreachable".
533+
- The recalled profile is rendered as lines again: the search response
534+
arrives as namespaces, and the renderer, handed one, had put
535+
`namespace(explicit_info=[namespace(...)])` -- evidence fields included --
536+
into every prompt. A tool-call-only assistant row is stored with empty
537+
content, not `"None"`; `top_k` is clamped to the server's 1..100; an empty
538+
query asks nothing; a `/health` probe that failed is not cached as "no
539+
capabilities" for the life of the adapter.
540+
- The wizard accepts a model wider than 1024 (EverOS keeps the first 1024,
541+
the settings page already accepted it) and turns the host's refusal into a
542+
re-prompt rather than a traceback.
543+
544+
**One guard added alongside.** The live install was found pinned to a
545+
768-dimension embedding model against this 1024-wide index, with every store
546+
and search answering 500. `set_embedding_endpoint` now measures the model's
547+
width before writing the pin and refuses anything narrower than
548+
`REQUIRED_EMBEDDING_DIMENSIONS`, but only where the config names EverOS as
549+
the memory backend: a knowledge base sizes itself to whatever width the
550+
model returns, so an install with memory off or on another backend keeps
551+
any width. The wizard's own check reads the same constant and probe.
552+
421553
---
422554

423555
## 8. Validation (this change)

‎plugins-dist/everos-memory/pyproject.toml‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "everos-memory"
3-
version = "1.2.0"
3+
version = "1.4.0"
44
description = "EverOS memory backend for Raven: dual-track semantic recall and the understand_media tool"
55
requires-python = ">=3.12"
66
license = "Apache-2.0"
@@ -20,7 +20,7 @@ dependencies = [
2020
# The substrate this adapter binds. Exact pin, not a range: the adapter
2121
# reaches internal (non-public) everos APIs, so an upgrade is a deliberate
2222
# act. Same pin the host carried while the plugin lived inside it.
23-
"everos[multimodal]==1.2.3",
23+
"everos[multimodal]==1.4.1",
2424
"httpx>=0.28.0,<1.0.0",
2525
"loguru>=0.7.3,<1.0.0",
2626
"tomli-w>=1.2.0",

‎plugins-dist/everos-memory/raven_everos/__init__.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,4 @@
3232
Anything else in the package is the plugin's own.
3333
"""
3434

35-
__version__ = "1.1.0"
35+
__version__ = "1.4.0"

0 commit comments

Comments
 (0)