Skip to content

v0.2.19

Choose a tag to compare

@het0814 het0814 released this 01 Sep 20:00
· 21 commits to main since this release
b3cc625

Release Notes for v0.2.19

This release makes MEMANTO survive an idle gap. Previously, once a session's expiry window fully lapsed, every entry point CLI, SDK, and REST, failed with 401 / "No active session. Call activate_agent()", forcing a manual re-activation. Sessions now transparently recreate themselves on the next request, gated behind the same management-access check as explicit activation, with a new auto_recreate_enabled toggle wired end-to-end through env vars, config.yaml, the CLI, and the Web UI.

New Features

  • Automatic session recreation after expiry (memanto/app/services/session_service.py, memanto/app/routes/auth_deps.py)
    • New SessionService.check_and_auto_recreate() complements check_and_auto_renew: where renewal keeps a live session going near expiry, this issues a brand-new session (new JWT, fresh expiry window) when a caller presents the token of a session that has already fully lapsed.
    • get_current_session now catches SessionExpiredError and attempts recreation before failing. Authorization reuses require_management_access (valid management credential or loopback caller), so a stolen stale token alone is worthless.
    • On success the route mirrors the auto-renewal handoff: refreshes the browser cookie when one was sent, and returns the replacement token via the X-Session-Token response header.
    • Safety rails: deliberately terminated (logged-out) sessions are never resurrected; a stale token whose persisted record was already replaced by a newer session never supersedes it; foreign, malformed, or unsignable tokens fall through to normal validation; an agent id that is no longer a safe id returns None rather than raising a 500 out of the auth dependency.
    • CLI and SDK direct paths (memanto/cli/client/direct_client.py, memanto/cli/client/sdk_client.py) call the same recreation path on SessionExpiredError and update their cached session and token in place. InvalidSessionTokenError is still surfaced unchanged.
  • SESSION_AUTO_RECREATE_ENABLED configuration toggle (memanto/app/config.py, .env.example, memanto/cli/config/manager.py, memanto/app/ui/static/index.html)
    • New setting, defaulting to True, exposed as the SESSION_AUTO_RECREATE_ENABLED env var, the session.auto_recreate_enabled key in config.yaml, a memanto config boolean, and an "Auto-create a fresh session after expiry (next request)" toggle in the Web UI settings panel.
    • Documented in .env.example alongside the existing SESSION_* knobs.

Improvements

  • Session toggles in config.yaml now actually reach the server (memanto/app/config.py)
    • SessionService reads auto_renew_enabled / auto_recreate_enabled off settings, but the Web UI and memanto config persist them to config.yaml. The startup overlay now maps both YAML keys onto their env vars, so they are no longer inert for the server and only half-honoured by the CLI. Uses setdefault, so an explicitly exported SESSION_AUTO_* (containerised deployments) still wins.
  • UI config changes apply without a restart (memanto/app/ui/routes/ui_router.py)
    • config.yaml is overlaid onto settings only at process start, so flipping the session toggles in the UI previously did nothing until the next restart. update_ui_config now applies auto_renew_enabled and auto_recreate_enabled to the running server's settings as well.
  • Single toggle governs CLI re-activation (memanto/cli/commands/_shared.py)
    • get_client() no longer re-reads the YAML session config for its own gate. Expiry is handled upstream by get_active_session(), so what remains here is the rotated-MEMANTO_SECRET_KEY case (a token that no longer verifies at all, which used to break analyze LLM narratives mid-run). It is now gated on settings.SESSION_AUTO_RECREATE_ENABLED like every other path, so turning auto-recreate off disables it everywhere.

Bug Fixes

  • Idle CLI sessions were stranded instead of recreated (memanto/app/services/session_service.py)
    • get_active_session() cleared the active marker as soon as the session it named had lapsed, so every CLI entry point — which all resolve their session through that marker reported "No active session. Call activate_agent()" regardless of the auto-recreate setting. It now attempts recreation first and returns the fresh session.
    • Recreation deliberately runs outside the active-marker lock: it takes the agent lifecycle lock, and delete_session takes those two in the opposite order, so holding both would invert the lock order and risk deadlock.
    • When recreation is declined (disabled by config, or a terminated session), the stale marker is dropped only if it still names the same lapsed session and that session is still not active, another thread may have activated in the meantime.
    • Marker reading was extracted to _read_active_marker_agent_id() so the re-check after recreation shares exactly the symlink/Windows-file handling of the original read.

Tests

  • tests/conftest.py: new autouse reset_session_toggles fixture pins SESSION_AUTO_RENEW_ENABLED and SESSION_AUTO_RECREATE_ENABLED to their defaults, so a developer who has switched either off locally no longer changes how the suite behaves.
  • tests/test_api.py: new TestSessionAutoRecreate covers the header path issuing a fresh token, a remote caller without a management credential getting no new session, terminated sessions not being recreated, and the behaviour with the toggle disabled.
  • tests/test_unit.py: check_and_auto_recreate unit coverage, reviving an expired session, invalidating the old token, never reviving a terminated session, skipping still-active sessions, honouring the disabled config, and ignoring foreign/malformed tokens; plus get_active_session recreating a lapsed session, clearing the marker when recreate is disabled, and refusing to revive a terminated session.
  • tests/test_session_config_overlay.py: new file verifying that YAML session toggles reach settings, that environment variables override YAML, and that missing or malformed config keeps the defaults.

Full Changelog

Full Changelog: v0.2.18...v0.2.19