All agents communicate through SARInvestigationState (defined in src/agents/state.py). Key fields and their ownership:
| Field | Type | Written By | Read By |
|---|---|---|---|
case_id |
str | Graph init | All agents |
current_phase |
str | Each agent on completion | Supervisor |
enriched_transactions |
list[dict] | Data ingestion | Crime detection, typology agents |
case_summary |
dict | Data ingestion | Narrative, validation |
detected_crime_types |
list[str] | Crime detection | Supervisor, narrative |
crime_type_confidence |
dict | Crime detection | Supervisor, typology dispatch |
typology_results |
Annotated[list[dict]] | Typology agents (parallel) | Aggregator, narrative, validation |
external_intel |
list[dict] | External intelligence | Narrative |
sar_narrative_draft |
str | Narrative generation | Validation, human review |
narrative_confidence |
float | Narrative generation | Validation, UI |
compliance_checks |
list[dict] | Compliance validation | Feedback, UI |
compliance_score |
float | Compliance validation | Supervisor routing |
compliance_passed |
bool | Compliance validation | Supervisor routing |
human_feedback |
Optional[str] | Human review | Feedback agent |
sar_approved |
bool | Human review | Supervisor routing |
investigation_outcome |
str | Supervisor / no_detection | API response |
agent_trace_log |
Annotated[list[dict]] | All agents | Audit endpoints |
- File:
src/agents/supervisor.py - Purpose: Route the investigation through phases based on current state
- Method: Conditional edge function (
plan_next_step) readscurrent_phaseand detection results - Routing logic:
ingestion→ crime_detectiondetection→ dispatch_typologyanalysis→ external_intelligence OR no_detection (false positive)intelligence→ narrative_generationnarrative→ compliance_validationvalidation→ human_review (pass) OR feedback_revision (fail)revision→ narrative_generationreview→ end (approved) OR feedback_revision (rejected)
- File:
src/agents/crime_detection/agent.py - Input:
enriched_transactions,case_summary,account_profiles - Output:
detected_crime_types,crime_type_confidence,risk_indicators - Method:
- Rule-based risk indicator extraction (threshold analysis, velocity checks, geographic flags)
- LLM classification with structured output (Groq Llama 3.3 70B)
- Merge rule-based and LLM outputs with weighted confidence
- Confidence: Rule-based indicators get base confidence (0.3-0.7), LLM adds delta. Final = weighted average.
- File:
src/agents/typology/structuring.py - Input:
enriched_transactions,case_summary - Output:
TypologyResultdict appended totypology_results - Detection logic:
- Transactions $8,000-$9,999 (below $10,000 CTR threshold)
- Fan-out pattern: single account → multiple recipients within short timeframe
- Multiple deposits across different branches/accounts within 24-48 hours
- Round-number or systematically varied amounts
- Features:
transaction_amount_proximity_to_threshold,fan_out_degree,temporal_clustering_score,amount_variance_pattern
- File:
src/agents/typology/layering.py - Input:
enriched_transactions,case_summary - Output:
TypologyResultdict - Detection logic:
- Funds pass through 3+ accounts within 24-72 hours
- Gather-scatter or scatter-gather patterns
- Multi-hop chains with minimal dwell time per account
- Cross-bank transfers with currency conversion
- Features:
hop_count,avg_dwell_time_hours,involves_currency_conversion,cross_bank_count
- File:
src/agents/typology/round_tripping.py - Input:
enriched_transactions,case_summary - Output:
TypologyResultdict - Detection logic:
- Funds return to originating account within a timeframe
- Simple cycles (A→B→A) and complex cycles (A→B→C→D→A)
- Amount conservation with small leakage (fees)
- Shell company indicators (bipartite transaction patterns)
- Features:
cycle_detected,cycle_length,amount_conservation_ratio,cycle_timespan_hours
- File:
src/agents/typology/sanctions.py - Input:
enriched_transactions,case_summary - Output:
TypologyResultdict - Detection logic:
- Transactions involving FATF grey/black list jurisdictions
- Counterparties matching mock sanctions lists
- Unusual cross-border patterns for account type
- Multiple jurisdictions in rapid succession
- Features:
high_risk_jurisdiction_count,sanctions_hit,cross_border_frequency,jurisdiction_diversity_score
- File:
src/agents/typology/nodes.py - Purpose: Collect parallel typology results and update
current_phasetoanalysis - Method: Passthrough — results are automatically merged by the
_extend_listreducer
- File:
src/agents/intelligence/agent.py - Input:
enriched_transactions,account_profiles - Output:
external_intel(list of mock intelligence results) - Mock MCP endpoints:
/sanctions_check— simulated OFAC/UN sanctions screening/adverse_media— simulated negative news hits/pep_check— simulated PEP screening/jurisdiction_risk— FATF risk ratings
- All results include
"source": "MOCK_MCP"for transparency
- File:
src/agents/narrative/agent.py - Input: All detection results, external intel, case summary, memory context
- Output:
sar_narrative_draft,narrative_confidence,narrative_chain_of_thought,narrative_version - Method: DSPy TypedChainOfThought with FinCEN 5W1H template
- LLM: Groq Llama 3.3 70B (temperature=0.3)
- Sections: Summary, WHO, WHAT, WHEN, WHERE, WHY, HOW, Recommended Action, Appendix
- Confidence: Per-section confidence scores + overall weighted average
- File:
src/agents/validation/agent.py - Input:
sar_narrative_draft,enriched_transactions,case_summary - Output:
compliance_checks,compliance_score,compliance_passed - Rule-based checks:
- All 5W1H sections present with sufficient detail
- Dollar amounts match source transaction data (anti-hallucination)
- No PII leakage in narrative
- FinCEN required keywords present
- Objective tone (no speculation without qualifiers)
- Date format consistency
- LLM judge: Separate Groq call scoring holistic quality (1-5 scale)
- Pass threshold:
compliance_score >= 0.80
- File:
src/agents/feedback/agent.py - Purpose: LangGraph interrupt point where the pipeline pauses for investigator input
- Input: Human decision (approve/edit/reject) via API
- Output:
sar_approved,human_feedback,human_edits
- File:
src/agents/feedback/agent.py - Input:
human_feedback,compliance_checks, revision history - Output: Structured revision instructions, incremented
current_revision - Max revisions: 3 (configurable via
max_revisionsstate field)
- File:
src/agents/supervisor.py - Purpose: Terminal node for false positive cases
- Trigger: Max typology confidence < 25% after all 4 agents run
- Output: Sets
investigation_outcome = "no_detection", logs audit trace, exits pipeline
- File:
src/agents/graph.py - Purpose: Thin node before Send API parallel fan-out to 4 typology agents
Typology agents execute in parallel via LangGraph Send API:
def dispatch_typology_agents(state) -> list[Send]:
return [
Send("typology_structuring", state),
Send("typology_layering", state),
Send("typology_round_tripping", state),
Send("typology_sanctions", state),
]The typology_results field uses an _extend_list reducer to merge parallel writes without conflict.
Compliance fails (score < 0.80)
→ Supervisor routes to feedback_revision
→ Feedback agent creates structured revision instructions
→ Supervisor routes to narrative_generation
→ Narrative agent re-generates with feedback context
→ Compliance re-validates
→ Loop up to max_revisions (default 3)
→ After max revisions, force to human_review