Resolve Issue #52: Fix missing document-level images and incorrect rendering order - #53
Merged
Merged
Conversation
…ing, synthesis, and execution budget management.
|
|
||
| _SCOPE_NAV_PROMPT = """\ | ||
|
|
||
| _DISCOVERY_SELECT_PROMPT = """\ |
| """ | ||
|
|
||
|
|
||
| _ACTION_PROMPT = """\ |
| data = _json.loads(text) | ||
| if isinstance(data, dict): | ||
| return _extract(data) | ||
| except (ValueError, _json.JSONDecodeError): |
| data = _json.loads(fence_match.group(1).strip()) | ||
| if isinstance(data, dict): | ||
| return _extract(data) | ||
| except (ValueError, _json.JSONDecodeError): |
| data = _json.loads(brace_match.group()) | ||
| if isinstance(data, dict): | ||
| return _extract(data) | ||
| except (ValueError, _json.JSONDecodeError): |
| # Simple queries: planner returns a single-step plan (no decomposition). | ||
| # Complex queries: planner returns a multi-step plan with synthesize. | ||
| # Both go through the same code path. | ||
| from shared.services.retrieval.workflow.orchestrator import WorkflowOrchestrator |
|
|
||
| from shared.core.database import get_db_context | ||
| from shared.services.retrieval.agentic.budget import BudgetLedger | ||
| from shared.services.retrieval.agentic.orchestrator import RetrievalAgent |
| parsed = json.loads(text) | ||
| if isinstance(parsed, dict): | ||
| return parsed | ||
| except (ValueError, json.JSONDecodeError): |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #52
Summary
This PR fixes a critical data integrity bug where standalone images located in the document root and L1 sections (e.g. preface/cover page) were being silently discarded during the Agentic RAG pipeline's asset reconciliation phase. Additionally, it corrects the rendering order so document-level assets appear at the top of the evidence tree.
Root Cause Analysis
Three interacting defects caused 3 out of 10 images to be silently dropped:
1. Overly Aggressive L1 Guard (
asset_filter_step)The guard clause
if own_section_path and ' / ' not in own_section_pathwas designed to reject only the synthetic"Root"aggregation label, but it inadvertently blocked ALL L1 section paths (e.g."前言","法律声明") since they also lack a/separator. This caused image-3 (preface chart) to be discarded at the filter stage before it ever reached reconciliation.2. Synthetic
"Root"Label Mismatch (_build_connected_owner_map)The DB stores
section_path = "Root"for document-level sections, but the outline tree uses the document'ssource_file_nameas the root path. The"Root"string could never match any outline node, causing image-1 and image-2 (cover page diagrams) to fail both Tier-1 exact match and Tier-2 ancestor walk.3. Tier-1 Match Too Narrow (
_reconcile_deferred_assets)Tier-1 exact matching only checked
final_paths(hydrated leaf content). In STOP scenarios where the LLM stops at root without drilling down,final_pathsis empty, so even correctly resolved owner paths like"前言"had no target to match against.Changes
tools.py— Asset Filter Step_build_connected_owner_mapreturns"Root"as an owner, dynamically replace it with the document'ssource_file_namevia a DB lookup. This gives root-level assets a real, matchable path identity.' / ' not in own_section_pathtoown_section_path == 'Root', so legitimate L1 sections like"前言"are no longer rejected as fallback owners.orchestrator.py— Reconciliation & Tree Assemblyfinal_pathstoall_target_paths(union of hydrated leaves + visible outline sections). This allows assets to be placed under visible but un-hydrated sections in STOP scenarios.source_file_nameintoroot.outline_itemsat position 0 (top of evidence tree), but ONLY whennot root.children(pure STOP — no drill-down navigation). This prevents root-level assets from leaking into focused navigation scenarios.Verification
E2E test results with
debug_agentic_e2e.py:Image-1/2 now render at the TOP of the evidence tree (before L1 sections) in T0, and are correctly excluded from T5's focused navigation.