Skip to content

The tool_confirmation window's data cannot be change. #3506

Closed

Description

@hongliang-nemovideo

Describe the bug
The confirm window's data cannot be reset.
I have multi tool_context.tool_confirmation operation in a conversion, after user submited the first confirm window, When the user triggers confirmation again, the data in the confirmation window remains unchanged.

Expected behavior
The confirmation window display the right data.

Screenshots

Image

Desktop (please complete the following information):

  • OS: [macOS]
  • Python version(3.11.9):
  • ADK version(1.18.0):

Model Information:

  • Are you using LiteLLM: Yes
  • Which model is being used(cloude 4.5)

Activity

  1. added
    web[Component] This issue will be transferred to adk-web
    on Nov 12, 2025
  2. added theissue type on Nov 12, 2025
  3. llalitkumarrr commented on Nov 12, 2025

    @llalitkumarrr
    Collaborator

    Hello @hongliang-nemovideo,

    Thank you for reaching out. Could you please share some additional details about your issue to help us understand it better? If possible, please include a minimal reproducible code example so that we can try to reproduce the issue and analyze it in more depth.

  4. added
    request clarification[Status] The maintainer need clarification or more information from the author
    on Nov 12, 2025
  5. hongliang-nemovideo commented on Nov 12, 2025

    @hongliang-nemovideo
    Author

    It is that within a single session, it will trigger multiple confirmations, and each confirmation has a different tool name and data. However, the pop-up on the frontend always displays the tool name and data of the first confirmation.

  6. llalitkumarrr commented on Nov 12, 2025

    @llalitkumarrr
    Collaborator

    Could you please share minimal reproducible code so that we can understand this issue better?

  7. hongliang-nemovideo commented on Nov 12, 2025

    @hongliang-nemovideo
    Author

    In a single session, multiple user queries will trigger confirmations, but the data in the confirmation windows from the second and subsequent confirmations are all from the first one. Sorry, the code is not suitable for pasting here. There are multiple confirmation tools under the agent.

  8. llalitkumarrr commented on Nov 14, 2025

    @llalitkumarrr
    Collaborator

    Ok, is it possible for you to share the reproduction steps to help us understand this better? Additionally could you please share the ADK version you are using and whether you are using LiteLLM or not?

  9. hongliang-nemovideo commented on Nov 14, 2025

    @hongliang-nemovideo
    Author

    Adk version is 1.8.0, and I'm using LiteLLM.

  10. llalitkumarrr commented on Nov 19, 2025

    @llalitkumarrr
    Collaborator

    Hello @hongliang-nemovideo ,

    We would require some more information on this so that we can try to reproduce, could please share some reproduction steps, it will help us analyze this issue better?

  11. hongliang-nemovideo commented on Nov 19, 2025

    @hongliang-nemovideo
    Author
    1. Create a new session
    2. Initiate a query that can trigger the adk_request_confirmation tool
    3. Open the confirmation form in the adk ui interface for confirmation
    4. Initiate another query that can trigger the adk_request_confirmation tool, this time with different confirmation data from the last one
    5. Open the confirmation form in the adk ui interface again
    6. At this point, the data in the confirmation form is still the first one, and it has not been updated
  12. llalitkumarrr commented on Nov 21, 2025

    @llalitkumarrr
    Collaborator

    Adk version is 1.8.0, and I'm using LiteLLM.

    Just to confirm, are you using 1.8.0 or 1.18.0 ADK version?

  13. hongliang-nemovideo commented on Nov 21, 2025

    @hongliang-nemovideo
    Author

    oh, sorry! It is 1.18.0 adk version.

  14. llalitkumarrr commented on Nov 21, 2025

    @llalitkumarrr
    Collaborator

    Have you tried using Gemini models out of Litellm or is this reproducible only with Litellm?

  15. hongliang-nemovideo commented on Nov 21, 2025

    @hongliang-nemovideo
    Author

    I only use cloude model, so I don't know how it will going without Litellm.

  16. gmbwork commented on Nov 27, 2025

    @gmbwork

    I’m facing the same issue. In my case, the agent checks the initial query to see if all required information is available. If something is missing, it triggers the request_user_clarification function. Each time the user provides more input, the agent checks again. If information is still missing, it asks for more details.
    What I’ve noticed is that the user input shown in the ADK web UI is not getting updated with the latest information each time request_user_clarification is called. Instead, it seems to be using cached data. Because of this, it keeps sending requests with the old function call ID. As a result, the agent keeps asking for more information, but the new user input is not being added on top of the previous details.
    This causes the tool-call pop-up to show outdated data, and it ends up in a loop where the user keeps providing information, but the agent never receives the correct, updated input.

    adk --version
    adk, version 1.19.0
    
    google-adk = "1.19.0"
    
    def request_user_clarification(
        question: str,
        context: str,
        tool_context: Optional[ToolContext]
    ) -> Dict[str, Any]:
        """
        Request clarification or missing information from user.
    
        Use when you need additional information to proceed:
        - Missing location/region
        - Unclear requirements
        - Need to choose from options
    
        Arguments:
        - question (str): Clear question for the user
        - context (str): Why you need this information
        """
        logger.info(f"  🔄 Clarification requested: {question}")
    
        if tool_context and tool_context.tool_confirmation and tool_context.tool_confirmation.confirmed:
            user_payload = tool_context.tool_confirmation.payload or {}
            logger.info(f"  ✅ User clarification received: {user_payload}")
            return {
                "user_answer": user_payload['answer'],
                "message": "User clarification received"
            }
    
        logger.info(f"  ⏸️  Pausing execution - waiting for user clarification")
    
        if tool_context:
            tool_context.request_confirmation(
                hint=f"CLARIFICATION NEEDED: {question}\nContext: {context}",
                payload={"answer": ""}
            )
    
        return {
            "confirmation_needed": True,
            "message": f"Waiting for clarification: {question}"
        }
    
    
    def request_human_approval(
        summary: str,
        context: str,
        tool_context: Optional[ToolContext]
    ) -> Dict[str, Any]:
        """
        Request human approval for a plan or action before proceeding.
    
        Use for high-impact decisions:
        - Campaign deployment
        - Budget allocation
        - Strategic decisions
        - Severe weather responses
    
        Arguments:
        - summary (str): Brief summary of what needs approval
        - context (str): Details about the approval request
        """
        logger.info(f"  🔄 Approval requested: {summary}")
    
        if tool_context and tool_context.tool_confirmation and tool_context.tool_confirmation.confirmed:
            user_payload = tool_context.tool_confirmation.payload or {}
            approved = user_payload.get("approved", False)
            logger.info(f"  ✅ User approval response: approved={approved}")
            return {
                "approved": approved,
                "user_response": user_payload,
                "message": "Approval decision processed"
            }
    
        logger.info(f"  ⏸️  Pausing execution - waiting for user approval")
    
        if tool_context:
            tool_context.request_confirmation(
                hint=f"APPROVAL REQUIRED:\n{summary}\n\nDetails:\n{context}",
                payload={"approved": False}
            )
    
        return {
            "confirmation_needed": True,
            "message": f"Waiting for approval: {summary}"
        }
    
    
    def create_hitl_tools() -> list:
        """
        Factory function to create HITL FunctionTools.
    
        Returns:
            List of FunctionTool instances for HITL interaction
    
        Usage:
            tools = create_hitl_tools()
            agent = Agent(..., tools=[*tools, mcp_toolset])
        """
        return [
            FunctionTool(func=request_user_clarification),
            FunctionTool(func=request_human_approval)
        ]
    
    def create_weather_agent() -> Agent:
       
        # Load system prompt
        try:
            instruction = load_system_prompt('weather')
            logger.info(f"   ✅ System prompt loaded")
        except Exception as e:
            logger.error(f"   ❌ Failed to load system prompt: {e}")
            raise
    
        # Create HITL tools
        hitl_tools = create_hitl_tools()
    
        # Create MCP toolset
        mcp_toolset = create_mcp_toolset(MCP_SERVER_URL, MCP_TOOLS)
        if mcp_toolset:
            logger.info(f"   ✅ MCP toolset connected to {MCP_SERVER_URL}")
        else:
            logger.warning(f"   ⚠️  MCP toolset not available (will use HITL only)")
    
        # Combine tools
        tools = [*hitl_tools]
        if mcp_toolset:
            tools.append(mcp_toolset)
    
        # Create agent
        agent = Agent(
            name=AGENT_NAME,
            model=LiteLlm(model=MODEL),
            description=AGENT_DESCRIPTION,
            instruction=instruction,
            tools=tools
        )
    
        logger.info(f"✅ {AGENT_NAME} created successfully")
        logger.info(f"   Model: {MODEL}")
        logger.info(f"   Total tools: {len(agent.tools)}")
    
        return agent
    
    
    try:
        weather_agent = create_weather_agent()
    except Exception as e:
        logger.error(f"❌ Failed to create weather_agent: {e}")
        weather_agent = None
    
    root_agent = weather_agent
    
    app = App(
        name="wather_app",
        root_agent=root_agent,
        resumability_config=ResumabilityConfig(
            is_resumable=True
        )
    )
    
  17. gmbwork commented on Nov 28, 2025

    @gmbwork

    When using [LongRunningFunctionTool] (via [tool_context.request_confirmation()]) for Human-in-the-Loop (HITL) interactions, the original adk_request_confirmation event is never updated to reflect that the user has provided a response. This causes:

    1. The ! (priority_high) FAB button to persist in the Dev UI after HITL completion
    2. Clicking the button shows stale HITL request with [confirmed: false] and empty payload/previously submitted payload
    3. Attempting to resubmit fails because it references an old/completed tool call ID

    Steps to Reproduce

    1. Create an agent with a [LongRunningFunctionTool] that uses [request_confirmation()]:
      `from google.adk.tools import FunctionTool
      from google.adk.tools.tool_context import ToolContext
    def request_user_clarification(
        question: str,
        context: str,
        tool_context: ToolContext
    ) -> dict:
        if tool_context.tool_confirmation and tool_context.tool_confirmation.confirmed:
            return {"user_answer": tool_context.tool_confirmation.payload.get('answer')}
        
        tool_context.request_confirmation(
            hint=f"Please answer: {question}",
            payload={"answer": ""}
        )
        return {"confirmation_needed": True}
    
    1. Run with ADK Dev UI: [adk web agent.py]
    2. Send a message that triggers the HITL tool
    3. Observe:
      • ! FAB button appears (correct)
      • adk_request_confirmation event created with [confirmed: false]
    4. Provide response via the HITL popup and submit
    5. Observe:
      • Workflow continues correctly
      • functionResponse event created
      • BUT: Original adk_request_confirmation event still shows [confirmed: false]
      • AND: ! FAB button persists
    6. Click the ! button again - it shows the OLD request with empty answer

    Expected Behavior
    After user provides HITL response:

    1. Original adk_request_confirmation event should be updated to [confirmed: true]
    2. The longRunningToolIds should be cleared from pending state
    3. The ! FAB button should disappear or change to indicate completion (✓)

    Actual Behavior
    After user provides HITL response:

    1. Original event remains [confirmed: false]❌
    2. longRunningToolIds still contains the completed tool ID ❌
    3. ! FAB button persists indefinitely ❌
    4. Clicking ! shows stale request ❌

    Evidence
    Event 2 (adk_request_confirmation) - AFTER user responded:

    {
      "content": {
        "parts": [{
          "functionCall": {
            "id": "adk-c42ce0f8-ea22-4894-96eb-858a3a0cb88a",
            "name": "adk_request_confirmation",
            "args": {
              "toolConfirmation": {
                "confirmed": false,  // ❌ Still false after user responded
                "payload": {"answer": ""}  // ❌ Still empty
              }
            }
          }
        }]
      },
      "actions": {
        "longRunningToolIds": ["adk-c42ce0f8-ea22-4894-96eb-858a3a0cb88a"]  // ❌ Not cleared
      }
    }
    

    Event 3 (functionResponse) - User's actual response:

    {
      "content": {
        "parts": [{
          "functionResponse": {
            "name": "request_user_clarification",
            "response": {"user_answer": "Phoenix, 2025-11-28 to 2025-11-30"}
          }
        }]
      }
    }
    

    The workflow continues correctly using Event 3, but the Dev UI still sees Event 2 as "pending".

    Impact

    • User Confusion: Users think there's still a pending HITL request
    • Resubmission Errors: Attempting to resubmit references invalid tool call ID
    • Poor UX: No visual feedback that HITL was successfully processed

    Workaround
    Currently, users must:

    1. Ignore the ! button after responding
    2. Create a new session for each conversation
    3. Rely on workflow continuation as confirmation of success

    Suggested Fix
    One of these approaches:

    Option A: Update Original Event
    When functionResponse is received for a longRunningToolIds tool, update the original adk_request_confirmation event:

    original_event.args["toolConfirmation"]["confirmed"] = True
    original_event.args["toolConfirmation"]["payload"] = user_response
    

    Option B: Track Resolution Separately
    Maintain a separate resolvedToolIds set and have Dev UI check both:
    is_pending = tool_id in longRunningToolIds and tool_id not in resolvedToolIds

    Option C: Dev UI Logic Fix
    Modify Dev UI to check for subsequent functionResponse events that match the longRunningToolIds:

    const isPending = event.longRunningToolIds?.some(id => 
      !events.some(e => e.functionResponse?.id === id)
    );
    
  18. added
    needs review[Status] The PR/issue is awaiting review from the maintainer
    on Dec 19, 2025
  19. GWeale commented on Oct 7, 2026

    @GWeale
    Collaborator

    fixed by google/adk-web@a2a337d, which replaced the confirmation dialog with an inline prompt per tool call, so a second confirmation no longer shows the first one's data. shipped in v1.27.0. please open a new issue if this is still happening.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

needs review[Status] The PR/issue is awaiting review from the maintainerrequest clarification[Status] The maintainer need clarification or more information from the authorweb[Component] This issue will be transferred to adk-web

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions