English | 简体中文
This document describes the goals, direction, and boundaries of the tinyagent Memory module.
Memory solves two separate problems without deleting original conversations: controlling the amount of context sent to a provider, and maintaining readable, revisioned long-term memory across Sessions. The two paths share sources of truth, but their failure behavior and configuration switches remain independent.
The module aims to:
- always retain complete original messages in SQLite;
- create recoverable, persistent summaries as context approaches the model window limit;
- keep long-term memory as user-readable Markdown in the Workspace;
- pass every automatic change through candidacy, validation, revision, and atomic commit stages;
- make manual changes, failed jobs, and hash drift observable and recoverable.
An independent ContextCompressor processes history once provider context reaches 50% of the configured window. During the first compaction, it protects the first three messages, the current unfinished Run, up to eight recent messages, and complete tool-call boundaries. It then produces a fixed-structure summary of the middle region.
Before semantic summarization, old tool payloads are reduced deterministically: long tool results become short text containing the tool name, important arguments, and a result overview, while long tool arguments are truncated as valid JSON structures. Compaction does not target an arbitrary percentage; it only requires the context to fit while preserving its protected boundaries.
After a successful summary, the original messages are marked as compacted and an internal role=summary message is inserted at their original position. The source text is not deleted. A failed, empty, truncated, or malformed summary does not change any message. If protected content alone still cannot fit, the operation returns the stable context_window_exceeded error.
Long tool chains that are still running are not summarized semantically. When necessary, only older tool payloads are reduced deterministically so the current call boundary is not changed.
Long-term memory lives at .tinyagent/memory/MEMORY.md. A line containing only § separates single-line logical entries; an empty file represents no long-term memory.
The model submits add, replace, remove, or batched operations candidates through the built-in memory tool. The tool does not write the file directly. Only candidates from successful Runs enter the append-only memory_events stream. The Curator returns a strict JSON array of entries and commits it only after size, duplication, credential, and prompt-injection checks pass.
Commit order is: prepared revision, atomic file replacement, committed revision. If the process stops during a write, startup recovery can therefore determine the state of both the file and database.
The Curator can run when a Session is created or closed, when pending events reach the threshold, during explicit synchronization, or on the next startup. A failed curation job does not advance the event cursor and must not prevent ordinary conversation.
Long-term memory is frozen on a Session's first request. Memory committed later in the same Runtime does not change the system prompt already used by that Session. A new Session, explicit resume, or new Runtime reads the latest revision. This keeps prompt context deterministic within a Session.
Hash drift caused by a manual edit disables automatic curation. After the user runs memory sync and the file passes canonical-format validation, the system records a manual revision before restoring automatic curation. Historical revisions can be inspected and restored by creating a new revision from an old snapshot rather than rewriting database history.
Memory does not delete original Session messages, include Curator or Compressor token usage in the user's RunResult.usage, or let model tools bypass validation to modify the long-term memory file directly.