Repository navigation
Labels
agentsUsage: [Issues, PRs], Target: Single agentUsage: [Issues, PRs], Target: Single agentbugUsage: [Issues], Target: all issues (Legacy, prefer issue type: bug)Usage: [Issues], Target: all issues (Legacy, prefer issue type: bug)pythonUsage: [Issues, PRs], Target: PythonUsage: [Issues, PRs], Target: Python
Description
Description
When a sub-agent is used via .as_tool() and its inner tool requires approval_mode="always_require", the approval request correctly propagates to the caller. However, sending the approval response back and resuming does not work. The inner tool is never executed.
Code Sample
async def nonstreaming():
chat_client = SomeChatClient()
@tool(approval_mode="always_require")
def get_weather_detail(location: Annotated[str, "The city and state, e.g. San Francisco, CA"]) -> str:
answer = f"The weather in {location} is cloudy with a high of 15°C, humidity 88%."
return answer
# Create weather assistant as inner agent
inner_agent = chat_client.as_agent(
instructions="You are a helpful assistant that provides weather information to users.",
description="Agent that provides weather information.",
name="weather_agent",
tools=[get_weather_detail],
)
# Create main Agent that uses inner agent as tool
outer_agent = chat_client.as_agent(
instructions=(
"You are a helpful coordinator. When a user asks about weather, "
"use the weather_agent_tool to get the information."
),
description="Coordinator agent that delegates to the weather agent tool.",
name="coordinator_agent",
tools=[
inner_agent.as_tool(
name="weather_agent_tool",
description="A weather agent tool that provides current weather information for any given location.",
approval_mode='never_require'
)
],
)
user_input = "What's the weather like in Amsterdam?"
session = outer_agent.create_session()
response = await outer_agent.run(user_input, session=session)
new_inputs: list[Message] = []
if response.user_input_requests:
for req in response.user_input_requests:
print(f'User input requested - Func name: {req.function_call.name}, Args: {req.function_call.arguments}')
new_inputs.append(Message("user", [req.to_function_approval_response(True)]))
print("\nRunning agent with new inputs after approvals...\n")
response2 = await outer_agent.run(new_inputs, session=session)
print(f"Final response: {response2}")Error Messages / Stack Traces
Result:
User input requested - Func name: get_weather_detail, Args: {"location":"Amsterdam, Netherlands"}
Running agent with new inputs after approvals...
Final response: I'm fetching the current weather in Amsterdam for you. One moment!
Here is the output when the tool approval model is set to `never_require`
Running agent with new inputs after approvals...
Final response: The current weather in Amsterdam is cloudy, with a high of 15°C and a humidity level of 88%.Package Versions
agent-framework-core: 1.0.0rc5
Python Version
Python 3.12.12
Additional Context
- The bug occurred in both streaming and non-streaming mode.
- Tested on
Workflow.as_tool(), doesn't work either.
Metadata
Metadata
Assignees
Labels
agentsUsage: [Issues, PRs], Target: Single agentUsage: [Issues, PRs], Target: Single agentbugUsage: [Issues], Target: all issues (Legacy, prefer issue type: bug)Usage: [Issues], Target: all issues (Legacy, prefer issue type: bug)pythonUsage: [Issues, PRs], Target: PythonUsage: [Issues, PRs], Target: Python
Type
Projects
- StatusShow more project fieldsDone
Activity
Fix sub-agent approval routing for as_tool() (microsoft#4963)
Address review feedback for sub-agent approval routing (microsoft#4963)
Fix pyright reportMissingImports for orjson in sample files (microsof…
Address review feedback for microsoft#4963: Python: [Bug]: Cannot app…
SuperMarimoBros commentedon Sep 11, 2026
I can reproduce this on the current Python packages with a minimal nested-Skill variant.
Setup:
Agentexposes a childAgentthroughchild.as_tool(..., approval_mode="always_require").SkillsProviderwith anInlineSkill.load_skill; its approval request is visible through the child stream callback, but it is not surfaced inouter_result.user_input_requests.The outer tool approval is returned and can be approved. The child starts, then its
load_skillapproval cannot be answered by the caller. The child run stops withTool requires user input to proceed.I observed the same primary failure with both clients:
OpenAIChatCompletionClientnote_workertool call has no matching tool responseOpenAIChatClientChatClientInvalidRequestException: Messages are required for chat completionsVersions:
agent-framework==1.18.0agent-framework-openai==1.14.3openai==2.54.0This appears to be the same approval-routing/resume gap as this issue, now reproduced through the built-in Skills path as well. The missing user-visible approval is the child Skill tool (
load_skill), while the Chat Completions 400 is a subsequent missing outer tool-result pair.Python: fix(core): correctly resolve, batch, and chain nested agent-a…
eavanvalkenburg commentedon Sep 18, 2026
We have chosen a deliberately smaller contract for this scenario, implemented in #8527.
Agent.as_tool()is intended for delegated calls that can complete within the current invocation. When a child tool requires approval:ToolApprovalMiddleware(auto_approval_rules=[...]);Approvals involving a person, a long wait, persistence, external coordination, cancellation, or process restarts should be modeled as a Workflow pause and resume. The PR includes a sample showing the same scenario first with an immediate
Agent.as_tool()policy and then with durable Workflow approval.We considered transparent propagation through the caller, application callbacks, and resumable child continuations. Those approaches require a broader contract for ownership, persistence, provider transcripts, cancellation, and nested or parallel calls. They are not necessary to fix this bug safely.
#8527 contains
Fixes #4963, so this issue will close automatically when the PR merges. If there is demand for transparent or resumable nested-agent approvals beyond this contract, please open a separate feature issue describing that use case and its required lifetime semantics rather than extending this bug.