Wiring an autogen human in the loop claude opus 4.5 n4n.ai system means connecting AutoGen’s agent runtime to a model endpoint that won’t fall over when Anthropic throttles you. This how-to builds a minimal but production-shaped pipeline: an Opus 4.5 assistant that proposes actions, a user proxy that blocks on human approval, and a gateway route that abstracts provider specifics. You’ll get runnable Python and a clear success criterion at the end.
Step 1: Set up the Python environment
Use a clean virtual environment. AutoGen’s classic autogen package (0.2.x) ships the UserProxyAgent and AssistantAgent classes we need; the newer autogen-agentchat split changes the API but the human-in-the-loop pattern is identical.
python -m venv .venv
source .venv/bin/activate
pip install pyautogen python-dotenv
Create a .env file that holds your gateway key and base URL. Keep the key out of source control.
# .env
MODEL_API_KEY=sk-your-gateway-key
MODEL_BASE_URL=https://api.n4n.ai/v1
Step 2: Point AutoGen at the Claude Opus 4.5 endpoint
AutoGen speaks OpenAI’s chat completion shape, so any OpenAI-compatible gateway works by swapping base_url and model. The minimal config for autogen human in the loop claude opus 4.5 n4n.ai is a single entry in config_list; point base_url at your gateway and keep the model name exact.
import os
from dotenv import load_dotenv
load_dotenv()
config_list = [
{
"model": "claude-opus-4-5",
"api_key": os.getenv("MODEL_API_KEY"),
"base_url": os.getenv("MODEL_BASE_URL"),
"api_type": "openai",
}
]
Do not set price or max_tokens here unless you have verified values; AutoGen will pass through the gateway’s usage metering unchanged. Because the gateway handles provider fallback, a 429 from Anthropic becomes a silent retry against another route instead of a dead agent loop.
Step 3: Build the assistant agent with guardrails
Opus 4.5 is strong at structured reasoning but will happily invent side effects. Constrain it with a system message that forbids self-execution and demands explicit proposals.
from autogen import AssistantAgent
assistant = AssistantAgent(
name="opus_assistant",
llm_config={"config_list": config_list, "temperature": 0.2},
system_message=(
"You are a senior incident responder. Propose concrete actions "
"as numbered steps. Never claim an action was executed. Wait for "
"human approval before marking anything done."
),
)
Temperature at 0.2 keeps output deterministic enough for audit logs. If you need JSON, add a follow-up instruction, but keep the human gate in place.
Step 4: Configure the human proxy for blocking approval
UserProxyAgent is the bridge between the agent runtime and a person. Set human_input_mode="ALWAYS" so every assistant turn pauses for a keypress. This is the core of human-in-the-loop.
from autogen import UserProxyAgent
user_proxy = UserProxyAgent(
name="human",
human_input_mode="ALWAYS",
code_execution_config=False,
is_termination_msg=lambda m: m.get("content", "").strip().lower().endswith("terminate"),
)
code_execution_config=False disables AutoGen’s built-in local execution. We do not want the model running Python; we want a human reading the proposal.
Interrupt semantics
With ALWAYS, the proxy prints the assistant message and calls input(). The loop blocks until the operator types. Returning a non-empty string feeds that text back as the next human message; returning empty ("") tells the proxy to continue without injecting new context. If you only want prompts on termination attempts, use TERMINATE mode instead. For fully automated runs, NEVER plus a Slack webhook function map is the usual pattern.
Step 5: Wire a concrete action tool that needs sign-off
A real workflow proposes an external effect. Define a stub function and register it so the assistant can reference it, but the human still controls invocation.
def issue_refund(ticket_id: str, amount: float) -> str:
# Stub: replace with Stripe/Paddle call behind your authz layer
return f"REFUND_PENDING:{ticket_id}:{amount}"
user_proxy.register_function(
function_map={"issue_refund": issue_refund}
)
The assistant will emit a natural-language proposal referencing issue_refund. The human reads it, decides, and either types approval (which the proxy echoes) or edits the plan. The actual issue_refund call only fires if you explicitly invoke it from the proxy’s function map after approval—in this minimal setup we keep it dormant and let the human act out-of-band.
Step 6: Run the loop and inspect the handoff
Initiate the chat from the proxy so the human controls the first message.
chat_result = user_proxy.initiate_chat(
assistant,
message="Customer T-4821 hit the latency incident. Draft an apology and propose a refund.",
summary_method="last_msg",
)
print("Final message:", chat_result.summary)
Expected runtime behavior: the assistant responds with a drafted apology and a numbered refund step. The proxy prints that text and waits. Type y to continue, n to halt. If you type terminate, the is_termination_msg lambda ends the session.
Step 7: Verify the workflow end to end
Success criteria
A correct run satisfies all of these:
- The process pauses for stdin input after the assistant’s first response.
- The assistant’s proposal mentions
issue_refundby name but no refund is actually issued (noREFUND_PENDINGstring appears unless you called the stub). - Token usage is visible in the gateway dashboard or via the
usagefield in the underlying completion response, confirming per-token metering works through the OpenAI-compatible interface. - If you kill the network mid-run and restart, re-pointing at the same gateway resumes without changing agent code, because the model name and base URL are externalized.
Common failure modes
Model name mismatch. AutoGen passes model verbatim. If the gateway expects claude-opus-4-5 and you send claude-opus-4.5, you get a 404. Check the gateway’s model list.
Human input swallowed in pipes. input() fails under non-TTY CI. For headless verification, monkeypatch UserProxyAgent.get_human_input to return "y" and assert the loop terminates.
Usage not tracked. If you set api_type to something other than openai, AutoGen may skip usage parsing. Keep it openai for any OpenAI-compatible endpoint.
Fallback confusion. When the gateway retries across providers, request IDs change. Log the x-request-id from response headers if you need to trace a specific generation.
The pattern above scales to group chats: drop the same config_list into a GroupChatManager and insert a HumanInputAgent (or a second UserProxyAgent) wherever a checkpoint is required. The assistant and human roles stay fixed; only the orchestration graph grows.