44from ..context import AnalysisContext
55try :
66 from services .workflow_pruner import WorkflowPruner
7+ from services .context_extractor import (
8+ extract_error_summary ,
9+ collapse_stack_frames ,
10+ build_context_manifest ,
11+ )
712except ImportError :
813 # Use relative import for flexibility
914 import sys
1015 import os
1116 sys .path .append (os .path .abspath (os .path .join (os .path .dirname (__file__ ), "../.." )))
1217 from services .workflow_pruner import WorkflowPruner
18+ from services .context_extractor import (
19+ extract_error_summary ,
20+ collapse_stack_frames ,
21+ build_context_manifest ,
22+ )
1323
1424logger = logging .getLogger (__name__ )
1525
1626class LLMContextBuilderStage (PipelineStage ):
1727 """
1828 Stage 4: LLM Context Builder.
19- Prepares the context for LLM analysis (R12).
20- - Prunes workflow JSON to relevant subgraph.
21- - Estimates token usage.
22- - Structures data for the LLM prompt.
29+ Prepares the context for LLM analysis (R12 + R14).
30+ - Extracts error summary (R14: summary-first prompt)
31+ - Collapses stack frames (R14: semantic truncation)
32+ - Prunes workflow JSON to relevant subgraph (R12)
33+ - Builds context manifest for observability (R14)
2334 """
2435
2536 def __init__ (self , workflow_pruner : WorkflowPruner ):
@@ -32,8 +43,8 @@ def __init__(self, workflow_pruner: WorkflowPruner):
3243 self ._name = "LLMContextBuilderStage"
3344 self .stage_id = "llm_context_builder"
3445 self .requires = ["sanitized_traceback" ]
35- self .provides = ["llm_context" , "metadata.estimated_tokens" ]
36- self .version = "1 .0"
46+ self .provides = ["llm_context" , "metadata.estimated_tokens" , "metadata.context_manifest" ]
47+ self .version = "2 .0" # R14 upgrade
3748 self .pruner = workflow_pruner
3849
3950 @property
@@ -42,12 +53,36 @@ def name(self) -> str:
4253
4354 def process (self , context : AnalysisContext ) -> None :
4455 """
45- Builds the LLM context.
56+ Builds the LLM context with R14 optimizations.
57+
58+ Order of sections in llm_context (summary-first):
59+ 1. error_summary - Short exception type + message
60+ 2. node_info - Failed node details
61+ 3. traceback - Collapsed if long
62+ 4. execution_logs - Recent log lines
63+ 5. workflow_subset - Pruned workflow
64+ 6. system_info - Environment info
4665 """
4766 if not context .sanitized_traceback :
4867 return
4968
50- # 1. Prune Workflow if available
69+ # R14 Step 1: Extract error summary
70+ pattern_category = context .metadata .get ("pattern_match" , {}).get ("category" )
71+ error_summary = extract_error_summary (
72+ context .sanitized_traceback ,
73+ pattern_category = pattern_category
74+ )
75+ if error_summary :
76+ context .error_summary = error_summary .to_string ()
77+
78+ # R14 Step 2: Collapse stack frames for token efficiency
79+ collapsed_traceback = collapse_stack_frames (
80+ context .sanitized_traceback ,
81+ head_frames = 3 ,
82+ tail_frames = 5
83+ )
84+
85+ # Step 3: Prune Workflow if available
5186 pruned_workflow = None
5287 if context .workflow_json and context .node_context and context .node_context .node_id :
5388 try :
@@ -57,23 +92,34 @@ def process(self, context: AnalysisContext) -> None:
5792 )
5893 except Exception as e :
5994 logger .warning (f"Workflow pruning failed: { e } " )
60- # Fallback to original or summary?
61- # For now, maybe just keep original or nothing
6295 pruned_workflow = context .workflow_json
6396
64- # 2. Build LLM Context Dict
97+ # Step 4: Build LLM Context Dict (summary-first order)
6598 llm_data = {
66- "traceback " : context .sanitized_traceback ,
99+ "error_summary " : context .error_summary , # R14: First
67100 "node_info" : context .node_context .to_dict () if context .node_context else {},
101+ "traceback" : collapsed_traceback , # R14: Collapsed
102+ "execution_logs" : context .execution_logs , # R14: From ring buffer
68103 "workflow_subset" : pruned_workflow ,
69104 "system_info" : context .system_info
70105 }
71106
72107 context .llm_context = llm_data
73108
74- # 3. Estimate Tokens (Optional Metadata)
109+ # R14 Step 5: Build context manifest for observability
110+ manifest = build_context_manifest (
111+ traceback_text = context .sanitized_traceback ,
112+ execution_logs = context .execution_logs ,
113+ workflow_json = context .workflow_json ,
114+ system_info = context .system_info ,
115+ error_summary = error_summary
116+ )
117+ context .add_metadata ("context_manifest" , manifest .to_dict ())
118+
119+ # Step 6: Estimate Tokens (Optional Metadata)
75120 try :
76121 tokens = self .pruner .estimate_tokens (llm_data )
77122 context .add_metadata ("estimated_tokens" , tokens )
78123 except Exception :
79124 pass
125+
0 commit comments