The ERP Financial Agent connects to a single MySQL database that holds migrated SAP/ERP financial tables. All access is read-only — the agent generates and executesDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/yohangr3/agentelanggrafh/llms.txt
Use this file to discover all available pages before exploring further.
SELECT statements only. Every connection is managed through a singleton AsyncEngine built with SQLAlchemy and the aiomysql async driver.
Supported database
| Property | Value |
|---|---|
| Engine | MySQL 8.0 |
| Driver | aiomysql (async) |
| ORM layer | SQLAlchemy AsyncEngine / AsyncSession |
| Deployment | AWS RDS (Multi-AZ recommended for production) |
| Default database name | iafinagent |
| Default port | 3306 |
Connection configuration
Set these variables in.env (or as ECS environment variables in production):
RDS endpoint hostname, e.g.
iafinagent.choi0eaq2mr7.us-east-1.rds.amazonaws.com.MySQL port. Change only if your instance uses a custom port.
Target database (schema) name. The default used across the CloudFormation stack is
iafinagent.Database login username. Create a dedicated user with
SELECT-only grants; do not use the RDS master user.Database password. In production this value is injected at container startup from AWS Secrets Manager via
DB_PASSWORD_SECRET_ARN. See AWS Setup for details.Settings class in src/core/config.py exposes a computed database_url property that assembles the full async connection string:
src/core/config.py
Connection pool
The singleton engine is created once at startup byget_engine() in src/core/database.py and reused for every request. The pool constants are:
| Pool parameter | Value | Notes |
|---|---|---|
pool_size | 5 | Persistent connections kept open |
max_overflow | 5 | Extra connections allowed above pool_size (burst) |
pool_timeout | 15 s | Time to wait for a free connection from the pool |
pool_recycle | 295 s | Connection is retired before RDS wait_timeout (typically 300 s) |
pool_pre_ping | true | Issues SELECT 1 before each checkout to evict stale connections |
src/core/database.py
Timeout settings
Three independent timeouts govern the MySQL connection lifecycle. All are tunable via environment variables:TCP handshake and authentication timeout in seconds. Passed as
connect_timeout in connect_args to aiomysql. The default of 10 seconds is conservative enough for cross-AZ RDS connections.Per-read timeout in seconds. Controls how long the driver waits for data from the server on a single network read.
Per-write timeout in seconds. Applies to write operations (used only if the application is ever extended beyond read-only access).
QUERY_TIMEOUT_SECONDS (default 30) is enforced at the application layer — the agent cancels any query that has not returned within this wall-clock limit.
Circuit breaker
A circuit breaker wraps database operations to prevent cascading failures when RDS becomes unavailable. Configuration:Number of consecutive failures required to trip the circuit breaker (open state). While open, requests fail fast without attempting a database connection.
Seconds after which the circuit breaker transitions from open to half-open and allows a single probe request through. If the probe succeeds the circuit closes; if it fails the timer resets.
Read-only enforcement
The agent exclusively executesSELECT statements. Enforcement happens at two layers:
- SQL validator
- Database user grants
The
sql_validation_enabled flag (default true) routes every generated SQL string through sqlglot before execution. The validator:- Parses the statement and checks the AST root node type.
- Rejects any statement that is not a
SELECT— this includesINSERT,UPDATE,DELETE,DROP,CREATE,ALTER,TRUNCATE, and any stored-procedure call. - Returns a structured error to the self-correction loop, which attempts to rewrite the query (up to
MAX_CORRECTION_ATTEMPTS = 3times).
Schema registry and FAISS index
At startup the agent readsINFORMATION_SCHEMA to build a semantic index of the database schema. This index is used by the schema_linker node to select the most relevant tables and columns for each natural-language query.
Read INFORMATION_SCHEMA
The schema registry queries
INFORMATION_SCHEMA.COLUMNS and INFORMATION_SCHEMA.TABLES to enumerate all tables and columns in DB_NAME.Enrich with domain knowledge
Each table/column entry is enriched with human-readable descriptions from the YAML schema catalog in
yaml_schemas/*.yml (when USE_GENERATED_SCHEMA_CATALOG=true, the default).Embed with Amazon Titan
Enriched schema chunks are embedded using
BEDROCK_EMBEDDING_MODEL_ID (amazon.titan-embed-text-v2:0), producing 1024-dimensional vectors (EMBEDDING_DIMENSIONS=1024).Persist FAISS index
The vectors are stored in a FAISS flat index on disk at the path specified by
FAISS_INDEX_DIR (default data/faiss_index). The index is loaded from disk on subsequent startups if it exists, avoiding re-embedding on every restart.Query limits
Hard ceiling on rows returned from any single SELECT. The database layer adds a
LIMIT clause if the generated SQL omits one, and truncates result sets that exceed this value.Wall-clock timeout for SQL execution enforced at the application layer. Queries running longer than this are cancelled and the agent returns a timeout error to the user.
Health check
The FastAPI application exposes aGET /health endpoint that verifies database connectivity by running SELECT 1:
src/core/database.py
database key:
GET /health every 30 seconds with a 15-second timeout. A task is marked unhealthy after 3 consecutive failures and replaced automatically.
Retry configuration
Transient database errors (e.g. connection refused during an RDS failover) are retried with exponential back-off:| Variable | Default | Description |
|---|---|---|
MAX_RETRIES_DB | 2 | Maximum retry attempts for database operations |
RETRY_BACKOFF_MULTIPLIER | 1 | Back-off multiplier applied between retries |
RETRY_BACKOFF_MIN | 2 s | Minimum wait before the first retry |
RETRY_BACKOFF_MAX | 10 s | Maximum wait cap between retries |
Retry logic is additive with the circuit breaker. If the circuit is already open, retries are skipped and the request fails immediately rather than waiting out the full back-off sequence.