AutoGen Tutorial (TypeScript): adding human-in-the-loop for beginners

By Cyprian AaronsUpdated 2026-04-21
autogenadding-human-in-the-loop-for-beginnerstypescript

This tutorial shows you how to pause an AutoGen TypeScript agent workflow, ask a human for approval, and continue only after the user responds. You need this when an agent is about to send an email, make a tool call, or take any action that should not happen without review.

What You'll Need

  • Node.js 18+
  • A TypeScript project with ts-node or tsx
  • autogen installed in your project
  • An OpenAI API key exported as OPENAI_API_KEY
  • Basic familiarity with AutoGen agents and model clients
  • A terminal where you can type human approval responses

Install the package if you do not have it yet:

npm install autogen
npm install -D typescript tsx @types/node

Step-by-Step

  1. Start by creating a small TypeScript file that wires up a single assistant agent. The important part is that we will not let the agent run unchecked; we will wrap each response in a human approval gate.
import { AssistantAgent, OpenAIChatCompletionClient } from "autogen";

const client = new OpenAIChatCompletionClient({
  model: "gpt-4o-mini",
  apiKey: process.env.OPENAI_API_KEY!,
});

const agent = new AssistantAgent({
  name: "support_agent",
  modelClient: client,
  systemMessage: "You are a support assistant. Keep replies short and practical.",
});
  1. Add a human-in-the-loop helper using Node’s built-in readline module. This gives you a simple approval prompt in the terminal, which is enough for beginners and works well for local testing.
import readline from "node:readline/promises";
import { stdin as input, stdout as output } from "node:process";

const rl = readline.createInterface({ input, output });

async function askHumanApproval(message: string): Promise<boolean> {
  console.log("\nAGENT DRAFT:\n");
  console.log(message);
  const answer = await rl.question("\nApprove this response? (y/n): ");
  return answer.trim().toLowerCase() === "y";
}
  1. Now run the agent, inspect its draft, and only release it if the human approves. If the human rejects it, stop the flow or ask the agent to rewrite based on feedback.
async function main() {
  const task = "Draft a one-paragraph reply to a customer asking why their refund is delayed.";

  const result = await agent.run(task);
  const draft = result.messages[result.messages.length - 1]?.content ?? "";

  const approved = await askHumanApproval(draft);

  if (!approved) {
    console.log("\nRejected by human. No message sent.");
    await rl.close();
    return;
  }

  console.log("\nApproved. Final message:\n");
  console.log(draft);
  await rl.close();
}

main().catch(async (err) => {
  console.error(err);
  await rl.close();
  process.exit(1);
});
  1. If you want the human to edit the output instead of just approving or rejecting it, add a second prompt. This is useful when the agent is close but needs compliance wording, shorter phrasing, or a different tone.
async function getHumanEdits(original: string): Promise<string> {
  console.log("\nPaste edits below. Press Enter on an empty line to keep original.");
  const edited = await rl.question("Edited version: ");
  return edited.trim().length > 0 ? edited : original;
}

async function approveOrEdit(draft: string): Promise<string | null> {
  const approved = await askHumanApproval(draft);
  if (approved) return draft;

  const revised = await getHumanEdits(draft);
  if (!revised) return null;

  return revised;
}
  1. Put it together in one file so you can execute it directly. This version uses approval plus optional editing, which is the simplest pattern for production-style review gates.
import { AssistantAgent, OpenAIChatCompletionClient } from "autogen";
import readline from "node:readline/promises";
import { stdin as input, stdout as output } from "node:process";

const rl = readline.createInterface({ input, output });

async function askHumanApproval(message: string): Promise<boolean> {
  console.log("\nAGENT DRAFT:\n");
  console.log(message);
  const answer = await rl.question("\nApprove this response? (y/n): ");
  return answer.trim().toLowerCase() === "y";
}

async function getHumanEdits(): Promise<string> {
  return rl.question("Enter revised text: ");
}

async function main() {
  const client = new OpenAIChatCompletionClient({
    model: "gpt-4o-mini",
    apiKey: process.env.OPENAI_API_KEY!,
  });

  const agent = new AssistantAgent({
    name: "support_agent",
    modelClient: client,
    systemMessage: "You are a support assistant. Keep replies short and practical.",
  });

  const result = await agent.run(
    "Draft a one-paragraph reply to a customer asking why their refund is delayed."
    );

  let draft = result.messages[result.messages.length - 1]?.content ?? "";

   if (!(await askHumanApproval(draft))) {
    draft = await getHumanEdits();
   }

   console.log("\nFinal text:\n");
   console.log(draft);

   await rl.close();
}

main().catch(async (err) => {
   console.error(err);
   await rl.close();
   process.exit(1);
});

Testing It

Run the file with OPENAI_API_KEY set in your shell and confirm that the agent prints a draft before anything else happens. Then type n at the approval prompt and verify that no final message is released unless you provide edits.

If you type y, the script should print the same draft as the final text. If you choose rejection and enter revised text, confirm that your edited version becomes the output instead of the raw model response.

A good next test is to replace the prompt with something risky, like “write an email requesting account verification details,” and confirm that your review gate catches it before release.

Next Steps

  • Add structured approval metadata like reviewer name, timestamp, and decision reason
  • Move the approval step into an HTTP API so product users can approve from a web UI
  • Extend this pattern to tool calls so humans can approve external actions before execution

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