How to Build a transaction monitoring Agent Using AutoGen in TypeScript for pension funds

By Cyprian AaronsUpdated 2026-04-21
transaction-monitoringautogentypescriptpension-funds

A transaction monitoring agent for pension funds watches contribution, transfer, withdrawal, and benefit-payment activity for patterns that look unusual, policy-breaking, or suspicious. It matters because pension administrators need to catch fraud, leakage, and compliance breaches early without flooding analysts with false positives.

Architecture

Build this agent as a small system, not a single prompt.

  • Ingestion layer

    • Pulls transactions from core pension systems, batch files, or event streams.
    • Normalizes fields like member ID, employer ID, amount, currency, channel, and timestamps.
  • Policy/rules service

    • Encodes pension-specific controls:
      • early withdrawal rules
      • contribution caps
      • duplicate payment detection
      • employer remittance delays
      • unusual beneficiary changes
  • AutoGen agent group

    • Uses multiple specialized agents:
      • a triage agent to classify the case
      • a compliance agent to check policy alignment
      • an investigator agent to produce an audit-ready summary
  • Case store and audit log

    • Persists every decision, tool call, and output.
    • Needed for regulator review and internal model governance.
  • Human review queue

    • Sends high-risk alerts to analysts before action is taken.
    • Keeps the agent advisory-only for regulated decisions.
  • Data boundary controls

    • Enforces residency, masking, retention limits, and least-privilege access.
    • Critical when member data cannot leave a specific jurisdiction.

Implementation

1) Install AutoGen and define your transaction schema

Use the TypeScript AutoGen package and keep your transaction object strict. Pension data gets messy fast if you let free-form JSON leak into the agent layer.

npm install @autogenai/autogen zod
import { z } from "zod";

export const TransactionSchema = z.object({
  transactionId: z.string(),
  memberId: z.string(),
  employerId: z.string().optional(),
  type: z.enum(["contribution", "withdrawal", "transfer", "benefit_payment"]),
  amount: z.number().positive(),
  currency: z.string().length(3),
  country: z.string(),
  timestamp: z.string(),
  channel: z.enum(["api", "batch", "manual", "partner"]),
  metadata: z.record(z.any()).optional(),
});

export type Transaction = z.infer<typeof TransactionSchema>;

2) Create specialized AutoGen agents

The pattern here is one orchestrator plus specialists. In AutoGen TypeScript you can instantiate AssistantAgent objects and wire them through a GroupChat with a GroupChatManager.

import {
  AssistantAgent,
  GroupChat,
  GroupChatManager,
} from "@autogenai/autogen";

const triageAgent = new AssistantAgent({
  name: "triage_agent",
  systemMessage:
    "You triage pension transactions for risk. Return concise risk labels only.",
});

const complianceAgent = new AssistantAgent({
  name: "compliance_agent",
  systemMessage:
    "You assess pension compliance issues. Focus on residency, caps, withdrawals, transfers, and auditability.",
});

const investigatorAgent = new AssistantAgent({
  name: "investigator_agent",
  systemMessage:
    "You produce an audit-ready case summary with facts, rationale, and next actions.",
});

const groupChat = new GroupChat({
  agents: [triageAgent, complianceAgent, investigatorAgent],
  messages: [],
});

const manager = new GroupChatManager({
  groupchat: groupChat,
});

3) Feed a transaction into the group chat and capture the result

Keep the prompt structured. The agent should not invent facts; it should classify based on the record plus explicit policy text.

async function monitorTransaction(tx: Transaction) {
  const validated = TransactionSchema.parse(tx);

  const policyContext = `
Pension fund controls:
- Flag withdrawals before eligibility age unless approved exception exists.
- Flag transfers to unsupported jurisdictions.
- Flag duplicate benefit payments within the same pay cycle.
- Flag contributions exceeding annual cap.
- All alerts must be explainable for audit.
`;

  const task = `
Review this transaction and return:
1. risk_level: low|medium|high
2. reasons: bullet list
3. recommended_action: monitor|queue_for_review|freeze_pending_review

Transaction:
${JSON.stringify(validated, null, 2)}

Policy:
${policyContext}
`;

  const result = await manager.run(task);
  return result;
}

4) Add a deterministic decision layer before any operational action

Do not let the model directly freeze accounts or block payments. Use the model for triage; use code for enforcement.

function decideAction(riskLevel: string) {
  switch (riskLevel) {
    case "high":
      return "queue_for_review";
    case "medium":
      return "monitor";
    default:
      return "monitor";
  }
}

Then parse the model output in your service layer and map it to your internal workflow engine.

Production Considerations

  • Deployment

    • Keep the agent inside your regulated network or approved cloud region.
    • For pension funds with residency constraints, pin storage and inference endpoints to the required jurisdiction.
  • Monitoring

    • Log every prompt, response, tool call, and final action with immutable correlation IDs.
    • Track false positives by transaction type so you can tune thresholds on contributions versus withdrawals separately.
  • Guardrails

    • Mask member PII before sending context to the model unless absolutely required.
    • Use allowlisted tools only; never expose raw database access from the agent layer.
    • Require human approval for any action that changes payment state.
  • Governance

Retain alert evidence according to local pension regulation + internal policy.
Version prompts like code.
Run periodic reviews of model outputs against known suspicious cases.

Common Pitfalls

  1. Letting the LLM make final decisions

    • Mistake: using model output as the source of truth for freezes or reversals.
    • Fix: keep decisioning deterministic in your application code; use AutoGen only for analysis and summarization.
  2. Sending too much member data into prompts

    • Mistake: including full identity profiles, bank details, or entire account histories by default.
    • Fix: pass only the fields needed for that case. Mask identifiers and redact sensitive attributes unless an analyst has explicitly opened the case.
  3. Ignoring pension-specific rules

    • Mistake: building generic AML logic that misses contribution caps, vesting conditions, eligibility age rules, or transfer restrictions.
    • Fix: encode fund policy as versioned rules alongside the agent so every alert is evaluated against pension-specific controls.
  4. Weak audit trails

    • Mistake: storing only the final risk label.
    • Fix: persist input transaction payloads, policy version used, agent outputs, timestamps, reviewer actions, and final disposition. That is what survives audit scrutiny.

Keep learning

By Cyprian Aarons, AI Consultant at Topiax.

Want the complete 8-step roadmap?

Grab the free AI Agent Starter Kit — architecture templates, compliance checklists, and a 7-email deep-dive course.

Get the Starter Kit

Related Guides