How to Build a compliance checking Agent Using AutoGen in TypeScript for investment banking

By Cyprian AaronsUpdated 2026-04-21
compliance-checkingautogentypescriptinvestment-banking

A compliance checking agent for investment banking reviews proposed client communications, trade-related content, and internal documents against policy rules before anything leaves the firm. It matters because a single bad recommendation, missing disclosure, or restricted-word violation can trigger regulatory issues, reputational damage, and audit findings.

Architecture

Build this agent as a narrow workflow, not a general chat bot.

  • Input normalizer

    • Accepts email drafts, pitch books, chat messages, or order/trade commentary.
    • Extracts the text plus metadata like desk, jurisdiction, client type, and timestamp.
  • Policy retrieval layer

    • Pulls the relevant rule set from a controlled source.
    • Examples: restricted terms, required disclosures, retention rules, and region-specific constraints.
  • AutoGen compliance analyst agent

    • Uses an LLM to classify issues against policy.
    • Produces structured findings: severity, violated rule, rationale, and suggested fix.
  • Deterministic validator

    • Enforces hard rules outside the model.
    • Examples: banned phrases, missing disclaimer blocks, PII leakage checks, and jurisdiction filters.
  • Audit logger

    • Stores prompt inputs, model outputs, policy version, and final decision.
    • Needed for supervision review and regulatory evidence.
  • Human escalation path

    • Routes borderline cases to compliance officers.
    • Required for high-risk content like MNPI references or suitability concerns.

Implementation

1. Install AutoGen for TypeScript and define your policy schema

Use AutoGen’s TypeScript packages and keep the policy output structured. In investment banking, free-form answers are a bad idea because you need deterministic review artifacts.

npm install @autogen-ai/core zod
import { z } from "zod";

export const ComplianceFindingSchema = z.object({
  status: z.enum(["pass", "review", "fail"]),
  severity: z.enum(["low", "medium", "high"]),
  ruleId: z.string(),
  explanation: z.string(),
  remediation: z.array(z.string()).default([]),
});

export type ComplianceFinding = z.infer<typeof ComplianceFindingSchema>;

2. Create a compliance agent with AssistantAgent

The core pattern is an AssistantAgent that receives the draft plus policy context and returns structured findings. Keep the system message strict so the model behaves like a reviewer, not a writer.

import { AssistantAgent } from "@autogen-ai/core";
import { ComplianceFindingSchema } from "./schema";

const complianceAgent = new AssistantAgent({
  name: "compliance_checker",
  systemMessage: `
You are a compliance checking agent for investment banking.
Review text for regulatory risk, disclosure gaps, restricted language, suitability issues,
MNPI indicators, and jurisdiction-specific problems.

Return only JSON matching this schema:
{
  "status": "pass" | "review" | "fail",
  "severity": "low" | "medium" | "high",
  "ruleId": string,
  "explanation": string,
  "remediation": string[]
}

Do not rewrite the content unless asked. Do not provide legal advice.
`,
});

3. Run the check with generateReply and validate the output

This is the operational pattern: send in content plus policy text, get a reply from generateReply, then validate it with Zod before any downstream action.

async function checkContent(draftText: string) {
  const prompt = `
Policy:
- No promises of guaranteed returns.
- All performance references need approved disclaimers.
- No MNPI or inside-information indicators.
- No client-specific advice unless suitability is confirmed.
- EU clients require GDPR-safe handling of personal data.

Draft:
${draftText}
`;

  const result = await complianceAgent.generateReply([
    { role: "user", content: prompt },
  ]);

  const raw = typeof result === "string" ? result : result.content;
  const parsed = ComplianceFindingSchema.parse(JSON.parse(raw));

  return parsed;
}

async function main() {
  const finding = await checkContent(
    `Our desk can guarantee strong returns this quarter. Send me the client's passport number first.`
  );

  console.log(finding);
}

main().catch(console.error);

That example should return a high-severity fail because it includes guaranteed returns language and asks for sensitive personal data. In production you would attach this to your document workflow before approval or distribution.

4. Add deterministic controls around the model

Do not let the LLM be your only gate. Use fixed checks for phrases and data classes that must never pass without review.

const bannedPatterns = [
  /guarantee(d)? returns?/i,
  /\binside information\b/i,
  /\bpassport number\b/i,
];

export function deterministicScreen(text: string) {
    const hits = bannedPatterns.filter((pattern) => pattern.test(text));
    return {
      blocked: hits.length > 0,
      reasons: hits.map((p) => p.toString()),
    };
}

If deterministicScreen() blocks content, send it directly to human review even if the model says pass. That protects you from false negatives on high-risk phrases.

Production Considerations

  • Deploy in-region

    • Keep prompts, documents, and logs in approved jurisdictions.
    • For EU or UK desks, make sure storage and inference paths satisfy residency requirements.
  • Log everything needed for audit

    • Store input text hashes or encrypted payloads, policy version IDs, model version IDs, timestamps, and final disposition.
    • Regulators will ask why something passed or failed months later.
  • Add human-in-the-loop thresholds

    • Auto-pass only low-risk content.
    • Route anything involving MNPI indicators, cross-border distribution rules, retail suitability language, or client complaints to compliance officers.
  • Version policies aggressively

    • Treat rule sets like code.
    • A change in disclosure language or jurisdiction mapping should create a new version with rollback support.

Common Pitfalls

  1. Using the model as the final authority

    • Bad idea in banking.
    • Fix it by combining AssistantAgent output with deterministic screening and mandatory escalation rules.
  2. Returning plain English instead of structured results

    • That makes audit trails messy and automation brittle.
    • Fix it by forcing JSON output and validating with Zod before anything proceeds.
  3. Mixing policy sources without versioning

    • If one desk uses stale disclosure rules while another uses updated ones, your control framework breaks.
    • Fix it by attaching every decision to a specific policy version and keeping immutable logs.
  4. Ignoring data residency and sensitive data handling

    • Drafts often contain client names, account details, or transaction context.
    • Fix it by redacting where possible before inference and keeping processing inside approved regions only.

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