Consolidator Implementation Documentation
Overview
The Consolidator is a special goal type in the Thalabus planning system that aggregates and consolidates information from previously executed goals (via goal_dependent_upon). Its primary purpose is to gather summaries, RAG fragments, datasets, and other metadata from completed goals and pass them up the goal hierarchy, preventing information loss as the plan executes.
All logic lives in PythonServer/src/core/thalaplan/goal/Goal.py.
Main Entry Point: _run_consolidator()
_run_consolidator() is the single entry point. It always delegates to _run_consolidator_for_plan() inside a try/except, then writes the result back onto the current goal and notifies Blazor:
def _run_consolidator(self) -> dict:
try:
response = self._run_consolidator_for_plan()
except Exception as e:
log(ERROR, ...)
response = { "success": False, "datasets": None }
if response is not None:
_cons_summary = response.get("summary")
if _cons_summary and len(_cons_summary.strip()) > 0:
self.goal_summary = _cons_summary
self.goal_rag_fragments = response.get("rag_fragments")
self.goal_rag_toomanyfragments = response.get("rag_toomanyfragments")
self.goal_rag_docids = response.get("document_ids")
if "datasets" in response:
self.set_datasets(response["datasets"])
send_plan_to_blazor(self.goal_plan, f"Consolidator completed for goal {self.get_id_chain_as_str()}")
return response
Note — single strategy only. There is no plan-name gating (e.g.
"_no_answer") and no fallback "standard" consolidation strategy._run_consolidator_for_plan()is called unconditionally. Aget_last_summaries_or_rag()method still exists onGoalbut is not called anywhere in the codebase — it is dead code left over from a previous, now-removed dual-strategy design. Thegoal_summary_consolidatedflag andset_consolidated_summary()method described in earlier revisions of this document no longer exist.
What is Consolidated: _run_consolidator_for_plan()
Source Goals Selection: goal_dependent_upon
goal_dependent_upon is the only mechanism for selecting input goals. For each delta index, get_previous_goal(delta_from_self=goal_delta_index) resolves the referenced sibling goal:
If self is goal 1.3.7 (consolidator) and goal_dependent_upon = [-1, -3]
Then input_goals = [goal 1.3.6, goal 1.3.4]
If goal_dependent_upon is empty or resolves to zero goals, the method returns early with {"success": True, "datasets": None}.
RAG Fragments
For each input goal with non-empty goal_rag_fragments:
- find_last_rag_fragments(g) resolves any stub fragments (fragment-ID-only entries left by AgentReranker) into full {fragmentid, documentid, text, ranking, ranking_text} dicts, first by walking the sibling/parent goal tree, then via a batched Neo4j query for anything still unresolved.
- Fragments are deduplicated across all input goals by fragmentid (a seen_fragment_ids set).
- documentid values are collected into doc_ids.
Datasets
Each input goal's get_datasets() result is merged into all_datasets, deduplicated by id.
Attributes and Followups
attributes: taken from the last input goal that has non-Nonegoal_attributes(last one wins, not first).optional_disambiguating_answer_proposals: taken from the first input goal that has non-emptygoal_proposed_followups.
Summaries
For each input goal (skipping any with goal_summary_suppress = True):
- str → used directly.
- list → joined with newlines.
- dict with "returned_objects" → formatted as "The '<operation>' operation returned: <returned_objects>" (operation prefix omitted if absent).
- dict with "results" → formatted as "This information was extracted with RAG: <results>" (unwraps a single-element results list that itself contains a "results" key).
- Any other case → falls back to g.get_summary().
- Summaries starting with "FUNCTION" are wrapped in <HIDDEN_TO_USER>...</HIDDEN_TO_USER> so they are not shown verbatim to the user while still being available in context.
Command vs. content separation: summaries are split into command_summaries (start with /, e.g. /no_information_found) and content_summaries. If any content summaries exist, they are joined first, with commands appended after. If only commands exist, the first command alone becomes the consolidated summary (so it reaches the frontend as a clean, unmixed /command).
Side Effects
self._consolidator_deduplicate_fragments(self, [])— marks duplicate fragments across the broader goal tree (historical context spanning prior conversation turns), not just the current input goals.- A background daemon thread runs
self._consolidator_streamline_loaded_documents()fire-and-forget. This normalizes (strips and regenerates) HTML tag IDs on each document/chapter listed inplan_loaded_documentswhosecontent_typeishtml, and persists the updatedenhanced_textback to Neo4j (under a per-document lock) only if it changed. Non-HTML content is skipped; exceptions are caught and logged, never raised.
Response Structure
{
"summary": consolidated_summary, # str | None
"rag_fragments": all_rag_fragments or None,
"rag_toomanyfragments": self.goal_rag_toomanyfragments,
"document_ids": doc_ids or None,
"datasets": all_datasets or None,
"attributes": last_attributes,
"optional_disambiguating_answer_proposals": optional_disambiguating_answer_proposals,
"success": True
}
Helper Methods
| Method | Purpose |
|---|---|
find_last_rag_fragments(last_goal) |
Resolves stub RAG fragments (fragment-ID only, e.g. from AgentReranker) into fully hydrated dicts by searching the goal tree, then Neo4j as a last resort. |
_consolidator_deduplicate_fragments(goal, already_seen_fragment_ids) |
Marks duplicate fragments across the wider goal tree, beyond just the immediate input goals. |
_consolidator_streamline_loaded_documents() |
Fire-and-forget background normalization of HTML tag IDs on loaded documents/chapters; writes back to Neo4j only on change. |
Future Work / Known Gaps
get_last_summaries_or_rag()is dead code (unused) and could be removed, or repurposed if a secondary consolidation path is reintroduced.- The "single-strategy" design means every consolidator goal must have
goal_dependent_uponpopulated correctly at plan-construction time; there is no automatic fallback if the plan builder omits it (an empty/short-circuited response is returned instead).
Enhanced Logic
def run_consolidator_standard_enhanced(self) -> dict:
# STEP 1: Determine source goals
if self.goal_dependent_upon is not None and len(self.goal_dependent_upon) > 0:
# Use explicit dependencies (like plan-based consolidation)
input_goals = []
for goal_delta_index in self.goal_dependent_upon:
previous_goal = self.get_previous_goal(delta_from_self=goal_delta_index)
if previous_goal is not None:
input_goals.append(previous_goal)
else:
# Fallback to current backward sibling traversal
input_goals = self.get_last_summaries_or_rag()
# STEP 2: Consolidate (rest of logic remains similar)
# ... existing consolidation logic ...
Benefits of Unified Approach
- Explicit Control: Plan authors can declare exactly which goals to consolidate via
goal_dependent_upon - Predictable Behavior: Same mechanism works in both strategies
- Better Parallel Execution Support: Dependencies can specify goals from parallel branches
- Reduced Magic: Less implicit traversal logic, more declarative
- Easier Debugging: Clear dependency relationships visible in goal structure
- Backward Compatible: Falls back to current behavior when
goal_dependent_uponis empty
Migration Strategy
- Phase 1: Add
goal_dependent_uponsupport to standard consolidation (as shown above) - Phase 2: Update plan templates to populate
goal_dependent_uponfor consolidators - Phase 3: Monitor and validate that consolidation behavior remains correct
- Phase 4: Consider deprecating implicit backward traversal as fallback
Example Scenario
Current Behavior (Standard Consolidation):
Goals: 1.3.1 (AgentRAG), 1.3.2 (AgentToolCaller), 1.3.3 (AgentFocusser), 1.3.4 (AgentAssistant), 1.3.5 (Consolidator)
Consolidator 1.3.5:
- Traverses backwards: 1.3.4, 1.3.3, 1.3.2, 1.3.1
- Collects from all with summary/RAG
- No control over which goals are consolidated
Enhanced Behavior with goal_dependent_upon:
Goals: Same as above, but Consolidator 1.3.5 has goal_dependent_upon = [-1, -4]
Consolidator 1.3.5:
- Explicitly consolidates: 1.3.4 (AgentAssistant) and 1.3.1 (AgentRAG)
- Skips 1.3.3 and 1.3.2 (as intended by plan author)
- Clear, explicit control over consolidation scope
Supporting Methods
consolidator_deduplicate_fragments(current_goal, already_seen_fragment_ids)
Purpose: Walk backwards through goal chain and mark duplicate RAG fragments.
Algorithm:
1. Start from current goal
2. Traverse siblings backward (from current index to 0)
3. For each fragment with fragmentid, check if ID is in already_seen_fragment_ids
4. If duplicate: add frag["duplicate"] = True
5. If new: append fragment ID to already_seen_fragment_ids
6. Recursively call on parent goal
Effect: Later processing can treat marked duplicates differently (e.g., exclude from context).
consolidator_streamline_loaded_documents()
Purpose: Normalize HTML tag IDs in loaded documents.
Process:
1. For each ID in plan_loaded_documents
2. Load enhanced text from Neo4j
3. If content type is HTML:
- Strip existing HTML tag IDs
- Add normalized HTML tag IDs
- Save back to database if changed
4. Ensures consistent fragment referencing across document versions
find_last_rag_fragments(last_goal)
Purpose: Extract complete RAG fragment information.
Algorithm:
1. For each fragment in last_goal.goal_rag_fragments:
- If fragment has full information (documentid present): use directly
- If fragment has only fragmentid: search backwards through goal hierarchy
- Check siblings in reverse order
- Move up to parent and repeat
- If still not found: query Neo4j directly
2. Return list of complete fragments with documentid, fragmentid, text, ranking, ranking_text
Purpose: Ensures fragments always have complete information, even when later goals only reference fragment IDs.
Summary and Recommendations
Current State
- Two consolidation strategies with fundamentally different goal selection mechanisms
goal_dependent_upononly used in plan-based consolidation- Standard consolidation relies on implicit backward traversal
Key Insight
The goal_dependent_upon attribute represents explicit, declarative dependencies and should be the primary mechanism for consolidation in BOTH strategies.
Recommended Action
- Enhance
run_consolidator_standard()to check and usegoal_dependent_uponfirst - Maintain backward compatibility by falling back to current traversal logic when
goal_dependent_uponis empty - Update plan generation to populate
goal_dependent_uponfor consolidators - Document the new behavior and provide examples in plan templates
Expected Benefits
- More predictable and debuggable consolidation behavior
- Better support for parallel goal execution
- Explicit control over what gets consolidated
- Unified logic across both strategies
- Easier to reason about information flow in complex plans
Code Location Reference
- Main method:
Goal.py:2697-run_consolidator() - Plan-based:
Goal.py:2446-run_consolidator_for_plan() - Standard:
Goal.py:2542-run_consolidator_standard() - Helper methods:
Goal.py:568-get_previous_goal()Goal.py:939-get_last_summaries_or_rag()Goal.py:1755-find_last_rag_fragments()Goal.py:2710-consolidator_deduplicate_fragments()Goal.py:2761-consolidator_streamline_loaded_documents()