Hacktoberfest 2026: los issues que los mantenedores marcaron para octubre, abiertos y aptos para principiantes. Explorar issues de Hacktoberfest

[Bug]: Local desktop agent memory is never compacted — MEMORY.md grows past the 20KB hard limit while only the last 10KB is injected

Abierto
#551 0 comentarios 0 reacciones 0 asignados Ver en GitHub

Los mantenedores suelen responder en 1 día

Nadie ha tomado este issue todavía.

Evaluación

Dificultad
4/5
Tiempo estimado
3-5 días
Aptitud para principiantes
42/100
Tipo de issue
Error
Claridad
Bastante claro
Estado de actividad
Activo
Stack tecnológico
typescript

Línea de trabajo

Start with packages/shared/src/memory-limits.ts, then trace triggerCleanup through packages/local-runtime/src/memory/local-memory-orchestration.ts, local-memory-facade.ts, and local-memory-store-fs.ts to understand the local cleanup path. Read the prompt block assembler that implements collectMemoryBlocks() and inspect its budget handling for the topic index. Done means local memory is compacted according to the documented limits and topic discovery is not silently lost when the shared injection budget is full.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

Product / Version / Platform

  • Product: Desktop app
  • Version: 3.1.6 (build 3.1.6.195)
  • Platform: macOS
  • OS version and architecture: macOS 15.7.7 arm64

Steps to reproduce

  1. Install the desktop app (3.1.6) on macOS and leave memory enabled (default config has memory.proactive: true).
  2. Use the agent over several days so it accumulates durable preferences and lessons. Every write appends to the agent-scoped file ~/.minimax/agents/<agent>/memory/MEMORY.md.
  3. Watch that file grow. In my case: 29 entries / 76 KB on day 3 → 173 entries / 403 KB on day 19. The entry count increased monotonically (29 → 37 → 44 → 47 → 52 → 61 → 69 → 74 → 83 → 105 → 114 → 118 → 123 → 129 → 160 → 173) and not a single entry was ever removed or compacted.
  4. Start a new session and read the injected memory block. It contains only the last 10,240 characters of MEMORY.md — about 11 of the 173 entries.

Expected and actual behavior

Expected: MEMORY.md is compacted when it crosses the documented thresholds, and the compressed index is written to .summary.md, so old entries stay reachable and the file stays within budget.

Actual: nothing is ever compacted. The only local reaction to a memory write is a snapshot; the file keeps growing without bound, and because injection is a 10,240-char tail, ~94% of accumulated memory (162 of 173 entries) is never injected by default — the agent has to know to Read/search the file to reach anything older.

Note on units: MEMORY_TAIL_INJECTION_CAP_CHARS = 10 * 1024 is characters, not bytes. The Chinese-heavy 403 KB file is ~200 K characters, so the injected slice is ~5% of it by characters and ~2.5% by bytes.

Root cause (as far as I can tell from the source)

I checked both the shipped desktop bundle and the open-source repo (MiniMax-AI/minimax-code); the constants match.

  1. packages/shared/src/memory-limits.ts documents the intended behavior:

    export const MEMORY_SOFT_LIMIT_BYTES = 15 * 1024;        // 15KB
    export const MEMORY_HARD_LIMIT_BYTES = 20 * 1024;        // 20KB
    /** Threshold above which memory.append triggers an immediate cleanup spawn. */
    export const MEMORY_CLEANUP_TRIGGER_BYTES = 18 * 1024;   // 18KB
    /** Minimum MEMORY.md size (bytes) required before the daily-cron cleanup runs. */
    export const MEMORY_CLEANUP_MIN_BYTES = 10 * 1024;       // 10KB
    export const MEMORY_SUMMARY_INJECTION_CAP_CHARS = 4 * 1024;
    export const MEMORY_TAIL_INJECTION_CAP_CHARS   = 10 * 1024;
    export const MEMORY_CONTEXT_CAP_CHARS          = 16 * 1024;
    

    MEMORY_CLEANUP_TRIGGER_BYTES and MEMORY_CLEANUP_MIN_BYTES are re-exported from packages/shared/src/index.ts, but a repo-wide search finds no consumer for either symbol — the only hits are the definition and the re-export. So the "18KB → immediate cleanup spawn" and "≥10KB → daily cron cleanup" paths are not wired up locally.

  2. The only local reaction to a write is the snapshot path:
    packages/local-runtime/src/memory/local-memory-orchestration.ts → memoryFacade.triggerCleanup(agentName, false) → packages/local-runtime/src/memory/local-memory-facade.ts → FsLocalMemoryStore.triggerCleanup(). That store compares against a different threshold, CLEANUP_THRESHOLD_BYTES = 64 * 1024 in packages/local-runtime/src/memory/local-memory-store-fs.ts, and above it only calls snapshotForCleanup(), which writes archive/<date>/MEMORY.md. It never rewrites MEMORY.md.

  3. The compaction step itself does not exist in the local runtime. memory_summary_write (the .summary.md index writer) has no hit in the repository, and the memory reference bundled with the desktop app describes it as "Called by cleanup curator session Step 9" — a curator session that the local runtime never spawns. The string curator has no hit in the repo either.

  4. The daily cleanup is a daemon-managed job. packages/shared/src/cron-purpose.ts says:

    /** Cron task name used for the daemon-managed memory cleanup automation. */
    export const MEMORY_CLEANUP_CRON_NAME = 'memory-cleanup';
    

    and packages/agent-modules/cron/src/executor.ts explicitly skips those sessions (if (parsed.cronName === MEMORY_CLEANUP_CRON_NAME) continue;). So the 05:00 memory-cleanup spawn does not run for a local desktop agent either.

A second, independent defect: the topic index is silently starved

This one only becomes visible after the file is split up, and it is easy to miss because nothing is logged.

collectMemoryBlocks() (in packages/local-runtime/src/.../local-agent-config-builder / the prompt-block assembler) builds one shared budget and consumes it in this fixed order:

user profile / user memory   (~8.4 K chars)
agent MEMORY.md tail         (up to 10,240 chars)
<available_memory_topics>    (topic index: name + description + path for every topic)
daily digest                 (whatever is left)

The topic index is consumed last, and budget.include(block) returns false when the block does not fit — the block is then dropped with no warning to the model and no log line. In my run: 8,447 + 5,598 = 14,049 used, 2,335 left, the topic index needed 2,873 → the model was told nothing about the topic files at all, while MEMORY.md itself said "project-level details live in memory/topics/*.md (read them when the description matches)". The pointer had no target.

A user cannot fix this from the file side — the only levers are "make MEMORY.md smaller" or "make user.md smaller", and neither is indicated anywhere. A dropped block should at least be logged, and the topic index should probably not be the one that gets dropped.

Impact

  1. Memory silently becomes unreachable. With a 10,240-char tail window, a 173-entry file means only the newest ~11 entries are visible per turn. Everything older needs an explicit Read/search — and because there is no .summary.md index, there is no cheap way to know what is even in there.
  2. Unbounded disk growth. archive/<date>/MEMORY.md snapshots accumulate with no TTL — the 60-day TTL in the code applies to daily/ only. Mine reached 17 snapshots / 3.5 MB in under three weeks, and there is no restore path (only readArchive), so the snapshots are history, not a real backup.
  3. The documented limits do not apply locally. Soft 15KB / hard 20KB / trigger 18KB are all exceeded by 19× in my case with no intervention.
  4. Topic memory cannot be discovered (second defect above) — the feature's discovery channel is the first thing dropped when the budget is tight.
  5. Related: the bundled memory reference says every entry needs a Type: line because "The cleanup curator relies on it", but nothing validates or warns when it is missing (0 of 173 entries in my file had one), so any future curation would have no way to classify the entries.

Questions

  1. Is compaction expected to run for local desktop agents at all? If yes, which component is supposed to spawn the curator session in the local runtime?
  2. Should memory.append honor MEMORY_CLEANUP_TRIGGER_BYTES (18KB) and trigger compaction locally, instead of only snapshotting?
  3. Should the memory-cleanup cron be registered by the desktop app, or is local compaction expected to happen only on append?
  4. For the shared injection budget: should the topic index be dropped silently when it does not fit? At minimum a log line would help — right now there is no way to tell "no topics configured" from "topics dropped for budget".

Redacted error summary

N/A — this is a behavioral gap rather than a crash. The relevant observed state, with private paths removed:

~/.minimax/agents/<agent>/memory/
├── MEMORY.md          # 403611 bytes, 173 entries, monotonically growing
├── archive/
│   ├── 2026-10-08/MEMORY.md   # 76K  (29 entries)
│   ├── 2026-10-15/MEMORY.md   # 160K (61 entries)
│   └── ...                    # 17 snapshots total, ~3.5MB, no TTL
└── (no .summary.md)

# injected per turn: last 10240 chars only, plus
# "Memory exceeded the injection budget — older entries are not shown above."

Before submitting

  • I have searched existing issues.
  • I have included my version and removed sensitive information.
Lenguaje dominante
TypeScript
Estrellas
2.1k
Forks
271
Merge medio
9 h 55 min
PR fusionados (30 d)
52

Preparar el entorno

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de MiniMax-AI/minimax-code

Todos los issues de MiniMax-AI/minimax-code

Issues similares

Más issues de TypeScript

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.