Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

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

オープン
#9,130 コメント 0 件 リアクション 1 件 担当者 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
スター
13.9k
フォーク
2.4k
平均マージ
1日 19時間
マージ済み PR(30日)
439

環境構築

Codespaces で開く

このプロジェクトの開発コンテナを、あなたの GitHub アカウントでブラウザ上に起動します。

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

microsoft/agent-framework のほかの issue

microsoft/agent-framework の issue をすべて見る

似ている issue

Python の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。