Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

.NET: [Feature]: .NET: resumable human approvals for agents used as tools (AsAIFunction)

未关闭
#9,130 0 条评论 1 个 reaction 已指派 1 人 在 GitHub 查看

维护者通常 1 天内回复

@rogerbarreto 已经在做这个了。

开始于 2026年10月7日。

评估

这个 Issue 还没有评估数据。

描述

.NET agents
Description

Following up on #4963, where the maintainers suggested opening a separate feature issue for resumable nested-agent approvals.

Problem. A primary agent that delegates subtasks to other agents as tools (agent-as-tools, AIAgent.AsAIFunction) cannot complete a subtask whose inner tool needs human approval (ApprovalRequiredAIFunction). The inner agent's ToolApprovalRequestContent never reaches the caller, so the delegated call can only fail. Handoff and group chat workflows do surface approvals, but they change the model: control and the full conversation pass to the other agent, and the primary agent no longer delegates a subtask and continues with its result. For hosts where a primary agent coordinates several specialist agents over many turns, and the specialists see only what they are sent, call and return with a human approval in the middle is the missing combination.

Expected behavior. When an agent invoked as a tool pauses for approval, the primary agent's response carries an approval request the caller can answer with the existing approval flow. On approval, the delegated call resumes the inner agent with the decision and returns its result to the primary agent's tool loop. On rejection, the inner tool never runs.

What we found prototyping it on Microsoft.Agents.AI 1.16 / Microsoft.Extensions.AI 10.8 with public APIs only (UseProvidedChatClientAsIs, UseApprovalResponseBinding, UseApprovalNotRequiredFunctionBypassing, UseFunctionInvocation):

  • A chat-client step between approval-response binding and the approval-not-required bypass can turn a paused delegated call into an approval request for the same call id. Function invocation then re-invokes the delegated function on approval, and binding validates the response.
  • Placement is critical. Below the bypass, the bypass removes the request (the delegating function needs no approval of its own) and re-injects it as approved on the next turn, so the inner tool runs with no human decision.
  • A function cannot stop the loop by throwing: FunctionInvocationProcessor records a thrown call with terminate: false, so the model is called again with "Error: Function failed." The function has to return a pause value and set FunctionInvocationContext.Terminate.
  • Other calls in the same batch need a synthesized result once the loop stops, or the history holds a call with no result.
  • Opting out of the default stack also drops the internal deferred telemetry slot, so a custom stack must add its own OpenTelemetry client below function invocation.

Each of these is easy to get wrong in host code, and the placement one fails open. A framework-owned option would close that risk.

Possible shape. An opt-in on AsAIFunction (or AIFunctionFactoryOptions), or a public decorator for custom stacks, that propagates an inner agent's approval requests and resumes the inner agent with the caller's decision. The inner agent's paused state would be held in its session, which the caller already passes to AsAIFunction.

Alternatives considered. Handoff or group chat workflows (they change ownership and context, as above). Failing closed per #4963 (safe, but agent-as-tools then cannot take gated actions at all).

Code Sample
AIAgent specialist = new ChatClientAgent(chatClient, new ChatClientAgentOptions
{
    Name = "specialist",
    ChatOptions = new() { Tools = [new ApprovalRequiredAIFunction(AIFunctionFactory.Create(ProcessRefund))] },
});

AIAgent primary = new ChatClientAgent(chatClient, new ChatClientAgentOptions
{
    Name = "primary",
    // Hypothetical option, shown as the desired shape; it does not exist today.
    ChatOptions = new() { Tools = [specialist.AsAIFunction(new() { PropagateApprovals = true }, specialistSession)] },
});

var response = await primary.RunAsync("Refund order 1234", session);
var request = response.Messages.SelectMany(m => m.Contents).OfType<ToolApprovalRequestContent>().Single();
var resumed = await primary.RunAsync(new ChatMessage(ChatRole.User, [request.CreateResponse(approved: true)]), session);
Language/SDK

.NET

主要语言
Python
星标
14k
派生
2.5k
平均合并
2 天 11 小时
30 天内合并 PR
407

环境准备

在 Codespaces 中打开

在浏览器里用你自己的 GitHub 账号启动这个项目的开发容器。

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

microsoft/agent-framework 的其他 Issue

查看 microsoft/agent-framework 的全部 Issue

相似的 Issue

更多 Python Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。