Give a memory a word ceiling, after measuring one
Ran the memory prompt end to end against a real model as a controlled A/B: one story generated through the app's own build_context a turn at a time, then both prompts run over the same blocks, so the story is held constant and the prompt is the only variable. Fresh process per call, so neither arm sees the other and the model is never told what is being tested. The control is the exact prompt from 9cdcb55. The reported fault reproduced. Two consecutive memories written from one story minutes apart came back in two different persons — "You crept low through the mist" and "The player asked Gwen to". With the cast brief both named Kaelen. The control also inverted who acted on a move whose player text was "grab her wrist and pull her down", which is the failure the brief predicts: with no cast there is nothing to say whose wrist "her wrist" was. It also found something the prompt review had not. "1-2 plain sentences" is not a length, and the same model wrote 34 words for one block and 105 for the next. A 105-word memory is a paragraph, and `memory_top_k` injects five every turn, so the bank's running cost was set by a number nobody had ever stated. MEMORY_MAX_WORDS states it, and the prompt now says which details to keep when trimming: the ones a later scene could turn on. Re-run over the identical story, the same two blocks came back at 32 and 58 words, still named, still third person, still carrying the camp map, the strongbox behind the second tent, and the strap frayed near through. Variance is the real gain — 34..105 became 32..58. Overshooting 50 slightly is expected. Models exceed word budgets, which is why builder.length_hint already carries a buffer for the same reason. What this does not show: the run used a Claude model, and the app talks to an OpenAI-compatible endpoint whose weaker models are why worldstate/parse.py tolerates trailing commas. The prompt is followable and the brief supplies the missing information; a weaker model is not proven to comply as well. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NPyQN926gkZTAYfgugcaok
This commit is contained in:
@@ -63,6 +63,14 @@ MAX_CAST_MEMBERS = 8
|
||||
CAST_ENTRY_CHARS = 240
|
||||
SETTING_TOKENS = 300 # of `adventure.memory`, the plot essentials
|
||||
|
||||
# A ceiling on one memory, in words. Measured, not guessed: with only
|
||||
# "1-2 plain sentences" to go on, a real model wrote 34 words for one block and
|
||||
# 105 for the next, and a 105-word memory is a paragraph. Five of those are
|
||||
# injected per turn at the default `memory_top_k`, so the bank's cost is set
|
||||
# here. A stated number also holds the length steady between memories, which is
|
||||
# the same consistency the framing rule buys for the wording.
|
||||
MEMORY_MAX_WORDS = 50
|
||||
|
||||
# The framing rule is the larger half of this prompt, and it is worth the
|
||||
# tokens. Without it the model chooses a person per call, so one bank ends up
|
||||
# holding "You entered the crypt", "The player entered the crypt" and "He
|
||||
@@ -77,7 +85,9 @@ SETTING_TOKENS = 300 # of `adventure.memory`, the plot essentials
|
||||
MEMORY_SYSTEM_PROMPT = (
|
||||
"You compress interactive-fiction story excerpts into memories. Respond with "
|
||||
"1-2 plain sentences in past tense stating the concrete facts and events "
|
||||
"(names, places, items, promises, injuries).\n\n"
|
||||
f"(names, places, items, promises, injuries), in at most {MEMORY_MAX_WORDS} "
|
||||
"words. Keep the details a later scene could turn on — a name, a promise, an "
|
||||
"injury, where something is — and drop the ones it could not.\n\n"
|
||||
"Write in the third person. The excerpt is written in the second person: "
|
||||
'"you" is the protagonist, who is named in the Cast. Refer to the '
|
||||
'protagonist by that name, never as "you". If the Cast gives no name for '
|
||||
|
||||
Reference in New Issue
Block a user