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. A get_last_summaries_or_rag() method still exists on Goal but is not called anywhere in the codebase — it is dead code left over from a previous, now-removed dual-strategy design. The goal_summary_consolidated flag and set_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

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

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

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

  1. Explicit Control: Plan authors can declare exactly which goals to consolidate via goal_dependent_upon
  2. Predictable Behavior: Same mechanism works in both strategies
  3. Better Parallel Execution Support: Dependencies can specify goals from parallel branches
  4. Reduced Magic: Less implicit traversal logic, more declarative
  5. Easier Debugging: Clear dependency relationships visible in goal structure
  6. Backward Compatible: Falls back to current behavior when goal_dependent_upon is empty

Migration Strategy

  1. Phase 1: Add goal_dependent_upon support to standard consolidation (as shown above)
  2. Phase 2: Update plan templates to populate goal_dependent_upon for consolidators
  3. Phase 3: Monitor and validate that consolidation behavior remains correct
  4. 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

Key Insight

The goal_dependent_upon attribute represents explicit, declarative dependencies and should be the primary mechanism for consolidation in BOTH strategies.

Recommended Action

  1. Enhance run_consolidator_standard() to check and use goal_dependent_upon first
  2. Maintain backward compatibility by falling back to current traversal logic when goal_dependent_upon is empty
  3. Update plan generation to populate goal_dependent_upon for consolidators
  4. Document the new behavior and provide examples in plan templates

Expected Benefits


Code Location Reference