Blueprint v1.5.0: AI Context Optimization — Dynamic Characters & Scene State
- writer.py: Dynamic character injection — only POV + beat-named characters are sent to the writer prompt, eliminating token waste and hallucinations from characters unrelated to the current scene. - writer.py: Smart tail truncation — prev_content trimmed to last 1,000 tokens (the actual chapter ending) instead of a blind 2,000-token head slice, preserving the exact hand-off point for continuity. - writer.py: Scene state injected into char_visuals — current_location, time_of_day, and held_items now surfaced per relevant character in prompt. - bible_tracker.py: update_tracking expanded to record current_location, time_of_day, and held_items per character after each chapter. - core/config.py: VERSION bumped 1.4.0 → 1.5.0. - README.md: Story Generation section and tracking_characters.json schema updated to document new context optimization features. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -46,10 +46,30 @@ def write_chapter(chap, bp, folder, prev_sum, tracking=None, prev_content=None,
|
||||
if samples:
|
||||
persona_info += "\nWRITING STYLE SAMPLES:\n" + "\n".join(samples)
|
||||
|
||||
# Only inject characters named in the chapter beats + the POV character
|
||||
beats_text = " ".join(str(b) for b in chap.get('beats', []))
|
||||
pov_lower = pov_char.lower() if pov_char else ""
|
||||
chars_for_writer = [
|
||||
{"name": c.get("name"), "role": c.get("role"), "description": c.get("description", "")}
|
||||
for c in bp.get('characters', [])
|
||||
if c.get("name") and (
|
||||
c["name"].lower() in beats_text.lower() or
|
||||
(pov_lower and c["name"].lower() == pov_lower)
|
||||
)
|
||||
]
|
||||
if not chars_for_writer:
|
||||
chars_for_writer = [
|
||||
{"name": c.get("name"), "role": c.get("role"), "description": c.get("description", "")}
|
||||
for c in bp.get('characters', [])
|
||||
]
|
||||
relevant_names = {c["name"] for c in chars_for_writer}
|
||||
|
||||
char_visuals = ""
|
||||
if tracking and 'characters' in tracking:
|
||||
char_visuals = "\nCHARACTER TRACKING (Visuals & Preferences):\n"
|
||||
char_visuals = "\nCHARACTER TRACKING (Visuals, State & Scene Position):\n"
|
||||
for name, data in tracking['characters'].items():
|
||||
if name not in relevant_names:
|
||||
continue
|
||||
desc = ", ".join(data.get('descriptors', []))
|
||||
likes = ", ".join(data.get('likes_dislikes', []))
|
||||
speech = data.get('speech_style', 'Unknown')
|
||||
@@ -62,6 +82,13 @@ def write_chapter(chap, bp, folder, prev_sum, tracking=None, prev_content=None,
|
||||
if worn and worn != 'Unknown':
|
||||
char_visuals += f" * Last Worn: {worn} (NOTE: Only relevant if scene is continuous from previous chapter)\n"
|
||||
|
||||
location = data.get('current_location', '')
|
||||
items = data.get('held_items', [])
|
||||
if location:
|
||||
char_visuals += f" * Current Location: {location}\n"
|
||||
if items:
|
||||
char_visuals += f" * Held Items: {', '.join(items)}\n"
|
||||
|
||||
style_block = "\n".join([f"- {k.replace('_', ' ').title()}: {v}" for k, v in style.items() if isinstance(v, (str, int, float))])
|
||||
if 'tropes' in style and isinstance(style['tropes'], list):
|
||||
style_block += f"\n- Tropes: {', '.join(style['tropes'])}"
|
||||
@@ -71,13 +98,8 @@ def write_chapter(chap, bp, folder, prev_sum, tracking=None, prev_content=None,
|
||||
|
||||
prev_context_block = ""
|
||||
if prev_content:
|
||||
trunc_content = utils.truncate_to_tokens(prev_content, 2000)
|
||||
prev_context_block = f"\nPREVIOUS CHAPTER TEXT (For Tone & Continuity):\n{trunc_content}\n"
|
||||
|
||||
chars_for_writer = [
|
||||
{"name": c.get("name"), "role": c.get("role"), "description": c.get("description", "")}
|
||||
for c in bp.get('characters', [])
|
||||
]
|
||||
trunc_content = utils.truncate_to_tokens(prev_content, 1000)
|
||||
prev_context_block = f"\nPREVIOUS CHAPTER TEXT (Last ~1000 Tokens — For Immediate Continuity):\n{trunc_content}\n"
|
||||
|
||||
total_chapters = ls.get('chapters', '?')
|
||||
prompt = f"""
|
||||
|
||||
Reference in New Issue
Block a user