Building a Supply Chain Monitoring Agent with Solon TeamAgent
Our warehouse manager was spending 3 hours every morning checking inventory levels across 4 warehouses. By the time he finished the check, some items were already out of stock.
We needed something that could monitor inventory, detect anomalies, and coordinate replenishment automatically. The challenge was that this involved multiple different systems working together: inventory DB, supplier API, order forecasting, and exception handling.
Solon's TeamAgent turned out to be a perfect fit for this kind of multi-system coordination.
Why TeamAgent Instead of ReActAgent?
ReActAgent is a single AI agent that thinks and acts sequentially. For our supply chain scenario, we had several distinct responsibilities:
| Agent | Responsibility | Tools |
|---|---|---|
| Inventory Monitor | Periodically check stock levels |
get_stock_level(), get_lead_time()
|
| Order Forecaster | Predict demand based on history |
get_sales_trend(), get_seasonal_factor()
|
| Replenishment Coordinator | Generate purchase orders |
calc_reorder_qty(), create_po()
|
| Exception Handler | Escalate anomalies |
check_supplier_status(), notify_manager()
|
Each of these is a self-contained domain. Having one giant ReActAgent handle all of them would be messy. TeamAgent lets us define specialized sub-agents that work together through a collaboration protocol.
What Is TeamAgent?
From the official docs, TeamAgent is Solon's multi-agent coordination framework. Think of it as:
A team leader who assigns tasks to specialists and aggregates their results.
Each sub-agent (called a "member") is itself a ReActAgent with its own tools and identity. The TeamAgent decides which member should handle each part of a complex request.
Implementing the Supply Chain Monitor
1. Define Domain Tools
Each sub-agent needs its own tools. Here's the inventory monitor's tool:
public class InventoryTools extends AbsToolProvider {
@ToolMapping(description = "Get current stock level for a specific SKU at a warehouse")
public String get_stock_level(
@Param(description = "Warehouse code, e.g. WH-SH, WH-BJ") String warehouse,
@Param(description = "SKU identifier") String sku) {
// In production, this queries the actual inventory DB
return "{\"warehouse\":\"" + warehouse + "\", \"sku\":\"" + sku
+ "\", \"qty\": 85, \"minStock\": 100, \"maxStock\": 500}";
}
@ToolMapping(description = "Get replenishment lead time for a SKU")
public String get_lead_time(@Param(description = "SKU identifier") String sku) {
return "{\"sku\":\"" + sku + "\", \"leadTimeDays\": 7}";
}
}
public class ReplenishmentTools extends AbsToolProvider {
@ToolMapping(description = "Calculate reorder quantity based on current stock and forecast")
public String calc_reorder_qty(
@Param(description = "Current stock") int currentStock,
@Param(description = "Min stock threshold") int minStock,
@Param(description = "Daily forecast demand") int dailyDemand,
@Param(description = "Lead time in days") int leadTimeDays) {
int reorderQty = (dailyDemand * (leadTimeDays + 3)) - currentStock;
return "{\"reorderQty\": " + Math.max(reorderQty, 0) + "}";
}
@ToolMapping(description = "Create a purchase order in the ERP system")
public String create_po(
@Param(description = "SKU") String sku,
@Param(description = "Quantity to order") int qty,
@Param(description = "Supplier code") String supplier) {
return "{\"poNumber\": \"PO-2026-07-\" + System.currentTimeMillis()
+ \", \"sku\": \"" + sku + "\", \"qty\": " + qty
+ ", \"supplier\": \"" + supplier + "\", \"status\": \"submitted\"}";
}
}
2. Build Sub-Agents
Each sub-agent is a standalone ReActAgent with its own role description and tools:
// Inventory Monitor Agent
ReActAgent inventoryAgent = ReActAgent.of(chatModel)
.role("You are an inventory monitoring specialist. " +
"Check stock levels and identify items below minimum threshold.")
.defaultToolAdd(new InventoryTools())
.build();
// Replenishment Coordinator Agent
ReActAgent replenishAgent = ReActAgent.of(chatModel)
.role("You are a replenishment specialist. " +
"Calculate optimal order quantities and create purchase orders.")
.defaultToolAdd(new ReplenishmentTools())
.build();
// Exception Handler Agent
ReActAgent exceptionAgent = ReActAgent.of(chatModel)
.role("You are an exception handler. " +
"Escalate critical supply chain issues to management.")
.defaultToolAdd(new ExceptionTools())
.build();
3. Assemble the Team
// Build TeamAgent with the three sub-agents
TeamAgent supplyChainTeam = TeamAgent.of(chatModel)
.addMember(inventoryAgent)
.addMember(replenishAgent)
.addMember(exceptionAgent)
.protocol(TeamProtocol.SEQUENTIAL) // Execute members one by one
.build();
// Execute a monitoring round
AgentSession session = InMemoryAgentSession.of("supply_chain_round_001");
String task = "Run daily inventory check for warehouse WH-SH. " +
"Check SKU 'HDD-2TB', current stock is 85, min threshold is 100. " +
"If below threshold, calculate reorder qty and create PO.";
String result = supplyChainTeam.prompt(task)
.session(session)
.call()
.getContent();
4. The Execution Flow
When we run this, TeamAgent orchestrates the work:
- TeamAgent receives the task and assigns it to the Inventory Monitor
-
Inventory Monitor calls
get_stock_level()→ finds stock (85) below threshold (100) - TeamAgent passes "below threshold, need replenishment" to Replenishment Coordinator
-
Replenishment Coordinator calls
calc_reorder_qty()andcreate_po()→ PO created - TeamAgent compiles the final report with all actions taken
Parallel Monitoring with TeamProtocol.NONE
For checking multiple warehouses simultaneously, we can use the NONE protocol (free mode) which lets all members work in parallel:
TeamAgent parallelTeam = TeamAgent.of(chatModel)
.addMember(inventoryAgent)
.protocol(TeamProtocol.NONE) // All members work independently
.build();
String result = parallelTeam.prompt(
"Check stock levels for all 4 warehouses: WH-SH, WH-BJ, WH-GZ, WH-CD")
.call()
.getContent();
Each inventory agent instance checks one warehouse in parallel, cutting total time by ~75%.
Real Deployment Notes
The official TeamAgent docs mention several config options we found useful:
# application.yml
solon.ai.team:
max_turns: 15 # Max total reasoning cycles
timeout: 60000 # 60s timeout for team execution
protocol: sequential # sequential or none
We run this as a scheduled job every 2 hours:
@Scheduled(cron = "0 0 */2 * * ?")
public void scheduledInventoryCheck() {
String result = supplyChainTeam.prompt(
"Run routine inventory check. Report any items below threshold " +
"and auto-create replenishment POs where possible.")
.call()
.getContent();
// Log results and alert on exceptions
log.info("Supply chain check complete: {}", result);
}
Results
After deploying this setup:
- Inventory checks that previously took 3 hours of manual work now run in under 30 seconds
- Replenishment POs are auto-generated when stock dips below threshold
- Exception handler only escalates truly unusual cases (supplier delays, system errors)
- The team can focus on strategic work instead of routine monitoring
All code based on Solon v4.0.3. Real API references: article/1283 (TeamAgent), article/1296 (TeamAgent config), article/1299 (NONE protocol).
Top comments (0)