Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
1 change: 1 addition & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ Create a multi-agent research workflow where different AI agents collaborate to
- [Custom Endpoints](./with-custom-endpoints) — Add bespoke REST endpoints alongside agent/workflow routes.
- [Dynamic Parameters](./with-dynamic-parameters) — Validate and inject runtime parameters into agents with Zod.
- [Dynamic Prompts](./with-dynamic-prompts) — Build prompts from templates and live data programmatically.
- [FXMacroData](./with-fxmacrodata) — Answer macro questions with official CPI, GDP, policy-rate and release-calendar data from FXMacroData tools.
- [Google AI](./with-google-ai) — Use Google Gemini models via the AI SDK provider.
- [Google Drive (MCP)](./with-google-drive-mcp) — Browse and read Drive files through a Google Drive MCP server.
- [Google Vertex AI](./with-google-vertex-ai) — Connect agents to Vertex AI models in your GCP project.
Expand Down
3 changes: 3 additions & 0 deletions examples/with-fxmacrodata/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
OPENAI_API_KEY=your_openai_api_key_here
# Optional: USD data works without a key
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.
Outdated
FXMACRODATA_API_KEY=
85 changes: 85 additions & 0 deletions examples/with-fxmacrodata/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# VoltAgent with FXMacroData

This example gives a VoltAgent research agent tools for official macroeconomic data from [FXMacroData](https://fxmacrodata.com/documentation/reference?utm_source=github&utm_medium=referral&utm_campaign=voltagent&utm_content=readme): indicator releases with their publication times, release calendars and FX rates.

## Features

- List the indicators available for a currency (CPI, GDP, policy rate, payrolls, bond yields and more)
- Fetch released values with the period, the publication timestamp and the official source link
- Fetch the upcoming release calendar, with times in UTC and the publisher's local time
- Fetch daily FX rates for a currency pair

## Prerequisites

1. **OpenAI API Key**: Used by the example agent model
2. **FXMacroData API Key** (optional): USD releases, the USD calendar and the indicator catalogue work without a key. Other currencies and FX rates need one, see [plans](https://fxmacrodata.com/subscribe?utm_source=github&utm_medium=referral&utm_campaign=voltagent&utm_content=readme)
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.
Outdated

## Setup

1. Install dependencies:

```bash
pnpm install
```

2. Configure environment variables:

```bash
cp .env.example .env
```

Then edit `.env`:

```env
OPENAI_API_KEY=your_openai_api_key_here
FXMACRODATA_API_KEY=
```

3. Run the example:

```bash
pnpm dev
```

The agent runs on the default VoltAgent server port and exposes one agent named `macroResearchAgent`.

## Tools Available

### 1. List Indicators

- **Purpose**: List indicator slugs, names, units and sources for a currency
- **Endpoint**: `GET /v1/data_catalogue/{currency}`

### 2. Get Indicator History

- **Purpose**: Released values for one indicator, newest first
- **Endpoint**: `GET /v1/announcements/{currency}/{indicator}`
- **Parameters**:
- `currency`: Three-letter code such as `usd`
- `indicator`: Slug such as `inflation` or `policy_rate`
- `startDate`, `endDate`: Optional `YYYY-MM-DD` bounds
- `limit`: Maximum rows (default 12)

### 3. Get Release Calendar

- **Purpose**: Scheduled releases for a currency
- **Endpoint**: `GET /v1/calendar/{currency}`
- **Parameters**:
- `indicator`: Optional slug filter
- `startDate`, `endDate`: Optional `YYYY-MM-DD` bounds

### 4. Get FX Rates

- **Purpose**: Daily rates for a currency pair (needs an API key)
- **Endpoint**: `GET /v1/forex/{base}/{quote}`

## Example Prompts

- "What was the latest US CPI print and when was it published?"
- "When are the next US payrolls and CPI releases?"
- "How has the Fed's policy rate moved this year?"
- "Compare the latest euro area and UK inflation" (needs an API key)

## Notes

The tools return the API response unchanged, so the agent sees units, source links and data-quality fields as published. Responses are not cached; the keyless tier has a fair-use allowance of 100 requests per day.
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.
Outdated
39 changes: 39 additions & 0 deletions examples/with-fxmacrodata/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"name": "voltagent-example-with-fxmacrodata",
"author": "",
"dependencies": {
"@voltagent/cli": "^0.1.21",
"@voltagent/core": "^2.11.0",
"@voltagent/logger": "^2.0.2",
"@voltagent/server-hono": "^2.0.14",
"ai": "^6.0.0",
"zod": "^3.25.76"
},
"devDependencies": {
"@types/node": "^24.2.1",
"tsx": "^4.21.0",
"typescript": "^5.8.2"
},
"keywords": [
"agent",
"ai",
"economic-calendar",
"fxmacrodata",
"macroeconomics",
"voltagent"
],
"license": "MIT",
"private": true,
"repository": {
"type": "git",
"url": "https://github.com/VoltAgent/voltagent.git",
"directory": "examples/with-fxmacrodata"
},
"scripts": {
"build": "tsc",
"dev": "tsx watch --env-file=.env ./src",
"start": "node dist/index.js",
"volt": "volt"
},
"type": "module"
}
30 changes: 30 additions & 0 deletions examples/with-fxmacrodata/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Agent, VoltAgent } from "@voltagent/core";
import { createPinoLogger } from "@voltagent/logger";
import { honoServer } from "@voltagent/server-hono";
import { fxmacrodataTools } from "./tools";
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.
Outdated

const logger = createPinoLogger({
name: "fxmacrodata-agent",
level: "info",
});

const macroResearchAgent = new Agent({
name: "macro-research-agent",
instructions: `You answer macroeconomic and FX questions with FXMacroData tools.

Use listIndicators when you need an indicator slug, getIndicatorHistory for released values,
getReleaseCalendar for what is scheduled next, and getFxRates for exchange rates.
Quote each value with the period it refers to and when it was published, and cite the source link.
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.
Outdated
If a tool returns HTTP 401 or 403, say that the currency or dataset needs an FXMacroData API key
rather than guessing a number.`,
model: "openai/gpt-4o-mini",
tools: fxmacrodataTools,
});

new VoltAgent({
agents: {
macroResearchAgent,
},
logger,
server: honoServer(),
});
167 changes: 167 additions & 0 deletions examples/with-fxmacrodata/src/tools.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
import { createTool } from "@voltagent/core";
import { z } from "zod";

const FXMACRODATA_BASE_URL = "https://api.fxmacrodata.com/v1";
const FXMACRODATA_REQUEST_TIMEOUT_MS = 20_000;

type FXMacroDataQueryParams = Record<string, number | string | undefined>;

type FXMacroDataResult = {
data?: unknown;
error?: string;
status?: number;
success: boolean;
};

const currencySchema = z.string().regex(/^[A-Za-z]{3}$/, "Use a three-letter ISO currency code.");

/**
* Lower-cases a currency code for use in a URL path segment.
*/
function code(value: string): string {
return value.trim().toLowerCase();
}

const dateSchema = z
.string()
.regex(/^\d{4}-\d{2}-\d{2}$/, "Use YYYY-MM-DD.")
.optional();
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.

/**
* Calls a read-only FXMacroData REST endpoint and returns a tool-friendly result.
*
* FXMACRODATA_API_KEY is optional: USD releases, the USD calendar and the data
* catalogue answer without a key. Other currencies and FX rates need one.
*/
export async function callFXMacroData(
path: string,
params: FXMacroDataQueryParams = {},
): Promise<FXMacroDataResult> {
const url = new URL(`${FXMACRODATA_BASE_URL}${path}`);
for (const [key, value] of Object.entries(params)) {
if (value !== undefined && value !== "") {
url.searchParams.set(key, String(value));
}
}

const headers: Record<string, string> = { accept: "application/json" };
const apiKey = process.env.FXMACRODATA_API_KEY;
if (apiKey) {
headers["x-api-key"] = apiKey;
}

const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), FXMACRODATA_REQUEST_TIMEOUT_MS);

try {
const response = await fetch(url, { headers, method: "GET", signal: controller.signal });

if (!response.ok) {
const body = (await response.text()).slice(0, 500);
return {
success: false,
status: response.status,
error: `FXMacroData API returned HTTP ${response.status}: ${body || response.statusText}`,
};
}

return {
success: true,
data: await response.json(),
};
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : "FXMacroData request failed.",
};
} finally {
clearTimeout(timeout);
}
}

/**
* Lists the indicator slugs available for a currency.
*/
export const listIndicatorsTool = createTool({
name: "listIndicators",
description:
"List the macroeconomic indicators available for a currency, with names, units and sources. Call this first when you do not know an indicator slug.",
parameters: z.object({
currency: currencySchema.describe('Three-letter currency code, such as "usd" or "eur".'),
}),
execute: async ({ currency }) => callFXMacroData(`/data_catalogue/${code(currency)}`),
});

/**
* Fetches released values for one indicator, with release timestamps and source links.
*/
export const getIndicatorHistoryTool = createTool({
name: "getIndicatorHistory",
description:
"Fetch released values for one indicator (for example inflation, policy_rate, gdp, unemployment) with the date each value refers to, when it was published, and the official source link.",
parameters: z.object({
currency: currencySchema.describe('Three-letter currency code, such as "usd".'),
indicator: z
.string()
.min(1)
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.
Outdated
.describe('Indicator slug from listIndicators, such as "inflation" or "policy_rate".'),
startDate: dateSchema.describe("Optional start date, YYYY-MM-DD."),
endDate: dateSchema.describe("Optional end date, YYYY-MM-DD."),
limit: z.number().int().min(1).max(100).optional().describe("Maximum rows to return."),
}),
execute: async ({ currency, indicator, startDate, endDate, limit = 12 }) =>
callFXMacroData(
`/announcements/${code(currency)}/${encodeURIComponent(indicator.trim().toLowerCase())}`,
{ start_date: startDate, end_date: endDate, limit },
),
});

/**
* Fetches the upcoming release calendar for a currency.
*/
export const getReleaseCalendarTool = createTool({
name: "getReleaseCalendar",
description:
"Fetch scheduled economic releases for a currency, with release times in UTC and the publisher's local time. Optionally filter to one indicator.",
parameters: z.object({
currency: currencySchema.describe('Three-letter currency code, such as "usd".'),
indicator: z.string().optional().describe('Optional indicator slug, such as "inflation".'),
startDate: dateSchema.describe("Optional start date, YYYY-MM-DD."),
endDate: dateSchema.describe("Optional end date, YYYY-MM-DD."),
}),
execute: async ({ currency, indicator, startDate, endDate }) =>
callFXMacroData(`/calendar/${code(currency)}`, {
indicator: indicator?.trim().toLowerCase(),
start_date: startDate,
end_date: endDate,
}),
});

/**
* Fetches daily FX rates for a currency pair.
*/
export const getFxRatesTool = createTool({
name: "getFxRates",
description:
"Fetch daily FX rates for a currency pair, such as EUR/USD. Requires an FXMacroData API key.",
parameters: z.object({
base: currencySchema.describe('Base currency, such as "eur".'),
quote: currencySchema.describe('Quote currency, such as "usd".'),
startDate: dateSchema.describe("Optional start date, YYYY-MM-DD."),
endDate: dateSchema.describe("Optional end date, YYYY-MM-DD."),
limit: z.number().int().min(1).max(100).optional().describe("Maximum rows to return."),
}),
execute: async ({ base, quote, startDate, endDate, limit = 20 }) =>
callFXMacroData(`/forex/${code(base)}/${code(quote)}`, {
start_date: startDate,
end_date: endDate,
limit,
}),
});

export const fxmacrodataTools = [
listIndicatorsTool,
getIndicatorHistoryTool,
getReleaseCalendarTool,
getFxRatesTool,
];
16 changes: 16 additions & 0 deletions examples/with-fxmacrodata/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.
Outdated
"outDir": "dist",
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"skipLibCheck": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true
},
"include": ["src/**/*"]
}
31 changes: 31 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.