Step 04 - Supervisor Pattern for Dynamic Orchestration
Supervisor Pattern for Dynamic Orchestration
In the previous step, you created nested workflows that combined sequential, parallel, and conditional patterns to build sophisticated multi-level orchestration.
However, those workflows used fixed, deterministic routing - the conditions were hardcoded and predictable. What if you need dynamic, context-aware orchestration where an AI agent decides which sub-agents to invoke based on the current situation?
In this step, you’ll learn about the Supervisor Pattern - a powerful approach where a supervisor agent autonomously orchestrates other agents based on runtime context and business conditions.
New Requirement from Miles of Smiles Management: Intelligent Disposition Decisions
The Miles of Smiles management team has identified a new challenge: they need to make intelligent decisions about vehicle disposition when cars return with severe damage.
The system needs to:
- Detect severe damage that might make a car uneconomical to repair
- Estimate vehicle value to inform disposition decisions
- Decide disposition strategy (SCRAP, SELL, DONATE, or KEEP) based on:
- Car value
- Age of the vehicle
- Severity of damage
- Repair cost estimates
- Let an AI supervisor orchestrate the entire decision-making process
What You’ll Learn
In this step, you will:
- Understand the Supervisor Pattern and when to use it
- Implement a supervisor agent using
@SupervisorAgentannotation - Create specialized agents for feedback analysis and action execution
- Build a PricingAgent to estimate vehicle market values
- Create a DispositionAgent to make SCRAP/SELL/DONATE/KEEP decisions
- See how supervisors provide autonomous, adaptive orchestration
Understanding the Supervisor Pattern
What is a Supervisor Agent?
A supervisor agent is an AI agent that:
- Coordinates other agents (called sub-agents)
- Makes runtime decisions about which agents to invoke
- Adapts to context using business rules and current conditions
- Provides autonomous orchestration without hardcoded logic
Supervisor vs. Conditional Workflows
| Aspect | Conditional Workflow | Supervisor Agent |
|---|---|---|
| Decision Logic | Hardcoded conditions | AI-driven decisions |
| Flexibility | Fixed rules | Adapts to context |
| Complexity | Simple boolean checks | Complex reasoning |
| Maintenance | Update code for changes | Update prompts/context |
When to Use Supervisors
Use supervisor agents when you need:
- Context-aware routing: Decisions based on multiple factors
- Business rule flexibility: Easy to adjust without code changes
- Complex orchestration: Multiple agents with interdependencies
- Adaptive behavior: System that learns and improves
What is Being Added?
We’re going to enhance our car management system with:
- DispositionFeedbackAgent: Detects severe damage requiring disposition evaluation
- PricingAgent: Estimates vehicle market value
- DispositionAgent: Decides SCRAP/SELL/DONATE/KEEP based on value and condition
- FleetSupervisorAgent: Orchestrates feedback and action agents autonomously
- Updated workflow: Two-phase processing (feedback → supervisor → actions)
The New Architecture
graph TB
Start([Car Return]) --> A[CarProcessingWorkflow<br/>Sequential]
A --> B[Step 1: FeedbackWorkflow<br/>Parallel Analysis]
B --> B1[CleaningFeedbackAgent]
B --> B2[MaintenanceFeedbackAgent]
B --> B3[DispositionFeedbackAgent<br/>NEW]
B1 --> BEnd[All feedback complete]
B2 --> BEnd
B3 --> BEnd
BEnd --> C[Step 2: FleetSupervisorAgent<br/>Autonomous Orchestration]
C --> C1{AI Supervisor<br/>Analyzes Feedback}
C1 -->|Severe Damage| C2[PricingAgent<br/>Estimate Value]
C2 --> C3[DispositionAgent<br/>SCRAP/SELL/DONATE/KEEP]
C1 -->|Repairable| C4[MaintenanceAgent]
C1 -->|Minor Issues| C5[CleaningAgent]
C3 --> CEnd[Supervisor Decision]
C4 --> CEnd
C5 --> CEnd
CEnd --> D[Step 3: CarConditionFeedbackAgent<br/>Final Summary]
D --> End([Updated Car with Status])
style A fill:#90EE90
style B fill:#87CEEB
style C fill:#FFB6C1
style D fill:#90EE90
style C1 fill:#FFA07A
style B3 fill:#FFD700
style C2 fill:#FFD700
style C3 fill:#FFD700
style Start fill:#E8E8E8
style End fill:#E8E8E8
The Key Innovation:
The FleetSupervisorAgent receives feedback from three parallel agents and then autonomously decides:
- If severe damage detected → invoke PricingAgent → DispositionAgent
- If repairable damage → invoke MaintenanceAgent
- If only cleaning needed → invoke CleaningAgent
Key Implementation Details
DispositionFeedbackAgent (NEW)
Detects severe damage that requires disposition evaluation:
package com.carmanagement.agentic.agents;
import dev.langchain4j.agentic.Agent;
import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.UserMessage;
/**
* Agent that analyzes feedback to determine if a car should be considered for disposition.
*/
public interface DispositionFeedbackAgent {
@SystemMessage("""
You are a disposition analyzer for a car rental company. Your job is to determine if a car should be considered for disposition (removal from fleet).
Analyze the feedback for SEVERE issues that would make the car uneconomical to keep:
- Major accidents: "wrecked", "totaled", "destroyed", "crashed", "collision"
- Severe damage: "frame damage", "structural damage", "major damage"
- Safety concerns: "unsafe", "not drivable", "inoperable", "dangerous"
- Catastrophic mechanical failure: "engine blown", "transmission failed", "major mechanical failure"
If you detect ANY of these severe issues, respond with:
"DISPOSITION_REQUIRED: [brief description of the severe issue]"
If the car has only minor or moderate issues that can be repaired, respond with:
"DISPOSITION_NOT_REQUIRED"
Keep your response concise.
""")
@UserMessage("""
Car Information:
Make: {carMake}
Model: {carModel}
Year: {carYear}
Previous Condition: {carCondition}
Feedback:
Rental Feedback: {rentalFeedback}
Cleaning Feedback: {cleaningFeedback}
Maintenance Feedback: {maintenanceFeedback}
""")
@Agent(description = "Disposition analyzer. Determines if a car has severe damage requiring disposition evaluation.",
outputKey = "dispositionRequest")
String analyzeForDisposition(
String carMake,
String carModel,
Integer carYear,
Long carNumber,
String carCondition,
String rentalFeedback,
String cleaningFeedback,
String maintenanceFeedback);
}
Key Points:
- Analyzes feedback for severe damage keywords (“wrecked”, “totaled”, “crashed”)
- Outputs “DISPOSITION_REQUIRED” or “DISPOSITION_NOT_REQUIRED”
- Runs in parallel with other feedback agents
- Provides early detection of cars that need disposition evaluation
PricingAgent
Estimates vehicle market value for disposition decisions:
package com.carmanagement.agentic.agents;
import dev.langchain4j.agentic.Agent;
import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.UserMessage;
/**
* Agent that estimates the market value of a vehicle.
* Used by the supervisor to make disposition decisions.
*/
public interface PricingAgent {
@SystemMessage("""
You are a vehicle pricing specialist with expertise in market valuations.
Use these pricing guidelines:
Brand Base Values (2024 models):
- Luxury brands (Mercedes, BMW, Audi, Lexus): $45,000-$65,000
- Premium brands (Volvo, Acura, Infiniti): $35,000-$50,000
- Mainstream brands (Toyota, Honda, Ford, Chevrolet): $25,000-$40,000
- Economy brands (Kia, Hyundai, Nissan): $20,000-$35,000
Depreciation:
- Apply 15% per year for the first 3 years
- Apply 10% per year for years 4-6
- Apply 5% per year for years 7+
Condition Adjustments:
- Excellent: +10% to base value
- Good: No adjustment
- Fair: -15% from base value
- Poor: -30% from base value
Provide:
1. Estimated market value (single dollar amount)
2. Brief justification (2-3 sentences)
Format your response as:
Estimated Value: $XX,XXX
Justification: [Your reasoning]
""")
@UserMessage("""
Estimate the current market value of this vehicle:
- Make: {carMake}
- Model: {carModel}
- Year: {carYear}
- Condition: {carCondition}
""")
@Agent(
outputKey = "carValue",
description = "Pricing specialist that estimates vehicle market value based on make, model, year, and condition"
)
String estimateValue(String carMake, String carModel, Integer carYear, String carCondition);
}
Key Points:
- Uses detailed pricing guidelines (brand base values, depreciation, condition adjustments)
- Considers make, model, year, and condition
- Returns structured output with value and justification
- Invoked by supervisor when disposition evaluation is needed
DispositionAgent (NEW)
Makes intelligent disposition decisions:
package com.carmanagement.agentic.agents;
import dev.langchain4j.agentic.Agent;
import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.UserMessage;
/**
* Agent that determines how to dispose of a car based on value, condition, and damage.
* This is a LOCAL agent - in step-05 it will be converted to a remote A2A agent.
*/
public interface DispositionAgent {
@SystemMessage("""
You are a car disposition specialist for a car rental company.
Your job is to determine the best disposition action based on the car's value, condition, age, and damage.
Disposition Options:
- SCRAP: Car is beyond economical repair or has severe safety concerns
- SELL: Car has value but is aging out of the fleet or has moderate damage
- DONATE: Car has minimal value but could serve a charitable purpose
- KEEP: Car is worth keeping in the fleet
Decision Criteria:
- If estimated repair cost > 50% of car value: Consider SCRAP or SELL
- If car is over 5 years old with significant damage: SCRAP
- If car is 3-5 years old in fair condition: SELL
- If car has low value (<$5,000) but functional: DONATE
- If car is valuable and damage is minor: KEEP
Provide your recommendation with a clear explanation of the reasoning.
""")
@UserMessage("""
Determine the disposition for this vehicle:
- Make: {carMake}
- Model: {carModel}
- Year: {carYear}
- Car Number: {carNumber}
- Current Condition: {carCondition}
- Estimated Value: {carValue}
- Damage/Feedback: {rentalFeedback}
Provide your disposition recommendation (SCRAP/SELL/DONATE/KEEP) and explanation.
""")
@Agent(outputKey = "dispositionAction", description = "Car disposition specialist. Determines how to dispose of a car based on value and condition.")
String processDisposition(
String carMake,
String carModel,
Integer carYear,
Long carNumber,
String carCondition,
String carValue,
String rentalFeedback);
}
Key Points:
- Receives car value from PricingAgent
- Decides: SCRAP, SELL, DONATE, or KEEP
- Considers repair cost vs. value, age, and damage severity
- Provides clear reasoning for the decision
FleetSupervisorAgent
Orchestrates the entire processing workflow:
package com.carmanagement.agentic.agents;
import dev.langchain4j.agentic.declarative.SupervisorAgent;
import dev.langchain4j.service.SystemMessage;
/**
* Supervisor agent that orchestrates the entire car processing workflow.
* Coordinates feedback analysis agents and action agents based on car condition.
*/
public interface FleetSupervisorAgent {
@SystemMessage("""
You are a fleet supervisor for a car rental company. You coordinate action agents based on feedback analysis.
The feedback has already been analyzed and you have these inputs:
- cleaningRequest: What cleaning is needed (or "CLEANING_NOT_REQUIRED")
- maintenanceRequest: What maintenance is needed (or "MAINTENANCE_NOT_REQUIRED")
- dispositionRequest: Whether severe damage requires disposition (or "DISPOSITION_NOT_REQUIRED")
Your job is to invoke the appropriate ACTION agents:
DECISION LOGIC:
1. If dispositionRequest contains "DISPOSITION_REQUIRED":
- ALWAYS invoke PricingAgent first to estimate car value
- Then invoke DispositionAgent to decide: SCRAP/SELL/DONATE/KEEP
- If DispositionAgent says KEEP, then invoke MaintenanceAgent or CleaningAgent as needed
2. If dispositionRequest is "DISPOSITION_NOT_REQUIRED":
- If maintenanceRequest is NOT "MAINTENANCE_NOT_REQUIRED": Invoke MaintenanceAgent
- If cleaningRequest is NOT "CLEANING_NOT_REQUIRED": Invoke CleaningAgent
- You can invoke both if both are needed
Explain your decision-making clearly, including which agents you invoked and why.
""")
@SupervisorAgent(
outputKey = "supervisorDecision",
subAgents = {
PricingAgent.class,
DispositionAgent.class,
MaintenanceAgent.class,
CleaningAgent.class
}
)
String superviseCarProcessing(
String carMake,
String carModel,
Integer carYear,
Long carNumber,
String carCondition,
String rentalFeedback,
String cleaningFeedback,
String maintenanceFeedback,
String cleaningRequest,
String maintenanceRequest,
String dispositionRequest
);
}
Key Points:
@SupervisorAgentannotation enables autonomous orchestrationsubAgentslists all available action agents (not feedback agents)- Receives feedback results as input parameters
- Makes intelligent routing decisions based on feedback analysis
- Two-phase approach: supervisor coordinates actions AFTER feedback is complete
Updated FeedbackWorkflow
Now includes disposition feedback:
package com.carmanagement.agentic.workflow;
import com.carmanagement.agentic.agents.CleaningFeedbackAgent;
import com.carmanagement.agentic.agents.MaintenanceFeedbackAgent;
import com.carmanagement.agentic.agents.DispositionFeedbackAgent;
import dev.langchain4j.agentic.declarative.ParallelAgent;
/**
* Workflow for processing car feedback in parallel.
* Analyzes feedback for cleaning, maintenance, and disposition needs.
*/
public interface FeedbackWorkflow {
/**
* Runs multiple feedback agents in parallel to analyze different aspects of car feedback.
*/
@ParallelAgent(outputKey = "feedbackResult",
subAgents = { CleaningFeedbackAgent.class, MaintenanceFeedbackAgent.class, DispositionFeedbackAgent.class })
String analyzeFeedback(
String carMake,
String carModel,
Integer carYear,
Long carNumber,
String carCondition,
String rentalFeedback,
String cleaningFeedback,
String maintenanceFeedback);
}
Updated CarProcessingWorkflow
Sequential workflow with supervisor:
package com.carmanagement.agentic.workflow;
import com.carmanagement.agentic.agents.CarConditionFeedbackAgent;
import com.carmanagement.agentic.agents.FleetSupervisorAgent;
import com.carmanagement.model.CarConditions;
import com.carmanagement.model.CarAssignment;
import dev.langchain4j.agentic.declarative.Output;
import dev.langchain4j.agentic.declarative.SequenceAgent;
/**
* Workflow for processing car returns using a supervisor agent for complete orchestration.
* The supervisor coordinates both feedback analysis and action agents.
*/
public interface CarProcessingWorkflow {
/**
* Processes a car return by first analyzing feedback, then using supervisor to coordinate actions.
* FeedbackWorkflow produces cleaningRequest, maintenanceRequest, and dispositionRequest.
* FleetSupervisorAgent then uses these to coordinate action agents.
*/
@SequenceAgent(outputKey = "carProcessingAgentResult",
subAgents = { FeedbackWorkflow.class, FleetSupervisorAgent.class, CarConditionFeedbackAgent.class })
CarConditions processCarReturn(
String carMake,
String carModel,
Integer carYear,
Long carNumber,
String carCondition,
String rentalFeedback,
String cleaningFeedback,
String maintenanceFeedback);
@Output
static CarConditions output(String carCondition, String dispositionRequest, String maintenanceRequest,
String cleaningRequest, String supervisorDecision) {
CarAssignment carAssignment;
// Check disposition first (highest priority)
// DispositionFeedbackAgent outputs "DISPOSITION_REQUIRED" if severe damage detected
if (dispositionRequest != null && dispositionRequest.toUpperCase().contains("DISPOSITION_REQUIRED")) {
carAssignment = CarAssignment.DISPOSITION;
}
// Also check supervisor's decision for disposition keywords
else if (supervisorDecision != null &&
(supervisorDecision.toUpperCase().contains("SCRAP") ||
supervisorDecision.toUpperCase().contains("SELL") ||
supervisorDecision.toUpperCase().contains("DONATE"))) {
carAssignment = CarAssignment.DISPOSITION;
}
// Check maintenance (high priority)
else if (maintenanceRequest != null && !maintenanceRequest.toUpperCase().contains("MAINTENANCE_NOT_REQUIRED")) {
carAssignment = CarAssignment.MAINTENANCE;
}
// Check cleaning (medium priority)
else if (cleaningRequest != null && !cleaningRequest.toUpperCase().contains("CLEANING_NOT_REQUIRED")) {
carAssignment = CarAssignment.CLEANING;
}
// No action needed
else {
carAssignment = CarAssignment.NONE;
}
return new CarConditions(carCondition, carAssignment);
}
}
Changes:
- FeedbackWorkflow runs first (produces
dispositionRequest,maintenanceRequest,cleaningRequest) - FleetSupervisorAgent receives feedback and orchestrates actions
- Output logic checks
dispositionRequestfirst for highest priority routing
Try the Supervisor Pattern
Start the Application
- Navigate to the step-04 directory:
Test Disposition Scenarios
Try these scenarios to see how the supervisor pattern autonomously orchestrates agents:
Scenario 1: Severe Damage - Disposition Required
Enter the following text in the feedback field for the Honda Civic:
What happens:
flowchart TD
Start([Input: Car was in serious collision<br/>Front end destroyed, airbags deployed])
Start --> FW[FeedbackWorkflow<br/>Parallel Analysis]
FW --> DFA[DispositionFeedbackAgent]
FW --> MFA[MaintenanceFeedbackAgent]
FW --> CFA[CleaningFeedbackAgent]
DFA --> DR[Detects: DISPOSITION_REQUIRED ✓<br/>Keywords: collision, destroyed]
MFA --> MR[Detects: maintenance issues ✓]
CFA --> CR[Detects: cleaning needed ✓]
DR --> FSA{FleetSupervisorAgent<br/>Autonomous Orchestration}
MR --> FSA
CR --> FSA
FSA -->|Disposition has highest priority| PA[Invoke PricingAgent]
PA --> PV[Estimate: $8,500<br/>2020 Honda Civic with severe damage]
PV --> DA[Invoke DispositionAgent]
DA --> DD[Decision: SCRAP<br/>Repair cost > 50% of value]
DD --> Result([Result: PENDING_DISPOSITION<br/>Condition: SCRAP - severe damage])
style FW fill:#FAE5D3
style FSA fill:#D5F5E3
style PA fill:#F9E79F
style DA fill:#F9E79F
style Result fill:#D2B4DE
Expected Result:
- Status: PENDING_DISPOSITION
- Condition includes disposition decision (e.g., “SCRAP - severe damage, repair cost exceeds value”)
- PricingAgent estimated the car’s value
- DispositionAgent made a SCRAP decision based on economics
Scenario 2: Total Loss
Enter the following text in the Toyota Camry feedback field:
What happens:
flowchart TD
Start([Input: Car is totaled<br/>completely inoperable])
Start --> FW[FeedbackWorkflow<br/>Parallel Analysis]
FW --> DFA[DispositionFeedbackAgent]
FW --> MFA[MaintenanceFeedbackAgent]
FW --> CFA[CleaningFeedbackAgent]
DFA --> DR[Detects: DISPOSITION_REQUIRED ✓<br/>Keywords: totaled, inoperable]
MFA --> MR[Analysis complete]
CFA --> CR[Analysis complete]
DR --> FSA{FleetSupervisorAgent<br/>Autonomous Orchestration}
MR --> FSA
CR --> FSA
FSA -->|Severe damage detected| PA[Invoke PricingAgent]
PA --> PV[Estimate: $12,000<br/>2019 Toyota Camry, totaled]
PV --> DA[Invoke DispositionAgent]
DA --> DD[Decision: SCRAP or SELL<br/>Beyond economical repair]
DD --> Result([Result: PENDING_DISPOSITION<br/>Condition: SCRAP/SELL - totaled])
style FW fill:#FAE5D3
style FSA fill:#D5F5E3
style PA fill:#F9E79F
style DA fill:#F9E79F
style Result fill:#D2B4DE
Expected Result:
- Status: PENDING_DISPOSITION
- Disposition decision: SCRAP or SELL (beyond economical repair)
- PricingAgent estimated value before total loss
- DispositionAgent determined vehicle is not worth repairing
Scenario 3: Repairable Damage
Enter the following text in the Mercedes Benz feedback field:
What happens:
flowchart TD
Start([Input: Engine making noise<br/>needs inspection])
Start --> FW[FeedbackWorkflow<br/>Parallel Analysis]
FW --> DFA[DispositionFeedbackAgent]
FW --> MFA[MaintenanceFeedbackAgent]
FW --> CFA[CleaningFeedbackAgent]
DFA --> DR[Detects: no severe damage ✗]
MFA --> MR[Detects: maintenance needed ✓]
CFA --> CR[Detects: no cleaning needed ✗]
DR --> FSA{FleetSupervisorAgent<br/>Autonomous Orchestration}
MR --> FSA
CR --> FSA
FSA -->|No disposition, maintenance is priority| MA[Invoke MaintenanceAgent]
MA --> Result([Result: IN_MAINTENANCE<br/>Condition: Engine inspection required])
style FW fill:#FAE5D3
style FSA fill:#D5F5E3
style MA fill:#F9E79F
style Result fill:#D2B4DE
Expected Result:
- Status: IN_MAINTENANCE
- Condition describes the maintenance issue
- Supervisor routed to MaintenanceAgent (not disposition)
Scenario 4: Minor Issues
Enter the following text in the Ford F-150 feedback field:
What happens:
flowchart TD
Start([Input: Car is dirty<br/>needs cleaning])
Start --> FW[FeedbackWorkflow<br/>Parallel Analysis]
FW --> DFA[DispositionFeedbackAgent]
FW --> MFA[MaintenanceFeedbackAgent]
FW --> CFA[CleaningFeedbackAgent]
DFA --> DR[Detects: no severe damage ✗]
MFA --> MR[Detects: no maintenance needed ✗]
CFA --> CR[Detects: cleaning needed ✓]
DR --> FSA{FleetSupervisorAgent<br/>Autonomous Orchestration}
MR --> FSA
CR --> FSA
FSA -->|No disposition or maintenance| CA[Invoke CleaningAgent]
CA --> Result([Result: IN_CLEANING<br/>Condition: Requires thorough cleaning])
style FW fill:#FAE5D3
style FSA fill:#D5F5E3
style CA fill:#F9E79F
style Result fill:#D2B4DE
Expected Result:
- Status: IN_CLEANING
- Condition describes cleaning needs
- Supervisor routed to CleaningAgent only
Observe the Disposition Tab
After processing a car with severe damage, check the Dispositions tab in the Returns section. You’ll see cars that have been marked for disposition with their condition and planned disposition action.

The UI now includes a dedicated tab to track all vehicles pending disposition, making it easy to see which cars need to be scrapped, sold, or donated.
Observe the Supervisor’s Decisions
Watch the console logs to see the two-phase processing:
Phase 1: FeedbackWorkflow executing (parallel)...
├─ CleaningFeedbackAgent analyzing...
├─ MaintenanceFeedbackAgent analyzing...
└─ DispositionFeedbackAgent analyzing...
Phase 2: FleetSupervisorAgent orchestrating...
├─ Received: DISPOSITION_REQUIRED (severe damage detected)
├─ Invoking: PricingAgent (estimating value)...
├─ Invoking: DispositionAgent (making decision)...
└─ Decision: SCRAP - severe damage, repair cost exceeds value
Phase 3: CarConditionFeedbackAgent updating...
└─ Condition: SCRAP - severe damage, low value
Why the Supervisor Pattern Matters
Autonomous Decision-Making
The supervisor uses AI reasoning to make complex decisions:
graph LR
Input[Feedback:<br/>Disposition Required?<br/>Maintenance Needed?<br/>Cleaning Needed?] --> Supervisor[FleetSupervisorAgent<br/>AI Reasoning]
Supervisor --> Decision{Dynamic<br/>Orchestration}
Decision -->|Severe Damage| Disposition[PricingAgent<br/>→ DispositionAgent]
Decision -->|Repairable| Maintenance[MaintenanceAgent]
Decision -->|Minor Issues| Cleaning[CleaningAgent]
Economic Intelligence
The system makes economically sound decisions:
- Car value < $5,000 + major damage → SCRAP
- Repair cost > 50% of value → SELL or SCRAP
- Old car (10+ years) + damage → Disposition evaluation
- Valuable car + minor damage → KEEP and repair
Flexibility Without Code Changes
To adjust behavior, you can:
- Update prompts: Change the supervisor’s decision criteria
- Adjust thresholds: Modify pricing guidelines or disposition rules
- Add context: Provide more information (repair history, customer value)
No code changes required!
Comparing Patterns
Before: Conditional Workflow (Step 03)
@ConditionalAgent(subAgents = {MaintenanceAgent.class, CleaningAgent.class})
String processAction(...);
@ActivationCondition(MaintenanceAgent.class)
static boolean assignToMaintenance(String maintenanceRequest) {
return isRequired(maintenanceRequest); // Simple boolean check
}
Limitations:
- Fixed logic
- Simple conditions
- No disposition handling
- Requires code changes
After: Supervisor Agent (Step 04)
@SupervisorAgent(
subAgents = {
PricingAgent.class,
DispositionAgent.class,
MaintenanceAgent.class,
CleaningAgent.class
}
)
String superviseCarProcessing(
String carMake, String carModel, Integer carYear,
String carCondition, String rentalFeedback,
String cleaningRequest, String maintenanceRequest,
String dispositionRequest // NEW: Disposition feedback
);
Advantages:
- AI-driven decisions
- Context-aware reasoning
- Handles complex disposition scenarios
- Easy to adjust via prompts
- Economic intelligence built-in
Experiment Further
1. Add More Disposition Criteria
Enhance the DispositionAgent to consider:
- Repair history (frequent repairs → disposition)
- Market demand for specific models
- Seasonal factors (convertibles in winter)
- Fleet composition (too many of same model)
2. Implement Multi-Tier Pricing
Create different pricing strategies:
- Wholesale value (for SCRAP decisions)
- Retail value (for SELL decisions)
- Donation value (for tax purposes)
3. Add Disposition Workflow
Create a separate workflow for cars marked PENDING_DISPOSITION:
- Get multiple price quotes
- Check auction values
- Evaluate donation options
- Final disposition decision
4. Test Edge Cases
What happens when:
- Luxury car with severe damage?
- Old car in excellent condition?
- Multiple disposition-worthy issues?
- Repair cost estimate unavailable?
Troubleshooting
Supervisor not invoking DispositionAgent
- Check that DispositionFeedbackAgent is detecting severe damage keywords
- Verify “DISPOSITION_REQUIRED” is in the output
- Review supervisor’s system message for disposition routing logic
- Add logging to see feedback values
Cars not getting PENDING_DISPOSITION status
- Check the output logic in CarProcessingWorkflow
- Verify
dispositionRequestparameter is being passed - Ensure
isDisposition()method checks for correct keywords - Check CarManagementService status mapping
PricingAgent returning unexpected values
- Review the pricing guidelines in the
@SystemMessage - Check that car information (make, model, year) is passed correctly
- Verify the LLM is following the output format
- Test with different car makes/models/years
What’s Next?
You’ve implemented the Supervisor Pattern for autonomous, context-aware orchestration with intelligent disposition decisions!
The supervisor agent can now:
- Detect severe damage requiring disposition
- Estimate vehicle value
- Make economically sound SCRAP/SELL/DONATE/KEEP decisions
- Route to appropriate action agents based on feedback
In Step 05, you’ll learn about Agent-to-Agent (A2A) communication — converting the local DispositionAgent you just built into a remote service that runs in a separate system, demonstrating how to distribute agent workloads across multiple applications!