Consolidate Character Profiles
Consolidate Character Profiles
- character_evidence
- lmstudio_config
- character_profiles
- saved_file
Extraction gives you facts scattered across chapters. That's not a character sheet, it's a pile of index cards. This node is the step that turns the pile into one profile per person - deciding that "Ellis", "El", "young Halloway" and "the captain" are the same identity, then reconciling what the text says about their hair across four hundred pages.
It's the boring, load-bearing stage of the MiniMax H3 Novel Pipeline. Skip it and you'll generate beautiful clips of four slightly different people who are supposed to be one.
How the merge actually works
Not by name matching. The node runs identity grouping in bounded chapter batches first, then contextual comparisons across those batches. Shared names or roles only nominate a comparison - they never auto-merge - which is the correct and slightly paranoid design, because "the doctor" is a different person in chapter 3 and chapter 19 in half the novels ever written. Trait analysis then runs per character in bounded batches, reconciling precise trait keys before values get compared across everything.
The output document is versioned and editable, and it's built to preserve disagreement rather than resolve it by guessing. global_traits holds explicit stable physical evidence. temporary_states keeps local observations - the mud, the bandage, the borrowed coat - without pretending they're canon. chronological_changes separates things a character acquired from things that were always true and mentioned late. unresolved_conflicts holds the arguments with a choices array, the first choice pre-selected. The README is pointed about one thing worth repeating: chapter order is not story chronology, and a wound does not establish a scar. If you're adapting a novel with flashbacks, that distinction is doing real work for you.
Inputs that change your results
character_evidence comes from Character Evidence Extractor or Load Character Evidence, and lmstudio_config from LM Studio Configuration. Wire both.
persistence_filter is the one I'd think about before running. Default persistent drops every observation marked temporary or unknown before consolidation, which is what you want for a character's body - but the tooltip's inverse is real too: filtering can remove context the model would have used to connect aliases. If your protagonist is described almost entirely through transient appearances (a shapeshifter, someone in disguise for the first act), try everything and compare.
context_tokens defaults to 65536 and must not exceed what your LM Studio instance actually has loaded - the node can't read your server's context size, so it trusts you. The input budget reserves room for max_tokens plus framing and counts conservatively. Lower it if requests are failing; an indivisible oversized observation produces an explicit diagnostic rather than truncated evidence, which is a good failure, not a bad one.
correction_attempts defaults to 0 here, unlike the extractor's 2. At 0, invalid identity decisions are skipped immediately with no repair or subdivision pass. That's deliberate - consolidation is the expensive stage - but if you've got difficult alias work, 1 or 2 is cheap insurance. thinking defaults to false for speed; turn it on when identity calls are genuinely hard.
Outputs are character_profiles (typed, wire it into Character Visual Profile Generator) and saved_file, pointing at character_profiles.json under out_dir (default character_profiles).
Install, and the LM Studio part
Same pack, so same install - Manager search for "MiniMax H3 Novel Pipeline", or:
cd ComfyUI/custom_nodes
git clone https://github.com/yuyuki/ComfyUI-Minimax_H3_Novel_Pipeline
python -m pip install -r ComfyUI-Minimax_H3_Novel_Pipeline/requirements.txt
Restart ComfyUI afterwards, and refresh the browser tab - the nodes appear under MiniMax H3 Novel. You need Python 3.10+, and LM Studio running its local server with a Qwen model loaded. The API key goes in ComfyUI Settings → MiniMax H3 Novel → LM Studio (lm-studio if auth is off), and a non-default endpoint must be registered there as Trusted API URL as well as typed into the config node.
Troubleshooting that's actually grounded
It refuses to run with a Mistral model. Consolidation hard-checks model_family == "Qwen" in lmstudio_config and raises otherwise. Whatever the README says about Mistral in the wider pipeline, this node is Qwen-only.
Everything stayed separate. Unresolved identity decisions leave observations separate by design - the node would rather hand you two half-profiles than merge two people. Look at character_profiles_validation.json and character_profiles_requests.json; the first holds the excluded evidence and validation detail, the second records warnings and which inputs caused them. Consolation: consolidation writes the validation file before its LLM request, so you still have the exclusion details if the request itself dies.
It's re-doing work. Validated requests are cached under <run>/<out_dir>/.cache/character_profiles, keyed on input, prompt, schema, model and settings. Change any of them and that batch re-runs; force re-runs everything. When a batch stays invalid after its allowed corrections, the node logs a warning and subdivides it to recover the independent decisions - those fallbacks aren't cached as successes, which is why you may see the same warning twice.
Your edits got clobbered. Rerunning writes character_profiles.json again. If you've hand-edited it, keep the good version as a renamed copy and load that through Load Character Profiles instead - that's exactly what the loader is for.
Inputs (10)
| Name | Type | Default | Description |
|---|---|---|---|
| character_evidence | MINIMAX_CHARACTER_EVIDENCE | — | |
| lmstudio_config | MINIMAX_LMSTUDIO_CONFIG | — | |
| out_dir | STRING | character_profiles | — |
| thinking | BOOLEAN | false | — |
| temperature | FLOAT | 0.120–2 | — |
| max_tokens | INT | 16384256–100000 | — |
| context_tokens | INT | 655368192–2000000 | Must not exceed the loaded LM Studio context. Includes output and retry reserves. |
| correction_attempts | INT | 00–10 | 0 skips invalid decisions immediately, without correction or subdivision requests. |
| force | BOOLEAN | false | — |
| persistence_filter | COMBO | persistent | Consolidate only persistent observations, or include temporary and unknown observations too. |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| character_profiles | MINIMAX_CHARACTER_PROFILES | — |
| saved_file | STRING | — |