Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 137 additions & 0 deletions examples/loan_covenant_monitoring/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
# Loan Covenant Monitoring Agent

A multi-agent compliance monitoring system built with the **Upsonic AI Agent Framework**. This example demonstrates how to use `Team` in coordinate mode with specialized `Agent` instances and custom financial calculation tools to automate end-to-end loan covenant compliance analysis.

## Features

- 🏦 **Automated Covenant Extraction**: Parses loan agreements to identify all financial covenant definitions, thresholds, and constraint types
- 📊 **Financial Ratio Calculation**: Uses six custom calculation tools to compute leverage, interest coverage, current ratio, DSCR, and tangible net worth
- ⚠️ **Compliance Assessment**: Evaluates each covenant as compliant, near-breach, or breached with headroom percentages
- 🛡️ **Risk Scoring**: Produces an overall risk score (0-100) with actionable remediation recommendations
- 🏗️ **Modular Design**: Clean separation of concerns with specialized agents, schemas, tools, and team configuration
- 🧠 **Structured Output**: Returns a comprehensive `CovenantMonitoringReport` Pydantic model with full audit trail

## Prerequisites

- Python 3.10+
- Anthropic API key
- OpenAI API key

## Installation

1. **Navigate to this directory**:
```bash
cd examples/loan_covenant_monitoring
```

2. **Install dependencies**:
```bash
# Install all dependencies (API)
upsonic install

# Or install specific sections:
upsonic install api # API dependencies only (default)
upsonic install development # Development dependencies only
```

3. **Set up environment variables**:
```bash
export ANTHROPIC_API_KEY="your-api-key"
export OPENAI_API_KEY="your-api-key"
```

## Usage

### Run the API Server

To run the agent as a FastAPI server:

```bash
upsonic run
```

The API will be available at `http://localhost:8000` with automatic OpenAPI documentation at `http://localhost:8000/docs`.

OR

You can run the agent directly:

```bash
uv run main.py
```

**Example API Call:**
```bash
curl -X POST http://localhost:8000/call \
-H "Content-Type: application/json" \
-d '{
"inputs": {
"company_name": "GlobalTech Manufacturing Inc.",
"reporting_period": "Q4 2025",
"loan_agreement_path": "data/loan_agreement.txt",
"financial_data_path": "data/financial_data.json"
}
}'
```

## Project Structure

```
loan_covenant_monitoring/
├── main.py # Entry point with async main() function
├── team.py # Team assembly (coordinate mode + leader)
├── agents.py # 3 specialist agent factory functions
├── schemas.py # Pydantic output schemas
├── tools.py # Custom financial calculation tools
├── task_builder.py # Task description builder
├── upsonic_configs.json # Upsonic configuration and dependencies
├── data/
│ ├── loan_agreement.txt # Synthetic loan agreement (5 covenants)
│ └── financial_data.json # Synthetic Q4 2025 financials
└── README.md # This file
```

## How It Works

1. **Team Assembly**: A `Team` in coordinate mode is created with a leader agent that orchestrates three specialist agents: Covenant Extractor, Financial Calculator, and Risk Assessor.

2. **Covenant Extraction**: The Covenant Extractor agent parses the loan agreement document to identify every financial covenant, its threshold, formula, constraint type, and testing frequency.

3. **Financial Calculation**: The Financial Calculator agent uses custom tools (`calculate_leverage_ratio`, `calculate_interest_coverage_ratio`, etc.) to compute all required ratios from raw financial data.

4. **Compliance Evaluation**: The Risk Assessor agent uses the `evaluate_covenant_compliance` tool to determine each covenant's status (compliant, near-breach, or breached) and computes an overall risk score.

5. **Structured Output**: The final response is enforced to match the `CovenantMonitoringReport` Pydantic model, ensuring consistent and machine-readable output with full audit trail.

## Example Queries

- Monitor Q4 2025 covenant compliance for GlobalTech Manufacturing Inc.
- Evaluate leverage ratio trends approaching covenant limits
- Assess debt service capacity under current cash flow conditions
- Identify breached covenants and recommend remediation strategies

## Input Parameters

- `company_name` (required): Name of the borrower company (e.g., "GlobalTech Manufacturing Inc.")
- `reporting_period` (required): Period being monitored (e.g., "Q4 2025")
- `loan_agreement_path` (required): Path to the loan agreement text file
- `financial_data_path` (required): Path to the financial data JSON file
- `focus_areas` (optional): List of priority focus areas for the analysis
- `enable_memory` (optional): Whether to enable in-memory session persistence (default: true)
- `model` (optional): Model identifier (default: "anthropic/claude-sonnet-4-5")

## Output

Returns a dictionary containing:
- `company_name`: The borrower company name
- `reporting_period`: The period that was monitored
- `report`: Full `CovenantMonitoringReport` object containing:
- `covenants_extracted`: All covenant definitions from the agreement
- `calculated_ratios`: Computed ratios with audit trail (formula, components)
- `compliance_results`: Per-covenant status with headroom percentages
- `risk_assessment`: Overall score (0-100), risk level, key concerns, and recommended actions
- `executive_summary`: Narrative summary of findings
- `next_steps`: Actionable remediation steps
- `monitoring_completed`: Whether the process completed successfully

The report is returned as a JSON-serializable dictionary with all findings structured according to the `CovenantMonitoringReport` schema.
162 changes: 162 additions & 0 deletions examples/loan_covenant_monitoring/agents.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
"""
Specialized agent creation functions for covenant monitoring.

Each function creates an Agent with a specific domain expertise:
- Covenant extraction from legal documents
- Financial ratio calculation using custom tools
- Compliance assessment and risk evaluation
"""

from __future__ import annotations

from typing import List, Callable

from upsonic import Agent

try:
from .tools import (
calculate_leverage_ratio,
calculate_interest_coverage_ratio,
calculate_current_ratio,
calculate_debt_service_coverage_ratio,
calculate_tangible_net_worth,
evaluate_covenant_compliance,
)
except ImportError:
from tools import (
calculate_leverage_ratio,
calculate_interest_coverage_ratio,
calculate_current_ratio,
calculate_debt_service_coverage_ratio,
calculate_tangible_net_worth,
evaluate_covenant_compliance,
)


def create_covenant_extractor_agent(model: str = "openai/gpt-4o-mini") -> Agent:
"""Create a specialist agent for extracting covenant definitions from loan agreements.

Args:
model: Model identifier for the agent.

Returns:
Configured Agent for covenant extraction.
"""
return Agent(
model=model,
name="Covenant Extractor",
role="Legal Document Analyst specializing in commercial loan agreements",
goal=(
"Extract and structure every financial covenant definition from the loan "
"agreement, including precise thresholds, formulas, constraint types, and "
"testing frequencies"
),
system_prompt=(
"You are a specialist in analyzing commercial loan agreements and credit "
"facility documentation. Your task is to:\n"
"- Identify every financial covenant in the provided agreement text\n"
"- Extract the exact numerical threshold for the applicable period\n"
"- Determine the formula specified for each covenant\n"
"- Classify each as 'maximum' (must not exceed) or 'minimum' (must not fall below)\n"
"- Note the testing frequency (quarterly TTM, point-in-time, etc.)\n\n"
"CRITICAL: Only extract values explicitly stated in the document. Never infer "
"or estimate thresholds. Use the exact step-down schedule applicable to the "
"reporting period being analyzed."
),
education="JD in Corporate Law, CFA Charterholder",
work_experience="15 years in leveraged finance documentation and loan agreement analysis",
tool_call_limit=5,
)


def create_financial_calculator_agent(model: str = "openai/gpt-4o-mini") -> Agent:
"""Create a specialist agent for computing financial ratios using calculation tools.

Args:
model: Model identifier for the agent.

Returns:
Configured Agent with financial calculation tools.
"""
financial_tools: List[Callable[..., dict]] = [
calculate_leverage_ratio,
calculate_interest_coverage_ratio,
calculate_current_ratio,
calculate_debt_service_coverage_ratio,
calculate_tangible_net_worth,
]

return Agent(
model=model,
name="Financial Calculator",
role="Quantitative Financial Analyst",
goal=(
"Calculate all required financial ratios and metrics from raw financial "
"data using the provided calculation tools, producing an audit-ready trail"
),
system_prompt=(
"You are a quantitative analyst responsible for computing financial ratios "
"needed for covenant compliance testing.\n\n"
"RULES:\n"
"1. ALWAYS use the provided calculation tools. NEVER compute ratios manually.\n"
"2. Use exact figures from the financial data. Do not round or adjust inputs.\n"
"3. For each ratio, identify the correct input values from the financial data "
"and call the corresponding tool.\n"
"4. Report all results with their component values for audit trail.\n\n"
"Available tools:\n"
"- calculate_leverage_ratio(total_debt, ebitda)\n"
"- calculate_interest_coverage_ratio(ebit, interest_expense)\n"
"- calculate_current_ratio(current_assets, current_liabilities)\n"
"- calculate_debt_service_coverage_ratio(net_operating_income, total_debt_service)\n"
"- calculate_tangible_net_worth(total_assets, total_liabilities, intangible_assets)"
),
education="MS in Financial Engineering, FRM Certification",
work_experience="10 years in credit risk analytics and financial modeling",
tools=financial_tools,
tool_call_limit=15,
)


def create_risk_assessor_agent(model: str = "openai/gpt-4o-mini") -> Agent:
"""Create a specialist agent for evaluating covenant compliance and risk.

Args:
model: Model identifier for the agent.

Returns:
Configured Agent with the compliance evaluation tool.
"""
compliance_tools: List[Callable[..., dict]] = [evaluate_covenant_compliance]

return Agent(
model=model,
name="Risk Assessor",
role="Credit Risk Officer",
goal=(
"Evaluate covenant compliance status for each covenant using the evaluation "
"tool, calculate overall risk score, and provide actionable recommendations"
),
system_prompt=(
"You are a senior credit risk officer evaluating loan covenant compliance.\n\n"
"PROCESS:\n"
"1. For each covenant, call evaluate_covenant_compliance with:\n"
" - covenant_name: the covenant's name\n"
" - actual_value: the calculated ratio/metric value\n"
" - threshold: the covenant threshold from the agreement\n"
" - constraint_type: 'maximum' or 'minimum'\n"
"2. Analyze headroom percentage for each to assess comfort level\n"
"3. Compute overall risk score using this methodology:\n"
" - Start at 0 (no risk)\n"
" - Add 30 points per breached covenant\n"
" - Add 15 points per near-breach covenant\n"
" - Risk levels: 0-20=Low, 21-40=Moderate, 41-70=High, 71-100=Critical\n"
"4. Provide specific, actionable recommendations for any covenant that is "
"near breach or breached, considering both immediate remediation and "
"structural solutions\n\n"
"Consider cure provisions and grace periods when formulating recommendations."
),
education="MBA in Finance, PRM Certification",
work_experience="12 years in commercial banking credit risk and portfolio monitoring",
tools=compliance_tools,
tool_call_limit=15,
)
92 changes: 92 additions & 0 deletions examples/loan_covenant_monitoring/data/financial_data.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
{
"company_name": "GlobalTechMac Manufacturing Inc.",
"reporting_period": "Q4 2025",
"period_end_date": "2025-12-31",
"measurement_basis": "Trailing Twelve Months (TTM) ending December 31, 2025",
"currency": "USD",

"income_statement_ttm": {
"revenue": 285000000,
"cost_of_goods_sold": 192000000,
"gross_profit": 93000000,
"selling_general_administrative": 51000000,
"depreciation_expense": 13500000,
"amortization_expense": 4500000,
"total_operating_expenses": 69000000,
"operating_income_ebit": 24000000,
"interest_expense": 8600000,
"pre_tax_income": 15400000,
"income_tax_expense": 3850000,
"net_income": 11550000,
"ebitda": 42000000,
"ebitda_adjustments_note": "EBITDA includes $2,100,000 add-back for non-recurring restructuring charges approved by Lender per Section 7.1"
},

"balance_sheet_q4_2025": {
"current_assets": {
"cash_and_equivalents": 12500000,
"accounts_receivable_net": 35800000,
"inventory": 24500000,
"prepaid_expenses": 5500000,
"total_current_assets": 78300000
},
"non_current_assets": {
"property_plant_equipment_net": 175000000,
"goodwill": 22000000,
"patents_and_trademarks": 8500000,
"other_intangible_assets": 4500000,
"other_non_current_assets": 6200000,
"total_non_current_assets": 216200000
},
"total_assets": 294500000,

"current_liabilities": {
"accounts_payable": 22000000,
"accrued_expenses": 12500000,
"current_portion_long_term_debt": 15000000,
"other_current_liabilities": 8500000,
"total_current_liabilities": 58000000
},
"non_current_liabilities": {
"long_term_debt": 120000000,
"capital_lease_obligations": 7500000,
"other_non_current_liabilities": 4000000,
"total_non_current_liabilities": 131500000
},
"total_liabilities": 189500000,

"shareholders_equity": {
"common_stock_and_apic": 15000000,
"retained_earnings": 90000000,
"total_shareholders_equity": 105000000
}
},

"debt_schedule": {
"senior_term_loan_outstanding": 120000000,
"current_portion_term_loan": 15000000,
"capital_lease_obligations": 7500000,
"outstanding_letters_of_credit": 9500000,
"total_funded_debt": 152000000,
"weighted_average_interest_rate_percent": 5.65,
"next_principal_payment_date": "2026-03-31",
"next_principal_payment_amount": 3750000
},

"cash_flow_data_ttm": {
"ebitda": 42000000,
"unfunded_capital_expenditures": 10000000,
"cash_taxes_paid": 4860000,
"net_operating_income_for_dscr": 27140000,
"scheduled_principal_payments": 15000000,
"total_interest_paid": 8600000,
"total_debt_service": 23600000
},

"intangible_assets_summary": {
"goodwill": 22000000,
"patents_and_trademarks": 8500000,
"other_intangibles": 4500000,
"total_intangible_assets": 35000000
}
}
Loading