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.
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
- The world part is the record of what really happened. Every event you send is recorded as true, because your game owns the truth. Plots and the referee read this record. No endpoint returns it, and it never reaches the model that writes a character's reply.
- The NPC part is what each character perceived, believes, and feels. It can be wrong. A character may have been told a lie, or may have heard a rumour that grew on the way.
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:
source:seen(the character perceived it),told(someone told the character),rumour(it reached the character through other characters), orplayer(the player said it). Treat the list as open and ignore values you do not know.source_entityandhops: who told the character, and how many steps the news has travelled. A memory seen first hand has 0 hops. A retelling adds 1.confidence,importance,feeling,arousal: how sure the character is and how much the memory matters, both from 0 to 1, how good or bad it feels, from -1 to 1, and how activating it is, from 0 to 1.diverging: the belief contradicts the world record, for example the character believes the sailor is alive and the record says the player defeated him.uncertain: the character did not see it themselves, or is not fully sure.
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
targetand theactorof an event perceive it, unless that one is a player. - The characters in
witnessesperceive it as well. When you name witnesses, Director looks no further. - With no
witnesses, the characters Director knows to be at the event'slocationperceive it. Director learns where characters are fromloreweaver.movement.location-enteredandloreweaver.movement.character-entered-location. Setmemory.perception_location_fallbacktofalseto turn this off. - When someone tells a character something, send
loreweaver.conversation.toldwith the teller asactorand the listener astarget. The listener remembers it with the teller as the source.
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.
- Each retelling loses some of the character's confidence and adds a hop.
- A character does not hear news about something they saw themselves or already know.
- At a meeting each of the two characters passes on at most 3 memories, the newest ones. A group exchange passes on at most
group_exchange_limitmemories per group per interval. - The group of a character comes from the
groupfield of the Character in your Plots library, or the field thatspreading.group_fieldnames.
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.
- The character's knowledge. Up to 10 of the character's memories, the most important ones about the player and the place first, go into the prompt. They are labelled as what the character knows, which may be wrong. The character knows nothing beyond them.
- The referee. When the event is the player's line (
loreweaver.conversation.player-said) and it touches a belief that is uncertain or contradicts the world record, a referee judges the line against the record and the belief. It gives the decision only a verdict:unconvinced,doubting, orconvinced. The record itself never reaches the model that writes the reply. A convincing lie can be believed. Setmemory.lies_believabletofalseto turn a convinced lie into doubt. - When the verdict is
convinced, the character now believes what the player said, with the player as the source, and holds the old belief less firmly. - A reply that invents a character, place, or item that nobody gave the decision is handled by the invention rule of your policy.
None of this appears in the response. It shapes the reply. Read the character afterwards with the endpoint below.
The runtime read
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.
{
"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
}
]
}| Member | Meaning |
|---|---|
acknowledged_seq, processed_seq | The 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. |
location | Where the character was last reported, or null if never. |
beliefs | What the character holds to be so: memories of kind knowledge or impression. Most important first, at most 50. |
recollections | What the character perceived: memories of kind event. Newest first, at most 20. |
relations | Every 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. |
- Both
world_instance_idandtimeline_idare required, each 1 to 128 characters and given once. Otherwise the answer is 400 with a plaindetail. - The answer is 404 for a timeline Director has never received events for, and for a character Memory holds nothing for on that timeline.
- The read needs the Memory switch (403 otherwise), shows only your own account's data, calls no model, costs nothing, and counts toward no limit.
- The read goes through the ancestry of the timeline. A child timeline sees what its parent believed up to the branch point, and nothing from the future the player abandoned.
- The routes of the older Memory interface (entities, runs, context, consolidate, debug) are not available to accounts. They answer 404.
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 weighed | Computed 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 memory | Keeps 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 invention | The check finds invented names. | A model also catches an unnamed new relation, such as a brother nobody mentioned. |
| Model calls when events arrive | None | One for every memory formed and every memory retold |
| Model calls in a decision | The referee, when it applies | The referee, and one invention check on every reply |
| Cost | The referee only | Credits 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
- Sending events, storing memories, and the runtime read cost nothing. They are capped, see the limits.
- With
weighing: "rules", events cause no Memory model calls. Only the referee in a decision can, when the player's line touches a belief that is uncertain or contradicts the record. - Every Memory model call (weighing in
modelmode, rumour retelling, the referee, the invention check) costs usage credits exactly like a decision. See Billing and limits. - Judgements use the model you bind with
shared.judgement_model, else the decision's model inside a decision, else your account's default model.
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:
{
"memory": {
"persistent": {"characters": ["npc-seer"], "kinds": ["knowledge"]}
}
}- Memories of the listed
characters, and memories of the listedkinds(event,knowledge,impression), are kept for the whole world, visible from every timeline of it. They show"persistent": truein the read. - The world part never persists across timelines. What really happened follows the timeline.
- Persistent memories live and die with the world. Deleting the world removes them. Closing the account removes everything.