Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/astrxnomo/financial-analytics-agent/llms.txt

Use this file to discover all available pages before exploring further.

The Agent Chat is the primary interface for Northwind Labs’ financial analytics system. It binds the eve agent — running server-side via withEve() in Next.js — to a browser chat panel that streams messages in real time and renders every tool result as an interactive Recharts chart, directly inline with the agent’s prose analysis. When you type a question, the agent calls the right analytics tool, the tool result flows back as a structured message part, and the custom ToolResult renderer swaps in the matching chart component — all without a separate API round-trip from the browser.

How it works

useEveAgent (from eve/react) opens a persistent channel to the agent at /eve/v1/* and exposes a messages array, a send function, and a streaming status. Each message from the agent can contain multiple parts: plain text parts carry the analyst’s prose, and tool result parts carry a name (e.g. "get_trend") plus a JSON output payload. AgentMessage iterates those parts and hands each tool result part to FinanceToolSlot, which renders a ToolResultSkeleton while the tool is still running (i.e. state === "input-available") and crossfades it to the real chart once state === "output-available". The crossfade is a 220ms opacity transition via motion/react (AnimatePresence + layout) so the height change between the fixed-height skeleton and the chart’s natural height animates instead of snapping. Inside ToolResult (the inner memo), the renderer inspects name, casts output to the correct TypeScript type from finance.types.ts, and picks the matching chart component:
if (name === "get_trend") {
  return (
    <ChartPanel
      render={(size, action) => (
        <TrendChart
          action={action}
          departments={trendInput?.departments}
          metric={trendInput?.metric}
          points={output as TrendPoint[]}
          size={size}
        />
      )}
      title={`${metricLabel(trendInput?.metric) ?? "Monthly"} trend${scopeSuffix([trendInput?.departments])}`}
    />
  );
}
The input prop travels alongside output so chart titles can reflect the exact scope of the call (e.g. "Revenue trend — Engineering, Marketing" rather than a generic heading that silently implies all departments).

Persona

The agent acts as a senior financial analyst for Northwind Labs. Its behavior is shaped by agent/instructions.md and a session-dynamic block injected by agent/instructions/dates.ts:
  • Always fetches real data first. Every figure in the agent’s reply must come from a tool result — no invented or recalled numbers.
  • Leads with the answer. The first sentence is always the direct takeaway, never a preamble like “Let me analyze…”
  • Does not compute directional deltas. When comparing two periods, the agent states both raw tool-sourced figures and lets the reader compare. This prevents a class of arithmetic-reversal bugs where the model states a direction backwards.
  • Scales depth to the question. A single-number lookup gets one or two sentences; a multi-part analytical question gets a short structured brief with bold inline labels.
  • Never writes markdown tables. The chart already shows the data; re-listing rows in a table is redundant.
  • Stays in scope. Questions outside what the tools can answer (HR, product strategy, etc.) are declined plainly.
The agent never states a directional delta (e.g. “expenses decreased by $X”) — it states both raw numbers and lets the reader compare. This prevents a class of subtle arithmetic reversal bugs.

Suggested questions

When the chat is empty, useFinanceHighlights (in app/_components/agent-chat/use-finance-highlights.ts) fetches /api/finance/highlights to retrieve live metadata about the seeded dataset: dataFrom, dataTo, latestMonth, and a few pre-computed story hooks (top anomaly, most-over-budget department, fastest-growing category). buildQuestions and QUESTION_TOPICS use that data to generate question chips that reference real departments, real date ranges, and real patterns from the live dataset — so a chip like “Which department went over budget in June 2026?” always names the actual latest closed month rather than a placeholder. This requires no extra model round-trip: it is a single REST call that runs before the user types anything, and the chips are rendered from the returned Highlights object directly. Once the user has asked questions, contextualFollowups and QUESTION_INDEX_BY_TOOL collaborate to surface follow-up chips that are thematically connected to the agent’s most recent tool call. Thread-specific follow-ups (referencing the same department or category as the last answer) appear first; generic pool questions fill remaining slots so targeted chips are never crowded out.

Example interactions

User questionTool triggeredChart rendered
”How did marketing spend grow in Q2 vs Q1?”get_trend with departments: ["Marketing"]Multi-period line chart; agent states Q1 and Q2 figures in order
”Which department went over budget this month?”get_budget_status for the latest closed monthGrouped bar chart (budget vs. actual); over-budget bars highlighted in critical red
”Any unusual transactions this year?”get_anomalies with threshold: 2.5Anomaly table with σ deviation labels; agent names the top outlier
”Show the revenue trend for the last 6 months”get_trend with metric: "income"Line chart across six monthly periods; single-period fallback renders as bars
For the budget question, the agent explicitly says “for [month], the latest closed month” rather than implying the answer covers a longer window — get_budget_status covers one month only.

Session management

Context is managed at the agent/agent.ts level. The model is Mistral devstral-latest via @ai-sdk/mistral, configured with modelContextWindowTokens: 128_000 (manually maintained, since the direct Mistral provider doesn’t expose this automatically). The client mirrors that same constant as MODEL_CONTEXT_WINDOW_TOKENS = 128_000 and uses token usage from step.completed events to render a live context-usage indicator in the prompt toolbar. Eve’s built-in context compaction fires at 70% of the context window, summarizing older turns to keep the conversation focused without truncating tool results mid-stream. Turn failures (e.g. provider rate-limit exhaustion after eve’s internal retries) are caught via an onEvent listener for "turn.failed" and surfaced as a dismissible amber warning banner with a retry button. Full session errors (agent.error) show a red banner instead.

API endpoints panel

The prompt toolbar contains a REST API menu (the <Code2Icon> button) that lists every app/api/finance/* endpoint as a clickable link. Each link is pre-filled with real date parameters sourced from the Highlights object — for example:
/api/finance/summary?from=2023-07-01&to=2026-06-30
/api/finance/budget-status?month=2026-06-01
/api/finance/trend?metric=income&groupBy=month&from=2023-07-01&to=2026-06-30
These links open in a new tab and go directly to the JSON response, making it easy to explore the REST surface that backs the agent. The same Highlights fetch that powers the suggested question chips also powers this panel, so both are grounded in the live dataset with a single request.

Build docs developers (and LLMs) love