Step3Simulation mounted with a simulation id and immediately called
doStartSimulation() with force: true. Because the id lives in the route
path (/simulation/:simulationId/start), a browser refresh remounted the
component and re-sent that request, so the backend stopped the running
subprocess and cleaned the run directory: run_state.json, the twitter and
reddit actions.jsonl action logs, and both *_simulation.db files. The
timeline, posts and comments views read those files directly, so the data
was unrecoverable.
Probe the run status before deciding what to do. A simulation that has
never run (runner_status "idle" with no recorded actions) still starts
exactly as before. Anything else is adopted instead of restarted: live
runs resume polling, finished runs load their existing timeline read-only.
If the status probe itself fails we now do nothing rather than risk
overwriting a run we could not verify.
force is also no longer hardcoded to true. The remaining call site only
runs when there is nothing to lose, and the flag should never be an
implicit default.
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
Previously, the frontend only checked for 'completed' and 'stopped'
status to stop polling. When the simulation process exited with an
error (runner_status === 'failed'), polling continued indefinitely.
This commit adds handling for the 'failed' status:
- Stop polling when runner_status is 'failed'
- Display error message in the log
- Update UI status to 'error'
- Add i18n translations for simFailed key
fetch_all_nodes already had a max_items guard (default 2000) but
fetch_all_edges had no such safeguard, allowing unbounded memory growth
on graphs with large numbers of edges.
Add _MAX_EDGES = 5000 constant and mirror the same loop-guard pattern
from fetch_all_nodes: cap the result list, emit a warning log, and
break pagination once the limit is reached.
Upgrade the transitive Python dependency NLTK from 3.9.2 to 3.10.0 to address CVE-2025-14009. The contributor title said 3.9.3, but the reviewed lockfile resolves 3.10.0.
HistoryDatabase.vue formatDate() derived the day from UTC
(new Date(dateStr).toISOString().slice(0, 10)) while the sibling
formatTime() uses local hours/minutes. The backend sends naive-local
timestamps (datetime.now().isoformat()), so for any non-UTC client the
two disagree by up to a day -- e.g. for the project's UTC+8 audience a
record created 00:00-08:00 local shows the previous day's date next to
the current time. Derive the date from local components so it matches
the time shown.