55from datetime import datetime
66import json
77import re
8- from typing import Dict , List , Optional , Tuple
8+ from typing import Any , Dict , List , Optional , Tuple
99from urllib .parse import urlparse
1010
1111import structlog
@@ -339,6 +339,21 @@ async def run_agent_pipeline(
339339 )
340340 queue = _deduplicate_test_cases (queue + chain_tests )
341341
342+ # Human-friendly iteration summary in the terminal
343+ console .print (
344+ Panel (
345+ f"[bold]Iteration { iteration } summary[/bold]\n "
346+ f"- Executed tests this iteration: [cyan]{ len (results )} [/cyan]\n "
347+ f"- New confirmed findings: [green]{ len (batch_confirmed )} [/green]\n "
348+ f"- New suspected findings: [yellow]{ len (batch_suspected )} [/yellow]\n "
349+ f"- Chained follow-up tests queued: [magenta]{ len (chain_tests )} [/magenta]\n "
350+ f"- Remaining request budget: [white]{ remaining_budget } [/white]\n "
351+ f"- Dynamic concurrency: [white]{ dynamic_concurrency } [/white]" ,
352+ title = f"🤖 Agent Iteration { iteration } " ,
353+ border_style = "magenta" ,
354+ )
355+ )
356+
342357 # Run final AI deduplication
343358 console .rule ("[bold yellow]Phase 3: Final Intelligence Processing" )
344359 confirmed = await deduplicate_findings_with_ai (confirmed )
@@ -369,7 +384,7 @@ async def build_pipeline_artifacts(
369384 verify_ssl = pipeline_input .verify_ssl ,
370385 )
371386 api_structure = analyze_api_structure (raw_schema )
372-
387+
373388 # Phase 1a — Active Reconnaissance (built-in fuzzer)
374389 discovered_endpoints = await perform_active_recon (api_structure , pipeline_input )
375390 if discovered_endpoints :
@@ -380,9 +395,10 @@ async def build_pipeline_artifacts(
380395 api_structure .endpoints = list (unique_endpoints .values ())
381396
382397 # Phase 1b — External Tool Orchestration (Dirsearch, Arjun, Nuclei, SQLMap)
398+ tool_context : Optional [Dict [str , Any ]] = None
383399 try :
384400 orch_result = await run_tool_orchestration_phase (api_structure , api_structure .base_url )
385-
401+
386402 # Merge tool-discovered endpoints into schema
387403 if orch_result .discovered_endpoints :
388404 for ep in orch_result .discovered_endpoints :
@@ -396,22 +412,74 @@ async def build_pipeline_artifacts(
396412 total = len (api_structure .endpoints ),
397413 added = len (orch_result .discovered_endpoints ),
398414 )
415+
416+ # Merge Dirsearch/Arjun-discovered parameters back into API structure
417+ if orch_result .discovered_params :
418+ merged_count = 0
419+ for ep_key , params in orch_result .discovered_params .items ():
420+ # Normalise the endpoint key (which may be a full URL) down to a path
421+ try :
422+ parsed = urlparse (ep_key )
423+ path = parsed .path or ep_key
424+ except Exception :
425+ path = ep_key
426+ if not path .startswith ("/" ):
427+ path = f"/{ path } "
428+
429+ for endpoint in api_structure .endpoints :
430+ if endpoint .path != path :
431+ continue
432+ existing_param_names = {p .name for p in endpoint .parameters }
433+ for p_name in params :
434+ if not p_name or p_name in existing_param_names :
435+ continue
436+ endpoint .parameters .append (
437+ type (endpoint ).model_fields ["parameters" ].annotation .__args__ [0 ]( # type: ignore[index]
438+ name = p_name ,
439+ ** {"in" : "query" },
440+ required = False ,
441+ schema_type = "string" ,
442+ )
443+ )
444+ merged_count += 1
445+ logger .info (
446+ "Merged tool-discovered parameters" ,
447+ total_parameters_merged = merged_count ,
448+ )
449+
450+ # Build compact tool context for downstream AI prompts
451+ tool_context = {
452+ "dirsearch_discovered_paths" : sorted (
453+ {ep .path for ep in orch_result .discovered_endpoints }
454+ ),
455+ "tool_discovered_params" : orch_result .discovered_params ,
456+ "tool_findings_sample" : [
457+ {
458+ "endpoint" : f .endpoint ,
459+ "method" : f .method ,
460+ "vuln" : f .vulnerability_class ,
461+ "cvss" : f .cvss_score ,
462+ }
463+ for f in orch_result .tool_findings [:25 ]
464+ ],
465+ }
399466 except Exception as e :
400467 logger .warning ("Tool orchestration phase failed, continuing without tools" , error = str (e ))
401468 orch_result = None
469+ tool_context = None
402470
403471 # Phase 1c — Deep Doc Analysis + AI-Directed Arjun Parameter Discovery
404472 try :
405473 api_structure = await perform_deep_recon (raw_schema , api_structure , pipeline_input )
406474 except Exception as e :
407475 logger .warning ("Deep recon phase failed, continuing without parameter enrichment" , error = str (e ))
408476
409-
410- understanding = await understand_api_with_ai (api_structure )
477+ understanding = await understand_api_with_ai (api_structure , tool_context = tool_context )
411478 tests = await generate_test_cases (
412479 understanding ,
413480 api_structure ,
414- instructions = pipeline_input .instructions [0 ].model_dump () if pipeline_input .instructions else None
481+ instructions = pipeline_input .instructions [0 ].model_dump () if pipeline_input .instructions else None ,
482+ tool_context = tool_context ,
415483 )
416484 return api_structure , tests , orch_result
417485
0 commit comments