Memory

Keep what an agent learns beyond its context window, its turn, and its session, without leaking data about one subject into another.

An agent works within a model's context window, and the window is bounded. Over a long session its conversation fills: older messages are summarized and earlier tool results are cleared. Some of what it learns must outlast that, and some must outlast the session itself. And what an agent learns about one subject, such as one account, must not reach the sessions about another unless you mean it to.

Twisp gives agents two mechanisms for this, both recorded and both bounded by the session they belong to:

ProblemMechanism
A detail from an earlier turn of this session fell out of the context.Session history
A fact must outlive the turn, and inform this session's later turns.Agent memory, SESSION scope
A fact learned in one session should inform the agent's other sessions.Agent memory, AGENT scope

The Memory and History reference lists every field and rule. Both features are configured in the agent's config.harness; see Agent configuration.

What stays in context

Before turning to memory, it helps to know what the agent keeps on its own. Within a turn, a tool result larger than the offload threshold is set aside, leaving a preview and a reference the agent retrieves it with. As the conversation fills, older messages are summarized, keeping the latest few word for word. In a session, each new turn continues the conversation, and earlier turns' large tool results are replaced by a note naming the reference that returns them. The session's state, which every turn reports, carries forward whole. See harness.context in Agent configuration.

Design the state to hold what the next turn must know, such as how far the agent has reviewed and which findings are open. Use history and memory for everything else.

Session history

A summary keeps the gist, not every amount and ID. With harness.history, what earlier turns of the session said stays searchable, so the agent can look up a detail instead of guessing or asking again. See Session history.

{ "harness": { "history": { "index": "messages_and_tools" } } }
indexWhat earlier turns keep searchable
none (default)Nothing.
messagesEach turn's message, as the agent received it, and the agent's replies.
messages_and_toolsAlso the results of the agent's tools, and their errors.

With an index, the agent has search_history. It ranks the kept events of the session's earlier turns by meaning, keywords, and recency, and the agent is told to search before guessing at something an earlier turn established. Only what a turn commits is kept: a failed attempt stays in its transcript but is never searchable.

History never crosses sessions: an agent searches only its own session's turns, and an agent without sessions has none. Choose messages when the turn messages and replies hold what later turns need. Choose messages_and_tools when the agent needs to find earlier tool results, such as an entry it looked up three weeks ago.

Agent memory

With harness.memory.enabled, an agent keeps durable facts it learns as memory records. A record belongs to one agent, and an agent never sees another agent's memory. See Agent memory.

{
  "harness": {
    "memory": {
      "enabled": true,
      "scope": { "read": ["session"], "write": ["session"] },
      "tools": ["add_memory", "read_memory", "delete_memory"],
      "pinned": { "max_tokens": 2000 }
    }
  }
}

Scopes

A record's scope decides which sessions recall it:

  • SESSION: only the session that wrote it. What the agent learns about one account stays with that account's session.
  • AGENT: every session of the agent that reads agent scope, so what it learns in one session informs the next.

harness.memory.scope sets which scopes the agent reads and writes. Both default to ["session"], which keeps every session's data to itself. Allow agent writes only when facts from one session's data may inform every other session, such as guidance an operator gave that applies to all accounts. When write includes both, the agent chooses the scope of each record. An agent without a session has no session scope, so it sets both to ["agent"].

How memory is written

Extraction. When a turn ends, the agent reviews the conversation for what is worth remembering. It compares each candidate with the most similar records it already has, and adds it, replaces a record it corrects, deletes a record it shows wrong, or skips it, so restated facts do not pile up. harness.memory.extraction.prompt replaces the default instructions for what to keep, and every sets how often the review runs: every turn, or once enough messages were added. Each review is a model call with purpose memory that counts against the turn's limits; harness.memory.model can name a cheaper model for it.

Memory tools. With harness.memory.tools, the agent can also save a fact as it learns it with add_memory, read one record with read_memory, and delete one with delete_memory. add_memory can name a record it replaces, which becomes SUPERSEDED.

Memory is written in the turn's transaction, so a turn that rolls back leaves no record. Only the agent itself writes memory: a subagent helper or a program run by programmatic_tool_caller can search memory but never write it.

How memory is used

Recall. Before each model call, the agent recalls the records that best match its current work. Recalled memory reaches the model marked as memory, and is data, never instructions.

Search. The agent can search its memory with search_memory, by query or by filters on kind, labels, or IDs. Search combines meaning, keywords, and recency. harness.memory.search tunes it: mode (hybrid, lexical, or vector), max_results per recall, and min_score for matches by meaning alone.

Pins. With harness.memory.pinned, the agent may pin a record, and every turn's instructions list the summary and ID of each pinned record it reads. Pins are for the few facts every turn must see, such as an operator's standing ruling. max_tokens is their budget: a pin that would exceed it is refused, and the agent is told to consolidate several pins into one.

Every recall and search whose records reached the model is recorded as a RETRIEVED output use, so you can see which memories informed a decision.

Kinds and labels

Each record has a one-line summary the agent can act on, and optional content with the evidence. Its kind is one of the kinds the agent declares in harness.memory.kinds, by default guidance, fact, event, and reference. Labels are exact values that searches filter on, such as a customer ID. Declare each label with a fixed number and a description the agent reads:

"labels": { "customer_id": { "number": 5, "description": "The customer the memory is about." } }

Once a version declares a label, later versions keep it with the same number.

Memory in preview mode

An agent in preview mode writes memory marked preview. Later preview turns read it, but a live turn never does, so once the agent goes live it does not act on what it learned of effects that never happened. A preview turn never changes a record a live turn wrote: it writes a preview record that names the record it would replace or delete, so Action.memories shows exactly what the preview would have changed. Preview history is likewise searched only by preview turns.

Reviewing and deleting memory

Action.memories lists an agent's records, newest first, and agentMemory reads one with its history. Each record names the execution, agent version, and session that wrote it. deleteAgentMemory removes a record from recall; the record and its versions stay readable. To list and read records, grant SELECT on financial.AgentMemory.indexes.* and financial.AgentMemory.document; to delete them, also grant UPDATE. The agent itself needs none of these: its memory is its own record, so neither its policies nor those of whoever starts or calls it need to grant them for it to use its memory.

Choosing settings

IfThen
The next turn needs a fact to do its workPut it in the session's state, or compute it with computed state.
A long session loses details to summariesEnable harness.history; use messages_and_tools if the details are in tool results.
Each session is about one subject whose data must stay with itEnable memory with the default scopes, session only.
What one session learns should inform all of themAdd agent to scope.read and scope.write, and tell the agent in extraction.prompt which facts belong in agent scope.
The agent should record facts as it learns them, not only after a turnAdd add_memory to harness.memory.tools.
A few facts must be in front of every turnSet pinned.max_tokens, small enough to keep the list short.
Records are about identifiable things you search byDeclare labels for those IDs.
Extraction costs too muchSet extraction.every to {"messages": N}, or name a cheaper harness.memory.model.
An agent runs without a sessionSet both scopes to ["agent"]. Every run then shares one memory, so declare labels for the subjects records are about, and let searches filter on them.

Next

Agent memory tutorial

Give an agent memory, and watch what it keeps and recalls.

Sessions

The durable identity that scopes history and session memory.

Memory and History reference

Every field, operation, and rule.

Previous
Sessions