Skip to content

Python: [AG-UI] Tool not executed after approval in Human-in-the-loop #3034

@TsukasaIshimura

Description

@TsukasaIshimura

We are building a web app using Microsoft Agent Framework AG-UI and CopilotKit.
We are trying out the Human-in-the-loop feature based on the samples below. However, after approving tool execution, it appears the tool is not actually executed.
We would appreciate any advice.

https://learn.microsoft.com/ja-jp/agent-framework/integrations/ag-ui/getting-started?pivots=programming-language-python
https://learn.microsoft.com/ja-jp/agent-framework/integrations/ag-ui/testing-with-dojo?pivots=programming-language-python
https://dojo.ag-ui.com/microsoft-agent-framework-python/feature/human_in_the_loop?file=dojo.py
https://github.com/CopilotKit/with-microsoft-agent-framework-python/tree/main

  • Backend source code
from __future__ import annotations

import logging
import os
from typing import Any

import uvicorn
from agent_framework import ChatAgent, ai_function
from agent_framework.azure import AzureOpenAIChatClient
from agent_framework_ag_ui import (AgentFrameworkAgent,
                                   add_agent_framework_fastapi_endpoint)
from azure.identity import AzureCliCredential
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware


chat_client = AzureOpenAIChatClient(credential=AzureCliCredential())

app = FastAPI(title="CopilotKit + Microsoft Agent Framework (Python)")
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)


@ai_function(
    name="get_datetime",
    description="Get the current date and time",
    approval_mode="always_require",
)
def get_datetime() -> str:
    print("★★★ get_datetime called ★★★")  # This message is not output.
    return "2025/12/01 12:00:00"


base_agent = ChatAgent(
    name="HumanInTheLoopAgent",
    instructions="You are a helpful AI Agent.",
    chat_client=chat_client,
    tools=[get_datetime],
)

add_agent_framework_fastapi_endpoint(
    app=app,
    agent=AgentFrameworkAgent(
        agent=base_agent,
        name="HumanInTheLoopAgent",
        description="Helpful AI Agent",
        require_confirmation=True,
    ),
    path="/api/v1/agents/human-in-the-loop-agent",
)


if __name__ == "__main__":
    host = os.getenv("AGENT_HOST", "0.0.0.0")
    port = int(os.getenv("AGENT_PORT", "8000"))
    uvicorn.run("main:app", host=host, port=port, reload=True)
  • Frontend source code
'use client';

import { useState } from 'react';

import { CopilotKit, useHumanInTheLoop } from '@copilotkit/react-core';
import { CopilotChat } from '@copilotkit/react-ui';

const HumanInTheLoop = () => {
  return (
    <CopilotKit runtimeUrl="/master-agent/api/copilotkit" agent="human_in_the_loop_agent">
      <CopilotKitPage />
    </CopilotKit>
  );
};

const CopilotKitPage = () => {
  useHumanInTheLoop({
    name: 'get_datetime',
    description: 'Get the current date and time',
    parameters: [],
    render: ({ status, respond }) => {
      return <GetDatetimeCard status={status} respond={respond} />;
    },
  });

  return (
    <main>
      <div className="flex h-full w-full items-center justify-center" data-testid="background-container">
        <div className="h-full w-full rounded-lg md:h-8/10 md:w-8/10">
          <CopilotChat
            className="mx-auto h-full max-w-6xl rounded-2xl"
            labels={{ initial: "Hi, I'm an agent specialized in helping you with your tasks. How can I help you?" }}
          ></CopilotChat>
        </div>
      </div>
    </main>
  );
};

interface GetDatetimeCardProps {
  status: 'inProgress' | 'executing' | 'complete';
  respond?: (response: { accepted: boolean }) => void;
}

const GetDatetimeCard = ({ status, respond }: GetDatetimeCardProps) => {
  const [decision, setDecision] = useState<'allowed' | 'aborted' | null>(null);

  const handleAllow = () => {
    setDecision('allowed');
    respond?.({ accepted: true });
  };

  const handleAbort = () => {
    setDecision('aborted');
    respond?.({ accepted: false });
  };

  return (
    <div className="mt-6 w-full max-w-md rounded-2xl bg-cyan-500 shadow-xl">
      <div className="w-full rounded-2xl bg-white/20 p-8 backdrop-blur-md">
        {/* Show decision or prompt */}
        {decision === 'allowed' ? (
          <div className="text-center">
            <h2 className="mb-2 text-2xl font-bold text-white">🚀 Allowed</h2>
          </div>
        ) : decision === 'aborted' ? (
          <div className="text-center">
            <h2 className="mb-2 text-2xl font-bold text-white">✋ Aborted</h2>
          </div>
        ) : (
          <>
            <div className="mb-6 text-center">
              <h2 className="mb-2 text-2xl font-bold text-white">
                Would you like to allow the date and time retrieval tool to run?
              </h2>
            </div>

            {status === 'executing' && (
              <div className="flex gap-3">
                <button
                  onClick={handleAllow}
                  className="flex-1 rounded-xl bg-white px-6 py-4 font-bold text-black shadow-lg transition-all hover:scale-105 hover:shadow-xl active:scale-95"
                >
                  🚀 Allow!
                </button>
                <button
                  onClick={handleAbort}
                  className="flex-1 rounded-xl border-2 border-white/30 bg-black/20 px-6 py-4 font-bold text-white shadow-lg transition-all hover:scale-105 hover:bg-black/30 active:scale-95"
                >
                  ✋ Abort
                </button>
              </div>
            )}
          </>
        )}
      </div>
    </div>
  );
};

export default HumanInTheLoop;
  • Expected and actual results after approval

Expected result:
"★★★ get_datetime called ★★★" is output to the log.
The current time should be displayed on the screen.

Actual result:
"★★★ get_datetime called ★★★" is not output to the log.
The message "Changes confirmed and applied successfully!" is displayed on the screen.

  • Screenshots
Image Image
  • Log after pressing the approval button
DEBUG:agent_framework_ag_ui._endpoint:[/api/v1/agents/human-in-the-loop-agent] Received request - Run ID: no-run-id, Thread ID: no-thread-id, Messages: 3
INFO:agent_framework_ag_ui._endpoint:Received request at /api/v1/agents/human-in-the-loop-agent: no-run-id
INFO:     172.20.2.3:56026 - "POST /api/v1/agents/human-in-the-loop-agent HTTP/1.1" 200 OK
INFO:agent_framework_ag_ui._orchestrators:=== TOOL RESULT DETECTED (HumanInTheLoopOrchestrator) ===
DEBUG:agent_framework_ag_ui._endpoint:[/api/v1/agents/human-in-the-loop-agent] Event 1: RunStartedEvent
DEBUG:agent_framework_ag_ui._endpoint:[/api/v1/agents/human-in-the-loop-agent] Event payload: {'type': <EventType.RUN_STARTED: 'RUN_STARTED'>, 'thread_id': 'afb6667a-3fa1-44d9-aef5-1315f4698c0f', 'run_id': 'b46880dc-fb66-48f8-8a9d-2c0ce079ebf7'}
DEBUG:agent_framework_ag_ui._endpoint:[/api/v1/agents/human-in-the-loop-agent] Encoded as: data: {"type":"RUN_STARTED","threadId":"afb6667a-3fa1-44d9-aef5-1315f4698c0f","runId":"b46880dc-fb66-48f8-8a9d-2c0ce079ebf7"}


INFO:agent_framework_ag_ui._orchestrators:  Accepted: True
INFO:agent_framework_ag_ui._orchestrators:  Steps count: 0
DEBUG:agent_framework_ag_ui._endpoint:[/api/v1/agents/human-in-the-loop-agent] Event 2: TextMessageStartEvent
DEBUG:agent_framework_ag_ui._endpoint:[/api/v1/agents/human-in-the-loop-agent] Event payload: {'type': <EventType.TEXT_MESSAGE_START: 'TEXT_MESSAGE_START'>, 'message_id': 'bc348bc0-7b7e-4f0a-9a20-68367a96ba2f', 'role': 'assistant'}
DEBUG:agent_framework_ag_ui._endpoint:[/api/v1/agents/human-in-the-loop-agent] Encoded as: data: {"type":"TEXT_MESSAGE_START","messageId":"bc348bc0-7b7e-4f0a-9a20-68367a96ba2f","role":"assistant"}


DEBUG:agent_framework_ag_ui._endpoint:[/api/v1/agents/human-in-the-loop-agent] Event 3: TextMessageContentEvent
DEBUG:agent_framework_ag_ui._endpoint:[/api/v1/agents/human-in-the-loop-agent] Event payload: {'type': <EventType.TEXT_MESSAGE_CONTENT: 'TEXT_MESSAGE_CONTENT'>, 'message_id': 'bc348bc0-7b7e-4f0a-9a20-68367a96ba2f', 'delta': 'Changes confirmed and applied successfully!'}
DEBUG:agent_framework_ag_ui._endpoint:[/api/v1/agents/human-in-the-loop-agent] Encoded as: data: {"type":"TEXT_MESSAGE_CONTENT","messageId":"bc348bc0-7b7e-4f0a-9a20-68367a96ba2f","delta":"Changes confirmed and applied successfully!"}


DEBUG:agent_framework_ag_ui._endpoint:[/api/v1/agents/human-in-the-loop-agent] Event 4: TextMessageEndEvent
DEBUG:agent_framework_ag_ui._endpoint:[/api/v1/agents/human-in-the-loop-agent] Event payload: {'type': <EventType.TEXT_MESSAGE_END: 'TEXT_MESSAGE_END'>, 'message_id': 'bc348bc0-7b7e-4f0a-9a20-68367a96ba2f'}
DEBUG:agent_framework_ag_ui._endpoint:[/api/v1/agents/human-in-the-loop-agent] Encoded as: data: {"type":"TEXT_MESSAGE_END","messageId":"bc348bc0-7b7e-4f0a-9a20-68367a96ba2f"}


DEBUG:agent_framework_ag_ui._endpoint:[/api/v1/agents/human-in-the-loop-agent] Event 5: RunFinishedEvent
DEBUG:agent_framework_ag_ui._endpoint:[/api/v1/agents/human-in-the-loop-agent] Event payload: {'type': <EventType.RUN_FINISHED: 'RUN_FINISHED'>, 'thread_id': 'afb6667a-3fa1-44d9-aef5-1315f4698c0f', 'run_id': 'b46880dc-fb66-48f8-8a9d-2c0ce079ebf7'}
DEBUG:agent_framework_ag_ui._endpoint:[/api/v1/agents/human-in-the-loop-agent] Encoded as: data: {"type":"RUN_FINISHED","threadId":"afb6667a-3fa1-44d9-aef5-1315f4698c0f","runId":"b46880dc-fb66-48f8-8a9d-2c0ce079ebf7"}


INFO:agent_framework_ag_ui._endpoint:[/api/v1/agents/human-in-the-loop-agent] Completed streaming 5 events
  • Version information

Python 3.13.10
agent-framework-ag-ui==1.0.0b251211
agent-framework-core==1.0.0b251211

Thank you in advance.

Metadata

Metadata

Assignees

Type

Projects

Status

In Review

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions