twin memory

Values & history

How memory shows a value that changed - every value as stated, dated, newest first - and how to read one subject's whole record.

People change their minds, move cities and switch jobs. Memory keeps every value that was said, with the day it was said, and shows them newest first. It does not decide for you which value replaced which.

Values as stated

When records give a subject's attribute a value, such as Alice's home_city, memory lists the values on one line in known:

Values as stated, newest said first:
- Alice Chen · home_city: Lisbon [said 2026-10-01]; Berlin [said 2024-06-01]
- Alice Chen · employer: Acme [said 2026-10-01]
  • Newest first. The value said most recently comes first, with its date.
  • Repeats collapse. The same value told again, in other words, is one entry.
  • Conflicts are named. Where one value was said both to hold and not to hold, the line says so.

Why memory does not say "replaced"

Two values under one name are often not a change. They can be two different things: the port a service uses locally and the one it uses in production, or a salary offer weighed against the current one. A line that said "Lisbon (before: Berlin)" would claim more than memory knows. So it states what was said and when, and leaves the judgment to the model reading it, which has the dates and the evidence beside them.

In practice, the newest value is usually what is true now, and a model told the dates will say so. When a question depends on which is current, give the model the dates and let it answer with them.

One subject's history

/v1/memory/history returns every value recorded for one subject, optionally narrowed to one attribute.

For { "subject": "Alice Chen" }:

{
  "subject": "Alice Chen",
  "count": 3,
  "assertions": [
    {
      "subject": "alice chen",
      "attribute": "employer",
      "value": "Acme",
      "valid_from": "2026-10-01",
      "polarity": 1,
      "source_turn_ids": ["ev_620270db0bff9328"]
    },
    {
      "subject": "alice chen",
      "attribute": "home_city",
      "value": "Berlin",
      "valid_from": "2024-03-01",
      "polarity": 1,
      "source_turn_ids": ["ev_c2cef398cd2bc8ac"]
    },
    {
      "subject": "alice chen",
      "attribute": "home_city",
      "value": "Lisbon",
      "valid_from": "2026-10-01",
      "polarity": 1,
      "source_turn_ids": ["ev_620270db0bff9328"]
    }
  ]
}
  • Assertions are sorted by attribute, then by valid_from, oldest first. This is the opposite order to known. Take the last entry of an attribute for the newest.
  • valid_from is the day the value held from.
  • polarity is 1 when the value was said to hold, and -1 when it was said not to be true, never to have been, or to have stopped being true.
  • source_turn_ids are the event ids it was read from. Pass one to lineage to find the passage.

History needs records, so it answers only once the end user's conversations have been read.

Naming the subject

The subject is matched by its recorded name, such as Alice Chen, case and spacing ignored. A name memory has not recorded is a miss, which lists the nearest recorded subjects:

{ "subject": "Alice", "error": "nothing recorded", "subjects": ["alice-chen"], "recorded": 1 }

Call again with one of subjects. recorded is how many subjects the end user's memory holds.

On this page