Eposyne Director

Memory

Memory gives your characters a past. It keeps what each character saw, was told, and believes, so a character can remember the player, repeat a rumour, or doubt a lie. You feed it with events and read it back with one endpoint. This page covers what characters believe, who perceives what, the runtime read, rules versus model weighing, and what carries across timelines.

Switch Memory on first

Memory is off by default for every account, on every plan. Switch it on under Modules at https://architect.eposyne.com/profile?section=director-keys. A switch reaches your API keys within a minute and your sign-in tokens within an hour. Until then the Memory endpoint answers 403: {"detail": "module 'memory' is not enabled for this tenant"}.

Two parts

Events are the only input. Your game reports what happened, and Director decides what each character believes. You cannot write a memory yourself. Set memory.world and memory.npc in the policy to use one part or both.

What a character believes

A memory records what it says (content), who it is about, and where it came from:

Memory words a memory from the event's key, the names in it, and its payload. A key such as combat.enemy-defeated with a named actor reads as a sentence. Choose readable keys and names.

Perception and witnesses

Memory forms a memory for each character who perceived an event, and only for characters. A player never forms memories, and neither does any player an event lists in players. An event for several players is perceived once.

The details of the event format, the standard events, and the witnesses field are on Events.

Retellings and rumours

News travels in two ways. Retellings your game reports with told are always processed. With memory.spreading.enabled on, Director also spreads memories on its own when characters meet. A meeting is recognized from character movement, from the characters-met event, or from a shared group on a game-time interval. The policy lists the settings.

Memory in a decision

Memory takes part in a decision that names a stream position (world, timeline, and after_seq on POST /v2/decide, see Events). The event at that position names the player and the character who decides. For an event with several players, the decision names one of them with the query parameter player_id, see Whose verdicts.

None of this appears in the response. It shapes the reply. Read the character afterwards with the endpoint below.

The runtime read

Request
curl "https://director.eposyne.com/v2/memory/runtime/npcs/npc-mara?world_instance_id=save-1&timeline_id=main" \
  -H "Authorization: Bearer $EPOSYNE_API_KEY"

GET /v2/memory/runtime/npcs/{npc_id} returns one character's beliefs, relations, and recent recollections on one timeline. The character id is the id you use in event references.

200 (example, values vary)
{
  "world_instance_id": "save-1",
  "timeline_id": "main",
  "npc_id": "npc-mara",
  "acknowledged_seq": 3,
  "processed_seq": 3,
  "location": "loc-tavern",
  "beliefs": [
    {
      "belief_id": "6f1c2a9e4b7d4c0e9a53d1f08b2e7c44",
      "kind": "knowledge",
      "content": "I will find your son. Where was he last seen?",
      "about": ["player-1", "npc-mara"],
      "source": "player",
      "source_entity": "player-1",
      "hops": 1,
      "confidence": 0.7,
      "importance": 0.5,
      "feeling": 0.2,
      "arousal": 0.3,
      "diverging": false,
      "uncertain": true,
      "seq": 2,
      "game_time": "day 1, 19:41",
      "persistent": false
    }
  ],
  "relations": [
    {"entity_id": "player-1", "feeling": -0.05, "memories": 2, "last_seq": 3},
    {"entity_id": "loc-tavern", "feeling": -0.3, "memories": 1, "last_seq": 3},
    {"entity_id": "npc-drunk-sailor", "feeling": -0.3, "memories": 1, "last_seq": 3}
  ],
  "recollections": [
    {
      "belief_id": "0a9d3c5e71f24b86b2c4e8d6f1a35b97",
      "kind": "event",
      "content": "Ilse enemy defeated at The Crooked Lantern (enemy: npc-drunk-sailor)",
      "about": ["player-1", "loc-tavern", "npc-drunk-sailor"],
      "source": "seen",
      "source_entity": null,
      "hops": 0,
      "confidence": 0.9,
      "importance": 0.6,
      "feeling": -0.3,
      "arousal": 0.7,
      "diverging": false,
      "uncertain": false,
      "seq": 3,
      "game_time": "day 1, 21:05",
      "persistent": false
    }
  ]
}
MemberMeaning
acknowledged_seq, processed_seqThe positions of the timeline. What you see is what Memory has been given, up to processed_seq. It is behind acknowledged_seq while events are deferred.
locationWhere the character was last reported, or null if never.
beliefsWhat the character holds to be so: memories of kind knowledge or impression. Most important first, at most 50.
recollectionsWhat the character perceived: memories of kind event. Newest first, at most 20.
relationsEvery other entity a memory of the character is about or came from, with the mean feeling of those memories, how many memories there are, and the last_seq. They are read off the character's memories, so a place or an item can appear as well as a character. Most memories first, at most 50.

Rules or model weighing

Weighing decides how much an event matters to a character. The setting is memory.weighing in the policy.

"rules" (default)"model"
How it is weighedComputed from the kind of event (a theft, a fight, a gift, a conversation), the character's part in it (target, actor, witness), and how they learned of it.A model judges how good or bad the event is for that character and how activating it is. The rest of the scoring stays rules.
Retelling a memoryKeeps the statement and drops detail, such as quoted words.A model retells it as the listener will remember it. A detail may shift, blur, or grow, as rumours do.
Replies with an unnamed inventionThe check finds invented names.A model also catches an unnamed new relation, such as a brother nobody mentioned.
Model calls when events arriveNoneOne for every memory formed and every memory retold
Model calls in a decisionThe referee, when it appliesThe referee, and one invention check on every reply
CostThe referee onlyCredits for every call above

If a model cannot answer, for instance because your credits do not cover the call, Memory falls back to its rules for that memory. The event is still processed. The events response reports it in refused_judgements.

Model weighing makes memories feel more alive and costs more. Start with rules. The counts per event, and a worked example, are on Policy.

What Memory costs

Memory across timelines

A memory belongs to the timeline it formed on. A child timeline sees its parent's memories up to the branch point, so loading an earlier save removes what the player did afterwards. The memories of the abandoned future stay stored on the old timeline and never show up on the new one.

Some characters should remember the player whatever the player loads. Mark them persistent in the policy:

policy.json (part)
{
  "memory": {
    "persistent": {"characters": ["npc-seer"], "kinds": ["knowledge"]}
  }
}