The Economic Data Tools: FRED and BEA
fred_tool.py and bea_tool.py fetch live economic data and inject it into synthesis context as cited markdown blocks. Both tools use intent-based routing — a query string maps to a curated set of series or tables — and embed structured citation anchors ([FRED:SERIES:DATE], [BEA:dataset:table:geo:period]) that the synthesis instruction requires the model to reference explicitly.
The citation discipline is the core design principle for both tools. Without it, an LLM synthesizing economic research will state figures confidently but without provenance — "unemployment fell to 3.7% in October" with no indication of whether that's FRED UNRATE data, a Beige Book anecdote, or a training-data guess. The citation format forces every empirical claim to be traceable to a specific API response with a known retrieval date.
fred_tool: FRED API with theme routing
The Federal Reserve Economic Data (FRED) API covers over 800,000 time series. fred_tool.py makes this navigable without knowing series IDs by maintaining a curated theme catalogue — keyword phrases mapped to groups of series identifiers.
# Standalone smoke-test
python -m harness.fred_tool "unemployment rate"
python -m harness.fred_tool --series UNRATE --start 2024-01-01
python -m harness.fred_tool --release "Consumer Price Index"
The theme catalogue maps common query phrases to pre-vetted series groups:
# Sample entries from the theme catalogue
THEMES = {
"unemployment": ["UNRATE", "U6RATE", "ICSA", "CCSA"],
"inflation": ["CPIAUCSL", "CPILFESL", "PCEPI", "PCEPILFE"],
"gdp": ["GDP", "GDPC1", "A191RL1Q225SBEA"],
"rates": ["FEDFUNDS", "DGS10", "DGS2", "T10Y2Y"],
"housing": ["HOUST", "CSUSHPINSA", "MORTGAGE30US"],
# ...15 themes total
}
query_fred(query) runs _themes_for_query(query) to identify matching themes, fetches observations for each mapped series, and formats the results as a markdown block. For each series it includes the series title, units, frequency, recent observations, and a citation anchor on each data point:
### UNRATE — Unemployment Rate (Seasonally Adjusted)
Units: Percent | Frequency: Monthly
| Date | Value | Citation |
|------------|-------|---------|
| 2024-10-01 | 4.1 | [FRED:UNRATE:2024-10-01] |
| 2024-09-01 | 4.1 | [FRED:UNRATE:2024-09-01] |
The rate limiter enforces 0.7 seconds between any two API calls (~1.4 req/s), with four retries on 429 errors using exponential backoff starting at 3 seconds. The FRED free tier allows ~120 requests per minute — the rate limiter keeps the tool well under that even when fetching multiple series for a single query.
Direct series access bypasses theme routing for cases where the series ID is known:
from harness.fred_tool import get_series, search_series
# Fetch specific series with date range
data = get_series("PCE", start="2023-01-01", end="2025-12-31")
# Search for series by keyword
hits = search_series("personal consumption expenditures", limit=8)
bea_tool: BEA API with curated query catalogue
The Bureau of Economic Analysis API is more structured than FRED — data is organized into datasets and tables rather than individual series. bea_tool.py wraps four BEA datasets with a curated query catalogue of ~15 named queries, each specifying the exact dataset, table names, geographic scope, and year range.
NIPA
National Income and Product Accounts — quarterly/annual GDP components, personal income, consumer spending, government expenditure. Queries: gdp_components, personal_income_national, consumer_spending.
Regional
Real GDP and personal income by state, county, and MSA going back to 1929. Queries: gdp_by_state, personal_income_by_state, per_capita_income_by_state, regional_price_parities.
GDPbyIndustry
Value added and gross output by industry sector, annual and quarterly. Queries: gdp_by_industry, gdp_by_industry_quarterly.
ITA
International Trade in Goods and Services — trade balance, exports and imports by category. Queries: trade_balance, goods_exports, services_balance.
query_bea(query, geo) maps query text to named queries via a keyword-to-query-list dict, executes each named query against the BEA API, and formats results as markdown. The optional geo parameter filters Regional dataset results to specific states (e.g. geo="NY,CA,TX").
Citation format: [BEA:Regional:SAGDP9N:STATE:2024] — dataset, table name, geographic scope, period. These match the pattern the SYNTH_INSTRUCTION_RESEARCH synthesis instruction requires:
use inline citations: [FRED:SERIES:DATE] for FRED data,
[BEA:DATASET:TABLE:GEO:PERIOD] for BEA data
Both tools are invoked automatically by agent.py when FRED_API_KEY and BEA_API_KEY are set and the task classifier identifies a macroeconomic context. They run in the research phase before synthesis — FRED and BEA data is fetched alongside web search results and injected into the same context block the model synthesizes from.
BEA API keys are free but require registration at apps.bea.gov. FRED keys are also free from fred.stlouisfed.org. Both are set in .env as FRED_API_KEY and BEA_API_KEY. Without keys, the tools raise a RuntimeError with instructions — they never silently fall back to stale training data.