# Agentic Memory (AgeMem): Technical Analysis and Application to Swival

**Paper:** "Agentic Memory: Learning Unified Long-Term and Short-Term Memory Management for Large Language Model Agents"
**Authors:** Yi Yu, Liuyi Yao, Yuexiang Xie, Qingquan Tan, Jiaqi Feng, Yaliang Li, Libing Wu (Alibaba Group / Wuhan University)
**Published:** January 2026, arXiv:2601.01885v1

---

## 1. Problem Statement

LLM agents operating over long-horizon tasks are fundamentally constrained by finite context windows. Memory management — deciding what to keep, what to store externally, and what to discard — is critical for sustained performance. The paper identifies that existing approaches treat **long-term memory (LTM)** and **short-term memory (STM)** as independent, loosely-coupled systems, optimized separately with different heuristics. This fragmented design leads to suboptimal behavior.

Three concrete challenges motivate the work:

- **C1 — Functional heterogeneity coordination:** LTM and STM serve complementary purposes (LTM: store/update/discard persistent knowledge; STM: retrieve/summarize/filter active context). No unified mechanism orchestrates their interplay.
- **C2 — Training paradigm mismatch:** LTM training uses session-level info upfront, STM training injects distractors for long contexts. Standard RL assumes continuous trajectories, but memory operations produce inherently fragmented and discontinuous experiences.
- **C3 — Practical deployment constraints:** Many systems require an auxiliary expert LLM for memory control, increasing inference cost and complexity.

## 2. The AgeMem Framework

AgeMem's central insight: **treat memory management as part of the agent's own policy, not as an external module.** Memory operations become tool calls that the LLM invokes autonomously — the same way it might call a file reader or a search engine.

### 2.1 Formal Setup

At each timestep *t*, the agent observes state *s_t = (C_t, M_t, T)* where:
- **C_t** = short-term memory (the current conversation context / message list)
- **M_t** = long-term memory store (persistent entries with embeddings and metadata)
- **T** = task specification (query *q*, contextual info *I_q*, expected answer *A_q*)

The agent selects action *a_t* from a hybrid action space that includes both language generation and memory operations. A parameterized policy *pi_theta* governs decisions. The optimization objective maximizes cumulative reward across trajectories:

```
R(tau) = sum(w_i * R_i(tau)) + P_penalty(tau)
```

where *R_i* covers task performance and memory quality, and *P_penalty* discourages violations (context overflow, excessive turns).

### 2.2 Memory Tools

AgeMem exposes six tools, split across the two memory types:

| Tool | Target | Function |
|------|--------|----------|
| **Add** | LTM | Add new knowledge to M_t. Creates entry with content, embedding `enc(c)`, and metadata (timestamp, source, tags) |
| **Update** | LTM | Modify existing entries in M_t. Requires memory_id from prior retrieval. Updates content, re-computes embedding, refreshes metadata |
| **Delete** | LTM | Remove obsolete/incorrect entries from M_t. Requires memory_id and explicit confirmation flag |
| **Retrieve** | STM | Fetch top-k entries from M_t by cosine similarity to a query, inject into C_t |
| **Summary** | STM | Compress conversation spans in C_t (all messages, or last N). Uses LLM with a summarization prompt. Replaces original messages with condensed version |
| **Filter** | STM | Remove messages from C_t whose semantic similarity to a criteria string exceeds threshold theta=0.6. Used to strip distractors |

The key design property: these are regular tool-call schemas. The LLM decides **when, what, and how** to invoke them, based on its own reasoning. No external controller, no trigger schedule.

### 2.3 Three-Stage Progressive Training

Training uses a trajectory structure that mirrors the natural progression of memory-augmented problem solving. Each task instance produces a three-stage trajectory:

**Stage 1 — LTM Construction (T_1 turns):**
The agent is exposed to contextual information *I_q* through casual conversation. It must identify salient facts and store them using Add/Update/Delete. The task query *q* hasn't been revealed yet — the agent must make general-purpose storage decisions. LTM *M_t* persists across all stages; the context *C_t* is reset before Stage 2.

**Stage 2 — STM Control Under Distractors (T_2 turns):**
The constructed LTM is retained, but the context is filled with semantically related but irrelevant distractor messages. The agent must learn to use Filter (remove by similarity threshold) and Summary (compress for space) to keep context clean and focused. This stage trains proactive context management — the agent learns to act before overflow, not after.

**Stage 3 — Integrated Reasoning and Memory Coordination (T_3 turns):**
The actual query *q* arrives. The agent must retrieve from LTM, manage STM, reason, and produce a final answer. This tests the full coordination of both memory types plus task-solving ability.

### 2.4 Step-wise GRPO

The paper adapts Group Relative Policy Optimization (GRPO) for the discontinuous, multi-stage trajectory structure.

**Standard GRPO** computes group-normalized advantages across *K* independent rollouts of the same task. AgeMem's modification: the terminal reward (computed only at the end of Stage 3) is **broadcast backward** to all preceding timesteps across all three stages. This means a Stage 1 memory storage decision gets supervised by the final task outcome — enabling long-range credit assignment across heterogeneous stages.

The advantage for trajectory *k* of task *q* at the terminal step:

```
A_T^(k,q) = (r_T^(k,q) - mu_G_q) / (sigma_G_q + epsilon)
```

This terminal advantage is then copied to all preceding steps: `A_t^(k,q) = A_T^(k,q)` for all *t*. The policy update uses importance-weighted gradient ascent with KL regularization against a reference policy.

### 2.5 Reward Function

The composite reward has three main components plus penalties:

```
R(tau) = w^T * [R_task, R_context, R_memory]^T + P_penalty
```

All weights set to 1/3 (uniform).

**R_task — Task Completion:**
LLM-as-a-judge score `S_judge(A_pred, A_q) in [0,1]`. Penalty of -1.0 if no answer produced.

**R_context — Context Management (STM behavior):**
Three sub-components (each weighted 1/3):
- *Compression efficiency:* `max(0, 1 - T_used/T_max)` — reward compact final context
- *Preventive management:* 1 if agent invoked context-reduction tool before overflow, 0 otherwise
- *Information preservation:* 1 if key entities/phrases from query are still present at answer time

**R_memory — Memory Management (LTM behavior):**
Three sub-components (each weighted 1/3):
- *Storage quality:* Fraction of stored entries judged high-quality by LLM evaluator
- *Maintenance:* Binary reward for performing update or delete operations (encourages hygiene)
- *Semantic relevance:* LLM-scored relevance between retrieved memories and the query

**P_penalty — Constraint Violations:**
- Exceeding max rounds: -1.0
- Context overflow (T_used > T_max): -0.5

## 3. Experimental Results

### 3.1 Benchmarks and Setup

Evaluated on five long-horizon benchmarks: ALFWorld (embodied action), SciWorld (science experiments), PDDL (planning), BabyAI (grid navigation), HotpotQA (multi-hop QA). Base models: Qwen2.5-7B-Instruct and Qwen3-4B-Instruct. Trained with RL on HotpotQA only, evaluated across all five.

### 3.2 Key Results

- **AgeMem achieves highest average performance** on both backbones: 41.96% (Qwen2.5-7B) and 54.31% (Qwen3-4B), outperforming all baselines including LangMem, A-Mem, Mem0, and Mem0^g.
- **Relative gains:** +49.59% over no-memory baseline (Qwen2.5-7B), +23.52% (Qwen3-4B).
- **RL contributes significantly:** AgeMem-noRL (same tools, no RL training) scores 33.43 / 45.59 vs. AgeMem's 41.96 / 54.31. That's +8.53 / +8.72 percentage points from RL alone.
- **Memory quality:** AgeMem achieves highest Memory Quality scores (0.533 on Qwen2.5-7B, 0.605 on Qwen3-4B) — stored memories are more relevant to ground-truth facts.
- **Token efficiency:** AgeMem's learned STM tools reduce prompt tokens by 3.1-5.1% compared to RAG-only variants, while maintaining or improving task performance.

### 3.3 Ablation Highlights

Progressive addition of components (on Qwen2.5-7B):
- Base (no memory): 27.16 / 13.80 / 38.36 (ALFWorld / SciWorld / HotpotQA)
- +LT (LTM tools only): +10.6% / +14.2% / +7.4%
- +LT/RL (LTM + RL): further +3.3% / +4.7% / +6.3%
- +LT/ST/RL (full AgeMem): +13.9% / +21.7% / +16.1% total

The biggest STM boost is on SciWorld (+3.1%) and HotpotQA (+2.4%), tasks with the most context pressure.

## 4. Relation to Swival's Existing Architecture

Swival already has surprisingly strong parallels to AgeMem's design — many of the building blocks exist, but they're organized differently and not unified under a single learned policy.

### 4.1 Mapping AgeMem Concepts to Swival Components

| AgeMem Concept | Swival Equivalent | Key Differences |
|----------------|-------------------|-----------------|
| **Long-term Memory (M_t)** | `.swival/memory/MEMORY.md` via `load_memory()` | Swival's LTM is a flat markdown file (max 200 lines, 8K chars) loaded into the system prompt. No embeddings, no structured retrieval, no semantic search. Written manually via `/learn` REPL command |
| **Short-term Memory (C_t)** | Message list in `run_agent_loop()` | Direct equivalent — the conversation context |
| **Add (LTM)** | `/learn` command in REPL | User-triggered only, not agent-autonomous. Appends to MEMORY.md |
| **Update (LTM)** | No equivalent | Agent cannot update existing memory entries |
| **Delete (LTM)** | No equivalent | Agent cannot remove stale memories |
| **Retrieve (LTM)** | Always loaded in system prompt | No selective retrieval — entire memory file is always present. No embedding-based search |
| **Summary (STM)** | `compact_messages()`, `drop_middle_turns()`, `SnapshotState.restore()` | Swival has three graduated compaction levels. Snapshot explicitly collapses scopes. But these are **reactive** (triggered by overflow) or **semi-manual** (snapshot requires agent to decide) — not proactively learned |
| **Filter (STM)** | No direct equivalent | Swival has no semantic filtering of context. Compaction drops turns by importance score, not by semantic irrelevance |
| **Three-stage training** | N/A | Swival uses a fixed-weight LLM (no fine-tuning) |
| **GRPO** | N/A | No RL training |
| **Reward function** | Heuristic guardrails | Error repetition triggers automatic nudges. No formal reward signal |

### 4.2 What Swival Does Well Already

**Graduated compaction.** Swival's three-level compaction (compact tool results -> importance-scored dropping -> aggressive last-resort) is more nuanced than AgeMem's binary Summary/Filter. The importance scoring in `drop_middle_turns()` (errors: +3, writes: +5, thinking: +2, snapshots: +5) is a hand-crafted approximation of what AgeMem learns through RL.

**Snapshot system.** The `SnapshotState` is genuinely ahead of what AgeMem describes. It's a proactive context collapse tool with dirty tracking, scope resolution, and history injection. AgeMem's Summary tool is a simpler version of this.

**Continue-here system.** Deterministic session state preservation on interruption, with optional LLM enhancement. AgeMem doesn't address session resumption at all.

**Proactive checkpoints (CompactionState).** Rolling summaries every N turns with hierarchical consolidation. This is similar in spirit to AgeMem's Stage 1 LTM construction — building persistent knowledge as the session progresses.

### 4.3 Where Swival Falls Short Relative to AgeMem

**No autonomous LTM management.** The agent cannot decide to store, update, or delete persistent knowledge on its own. Memory writes are user-initiated (`/learn`). AgeMem's key insight is that the agent itself should decide what's worth remembering — and RL training teaches it to make good decisions.

**No semantic retrieval.** Swival loads the entire MEMORY.md into the system prompt every turn. This works while memory is small, but doesn't scale. AgeMem's embedding-based Retrieve with top-k selection is fundamentally more scalable.

**No proactive context filtering.** Swival's compaction is reactive (triggered by overflow) or agent-initiated (snapshot). AgeMem trains the agent to filter irrelevant content *before* it becomes a problem — a meaningful behavioral difference.

**No unified memory policy.** Swival's memory systems are independent modules with different triggers, formats, and lifecycles. AgeMem unifies them under one tool interface with one optimization objective.

**Fixed heuristics vs. learned behavior.** Swival's importance scores, compaction thresholds, checkpoint intervals, and memory limits are all hand-tuned constants. AgeMem replaces these with a learned policy that adapts to task demands.

## 5. Application to Swival

### Design constraint: small context windows

Swival's goal is to work well even with models that have small context windows (4K-8K tokens). Every token in the system prompt is expensive. Loading all of MEMORY.md (up to 8K chars, roughly 2K tokens) into every request can consume 25-50% of a small model's context on its own.

AgeMem was evaluated with 8,192-token contexts and still found STM management essential. For Swival, context efficiency is the single most important concern.

### A warning about tool-only memory

An important caveat from the paper's own results: AgeMem-noRL (same tool interface, no RL training) does **not** outperform strong memory baselines. On Table 2, AgeMem-noRL averages 33.43 (Qwen2.5-7B) and 45.59 (Qwen3-4B), which is below Mem0 (37.14 / 44.70) and A-Mem (36.78 / 45.74) on both backbones. On some individual benchmarks, AgeMem-noRL even loses to the no-memory baseline.

Adding memory tools alone — without a strong usage policy — can make the agent worse. Swival uses fixed-weight models and cannot do RL fine-tuning. That makes this risk real and concrete, not theoretical. The practical consequence: new memory features should start narrow, stay opt-in until proven, and be measured before expanding.

### 5.1 v1: Make Existing Memory Cheaper and More Targeted

v1 adds no new tools. It keeps `.swival/memory/MEMORY.md` as the source of truth, keeps snapshot unchanged, keeps compaction unchanged. The only change is how memory gets injected into the system prompt.

**What changes:**

1. **Parse MEMORY.md into entries at startup.** Entries are heading-delimited blocks: any ATX heading (`#` through `######` — a line starting with one or more `#` followed by a space) starts a new entry, and everything under it (bullets, prose, code blocks) belongs to that entry until the next heading or EOF. Unheaded content at the top of the file is one entry. This preserves semantic coherence — related bullets stay grouped under their topic — and gives BM25 enough terms per entry to rank meaningfully. If an entry exceeds the retrieval budget, truncate it in the result rather than splitting it further. Each entry gets a short id for telemetry.

2. **Split entries into bootstrap and retrievable.** Some memory is durable bootstrap knowledge that the agent needs on every run regardless of the task. The rest is situational and only needs to appear when relevant.

   **What qualifies as bootstrap:**
   - Provider and model quirks (e.g., "this model doesn't support tool_choice", "max output is 4096")
   - Stable repo conventions (e.g., "tests use pytest, run with `uv run`", "stdout is for final answer only")
   - Tool behavior notes (e.g., "run_command requires whitelisting")
   - User workflow preferences that apply to every session (e.g., "always use bun", "never auto-commit")

   **What does not qualify (goes to retrieval-only):**
   - Prior debugging findings for specific bugs
   - Past architectural decisions about specific features
   - Project-specific patterns that only matter when working in that area
   - Anything that references specific files, functions, or branches

   The rule of thumb: if the entry would be useful even when the user's prompt is "fix the typo in README.md", it's bootstrap. If it depends on what the user is actually working on, it's retrieval.

   **Selection mechanism:** Bootstrap is conservative by default. Stale task-local notes accidentally promoted into always-on context is worse than missing a useful entry — the retrieval pass catches it anyway. The only bootstrap mechanism in v1 is an explicit `<!-- bootstrap -->` comment on the line above a heading in MEMORY.md. This is unambiguous, opt-in, and zero-cost if unused. No heading-based heuristics — a heading allowlist (e.g., `## Provider`, `## Tool`) would assume a convention that doesn't exist today and silently misclassify entries when users organize differently. If telemetry later shows most users don't tag anything and would benefit from defaults, a heading heuristic can be added in a follow-up with real usage data. Untagged entries go to retrieval regardless of heading or length.

3. **Replace bulk `load_memory()` injection with budgeted two-part injection.** First, inject the bootstrap block (strict token budget, say 200-400 tokens). Then, run one retrieval pass over the remaining entries keyed from the first user message. Inject the top results into a second block, capped to its own token budget (200-400 tokens). v1 does not use continue-here context as a retrieval signal — `load_memory()` runs inside `build_system_prompt()` which has no visibility into whether a continue file was loaded, and adding that plumbing for speculative benefit is not justified before telemetry shows the first-message key is insufficient. If it is, wiring continue-here context into retrieval becomes a concrete v2 task with a measured motivation.

   Total memory cost in the system prompt: 400-800 tokens, down from potentially 2000+.

4. **Use BM25 or simple lexical ranking for retrieval.** No embeddings. BM25 via `rank_bm25` (pure Python, minimal dependency) or even simpler keyword overlap. No new ML dependencies in the default install. Embeddings can be an optional backend later for users who configure an embedding endpoint.

5. **Add telemetry.** Log: how many entries exist, how many are bootstrap vs. retrievable, how many tokens the bootstrap block uses, how many tokens the retrieval block uses, which entries were retrieved (by id), total memory token cost per session. Telemetry goes to `--report` JSON (structured, machine-readable, already exists as Swival's evaluation surface) and optionally to stderr when `--verbose` is on. No new `.swival/` artifacts — that would add a file lifecycle to manage for marginal benefit. This data is needed before any further memory work.

**What stays the same:**

- MEMORY.md is still a plain markdown file the user can read and edit
- `/learn` still appends to it
- Snapshot is unchanged
- Compaction is unchanged
- No new tool schemas are added to the tool list

**Success criteria:**

A win for v1 means all three of these hold:

1. **Prompt-token reduction.** For sessions where MEMORY.md exceeds ~1000 tokens, the new injection path uses measurably fewer tokens (target: 30-50% reduction in memory token cost). Measured via the new telemetry, comparing bootstrap+retrieval budget against what `load_memory()` would have injected.

2. **No regression in task completion.** Existing benchmarks and reviewer-mode runs produce the same pass rates (within noise) as before. The risk is that retrieval misses an entry the agent needed. If regressions appear, the fallback flag (inject everything) should recover them, confirming the regression is retrieval-related rather than a deeper bug.

3. **Fallback rate.** How often does adding `--memory-full` change the outcome of a reviewer-mode run? This is the direct measure of whether retrieval is missing critical entries. Evaluation protocol: run the same prompts with the same model and config under three modes — baseline (no memory), budgeted (v1 default), and `--memory-full` (inject everything). Record outcome deltas (pass/fail, token counts, compaction events) in `--report` JSON for each run. Compare budgeted vs. `--memory-full` outcomes. If `--memory-full` rarely changes the result, retrieval is sufficient. If it frequently does, retrieval is missing critical entries and the ranking or entry model needs work before v2.

Secondary signals worth tracking but not gating on:
- **Compaction frequency delta:** did sessions start compacting later (or not at all) because the prompt was smaller?
- **Retrieval-vs-full overlap:** which entries startup retrieval selected vs. which entries were in the full injection. Over time this shows whether retrieval is converging on the useful subset or consistently missing important content.
- Whether users manually adjust bootstrap tags after seeing the defaults

**Migration:**

v1 does not introduce a new storage format. MEMORY.md stays the single source of truth, read fresh on each session.

The startup path is:
1. Read `.swival/memory/MEMORY.md` (same file, same location)
2. Parse into entries using the boundary rules above
3. Classify each entry as bootstrap (has `<!-- bootstrap -->` tag) or retrievable (everything else)
4. Inject bootstrap block (capped to token budget)
5. Run one BM25 retrieval pass, inject results (capped to token budget)

There is no migration step. Existing files work unchanged. Users who want finer control can add `<!-- bootstrap -->` tags; users who don't simply get all entries routed to retrieval.

The old behavior (inject everything) stays available via a config flag or CLI option (e.g., `--memory-full`). This is the escape hatch if retrieval causes regressions, and it's how A/B comparison works during evaluation.

### 5.2 v1a: Add Read-Only Memory Search

v1 and v1a answer different questions. v1 asks: can we reduce startup memory cost without losing useful context? v1a asks: can on-demand read-only search improve mid-session recall enough to justify its schema cost?

Preliminary evaluation shows that context overflow is already rare, even on small models. That weakens the case for STM tooling (`compact_context`) and means `memory_search` is not about overflow management. It is about precision and mid-session recall: the agent may need a specific memory that startup retrieval did not include, and searching for it on demand is cheaper and more targeted than injecting more at startup.

A read-only search tool is the lowest-risk way to address that gap. It can't corrupt the store, can't create stale entries, and the worst case is wasted tokens on an irrelevant retrieval.

**What changes:**

1. **Add one tool: `memory_search`.** Opt-in via config or flag.

```python
{
    "name": "memory_search",
    "description": "Search persistent memory for relevant facts, prior discoveries, or stored knowledge.",
    "parameters": {
        "type": "object",
        "properties": {
            "query": {"type": "string", "description": "What to search for"},
            "top_k": {"type": "integer", "description": "Max results (default 3)"}
        },
        "required": ["query"]
    }
}
```

   Schema cost: ~100 tokens. The tool reuses the same entry parser and BM25 ranking from v1's startup retrieval path. Returned entries include short IDs for traceability.

2. **Add telemetry for search usage.** Log per call: query text, entries returned (by id), token cost of the result. Log per session: total search calls, total search token cost. Telemetry goes to `--report` JSON and verbose stderr, same as v1.

**What stays the same:**

- Everything from v1 is unchanged
- No write access to memory
- No new storage format
- Snapshot and compaction are untouched

**Success criteria:**

Measured over a trial period with the tool enabled:

1. **Usage frequency.** The agent calls `memory_search` at least occasionally (more than noise). If it never calls it, either the startup retrieval is sufficient or the system-prompt guidance is wrong. Both are useful findings.

2. **Fallback rate delta.** Compare v1a (budgeted startup + search tool) against `--memory-full` using the same evaluation protocol as v1: same prompts, same model/config, outcomes recorded in `--report`. If the search tool closes the gap between budgeted and full injection (fewer cases where `--memory-full` changes the outcome), search is adding value. If the gap is unchanged, search isn't helping and the stop condition applies.

3. **Prompt cost is bounded.** Average token cost per `memory_search` call stays under ~200 tokens (the result payload, not the schema). If results are routinely large, the top_k default or entry truncation needs tightening.

4. **No regression.** Task completion rates with the tool enabled are at least as good as without it. If the tool is hurting outcomes (agent distracted by irrelevant retrievals, wasting turns on search instead of working), disable it and investigate.

**Stop condition:** If `memory_search` gets low usage or poor precision after a reasonable trial, stop here. The startup retrieval from v1 may be sufficient. Do not proceed to write tools on the assumption that more memory tooling is always better — the AgeMem-noRL results say otherwise.

### 5.3 Future Work

These are possible directions, not commitments. Each depends on evidence from v1 and v1a.

**Memory write tool.** If `memory_search` proves useful and gets consistent high-precision usage, there may be a case for letting the agent store, update, and delete entries autonomously. This is the highest-risk addition — the AgeMem-noRL results show that without a learned policy, writes can pollute the store. It should be opt-in and gated on evidence from the read path. If added, it would be a separate `memory_write` tool (not merged with search — different required fields, different failure modes, clearer contract for small models).

**Context management tool.** If future evaluation shows overflow becoming a problem (e.g., as tasks get longer or models get smaller), a `compact_context` tool could give the agent voluntary access to context reduction. This would be separate from snapshot (scoped save/restore with dirty checks) and separate from the reactive compaction pipeline (overflow-driven escalation). Currently there is no evidence this is needed.

**Structured store.** If MEMORY.md's flat format becomes limiting (too many entries, need for scoping or metadata filtering), consider migrating to a JSONL-backed store. JSONL, not SQLite — it matches Swival's inspectability. Migration from MEMORY.md should be automatic and the old format should remain readable.

**RL or distillation.** The paper's strongest results come from RL training. If Swival ever supports fine-tuned models, the three-stage training strategy and step-wise GRPO are the right starting points. Far out and depends on having tool interface, telemetry, and evaluation infrastructure in place first.

## 6. Summary

AgeMem's core insight — that memory management should be part of the agent's own decision-making, not a separate system with fixed triggers — is sound. Its secondary insight — that RL training is needed to get the full benefit, because tools alone underperform — is an important warning.

For Swival, the plan is:

1. **v1: Make existing memory cheaper.** Replace bulk MEMORY.md injection with a small bootstrap block plus one budgeted retrieval pass. No new tools. Measure token cost and retrieval precision.
2. **v1a: Add read-only search.** One opt-in `memory_search` tool for mid-session recall. Measure usage, precision, and prompt cost. Stop here if it doesn't prove useful.
3. **Preserve existing invariants.** Snapshot stays a scoped save/restore system. Compaction stays a reactive overflow handler. MEMORY.md stays a human-readable file. New features layer on top; they don't replace the safety net.

Everything beyond v1a depends on evidence. The guiding question is always: does this improve reasoning per token? If it doesn't measurably reduce re-reading and re-reasoning, it's a regression.
