v0.2.19

anomalyco/opentuiv0.2.19Sep 1, 2026by het0814

AI Summary

This release implements automatic session recreation after expiry, allowing MEMANTO to survive idle gaps without manual re-activation. It introduces a new configuration toggle to control this behavior across the CLI, SDK, and Web UI.

Key Highlights

  • Automatic session recreation after expiry
  • New `SESSION_AUTO_RECREATE_ENABLED` configuration toggle
  • Session toggles in `config.yaml` now reach the server
  • UI config changes apply without a restart
  • Idle CLI sessions are recreated instead of stranded

New Features

  • Automatic session recreation after expiry
  • `SESSION_AUTO_RECREATE_ENABLED` configuration toggle

Full Release Notes

# 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: https://github.com/moorcheh-ai/memanto/compare/v0.2.18...v0.2.19