When the LLM returns ontology attributes as plain strings instead of
dicts, set_ontology() crashes with "TypeError: string indices must be
integers, not 'str'" at attr_def["name"].
Two-layer fix:
1. ontology_generator.py: normalize string attrs to {"name", "type",
"description"} dicts during validation, so downstream code always
receives well-formed structures.
2. graph_builder.py: add isinstance guard as a safety net in
set_ontology() for both entity and edge attribute loops.
Co-Authored-By: Octopus <liyuan851277048@icloud.com>
When the LLM generates a <tool_call> block followed by a self-generated
<tool_result> block in the same response, the fake result must be stripped
before appending to message history. The real tool result will be injected
separately by the system.
This fixes a React Hallucination bug where models could fabricate tool
results that didn't actually come from tool invocations.
The API retrieval layer hardcoded reddit as the default platform in 11+ locations. When a Twitter-only simulation was run, all data retrieval APIs silently returned empty results because they looked for reddit_simulation.db which did not exist. This commit reads the simulation enable_twitter/enable_reddit config to determine the correct default platform.
Fixes#150
- New Vue views: GodModeView (inject event, modify emotions with
preloaded current values, kill character with typed-name
confirmation) and WorldBuilderView (rules editor, locations with
cinematic atmosphere field, event log viewer)
- Shared sim-nav strip across Story/GodMode/World views
- Location schema extended with optional atmosphere field — a short
mood phrase that anchors the opening visual of every scene set there
- Translator's _format_world_locations surfaces atmosphere to the LLM
prompt so the field actually influences generation
- Routes added for /godmode/:simId and /world/:simId
Tests: 39/39 passing (added test_location_atmosphere_surfaces_in_prompt).
Frontend builds clean.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- PROSE_PROMPT_TEMPLATE extended with world_rules, world_events,
world_locations, and event_enforcement substitution fields
- EVENT_ENFORCEMENT_STRENGTH set to "hard" — opening line MUST
reference the most recent world event (aligns with existing
punchy, cinematic voice)
- Character summaries now resolve location id → name for prompts
- translate_round loads world_state and filters dead characters
from both the roster and the action list before prose generation
- User-supplied strings (rules, events, locations) brace-escaped
before str.format() to prevent KeyError on stray { or }
Tests: 36/36 passing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
translate_round() ties together:
- reading the round's actions from actions.jsonl
- generating prose via the LLM
- updating per-character emotional state
- persisting the beat, characters, and file offset
Full test suite now at 19/19 passing across action mapper, character
engine, story store, and translator.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Module-level call_llm() wrapper (patchable by tests) drives
PROSE_PROMPT_TEMPLATE rendering with character summaries, actions,
previous beats, and user-selected tone. Prompt tuned for punchy,
cinematic, dialogue-heavy voice.
Tests: 5/5 passing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Reads one round's worth of agent actions from the OASIS log file,
tracking file offset so callers can resume across translation calls.
Handles missing files, malformed JSON lines, and non-target rounds
gracefully.
Tests: 3/3 passing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Character profiles now track a six-dimension emotional state (anger,
fear, joy, sadness, trust, surprise) that evolves based on actions
taken. Initial deltas for all 13 OASIS actions chosen as a balanced
baseline (see module docstring for tuning guidance).
Tests: 5/5 passing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Three JSON files per simulation under narrative/ subdir:
- story_beats.json: chronological story passages
- translator_state.json: per-platform file offsets
- characters.json: extended character profiles
Tests: 4/4 passing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New narrative package with action_mapper module that maps the 13 OASIS
action types (CREATE_POST, LIKE_POST, REPOST, etc.) to narrative verbs
and interpretations used when generating story prose.
Tests: 4/4 passing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Background threads (graph building, simulation prep, report generation,
profile generation) now inherit the requesting user's locale preference.
Previously these fell back to 'zh' because Flask request context was
unavailable in spawned threads.
Ensure poster_type stays PascalCase English and stance stays English enum
values regardless of language setting. Only natural language fields follow
the user's language preference.
The language instruction was causing LLM to change entity/relation naming
conventions. Now explicitly enforce PascalCase/UPPER_SNAKE_CASE for technical
identifiers while only applying language preference to description fields.