.NET: [Feature]: .NET: resumable human approvals for agents used as tools (AsAIFunction)
メンテナーはふだん 1 日以内に返信
@rogerbarreto がすでに取り組んでいます。
2026年10月7日 から。
評価
この issue はまだ評価されていません。
説明
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:
FunctionInvocationProcessorrecords a thrown call withterminate: false, so the model is called again with "Error: Function failed." The function has to return a pause value and setFunctionInvocationContext.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
環境構築
このプロジェクトの開発コンテナを、あなたの GitHub アカウントでブラウザ上に起動します。
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートあり
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
microsoft/agent-framework のほかの issue
-
.NET python triage
難易度 1/5 1時間未満 初心者へのやさしさ 85/100
microsoft/agent-framework#9092 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
Python: raw-data content mappings lose annotations and attachment metadata対応中かも @moonbox3 が 10 日前に担当しました。 オープンpython triage
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
microsoft/agent-framework#8632 · コメント 2 件 ·
メンテナーはふだん 1 日以内に返信
-
Python: Clarify when to use platform対応中かも @eavanvalkenburg が 9 日前に担当しました。 オープンpython triage
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
microsoft/agent-framework#8599 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
.NET Compaction - Update docs to refer to `AIContextProvider` deep dive対応中かも このイシューにリンクされたプルリクエストがオープン中、またはマージ済みです。 オープン.NET compaction documentation
難易度 1/5 1時間未満 初心者へのやさしさ 82/100
microsoft/agent-framework#4629 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
Python: [Feature]: Official first-class TypeScript SDK support対応中かも @rogerbarreto が 1 日前に担当しました。 オープン.NET agents python
microsoft/agent-framework#9226 · 担当者 1 名 ·
メンテナーはふだん 1 日以内に返信
microsoft/agent-framework の issue をすべて見る
似ている issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 62/100
メンテナーはふだん 1 日以内に返信
-
enhancement good first issue Stellar Wave trivial
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
StellarCanary/ProtocolCanary-Fixtures#258 ·
メンテナーはふだん 1 日以内に返信
-
enhancement
難易度 2/5 1〜3時間 初心者へのやさしさ 70/100
IBM/ai-atlas-nexus#295 ·
メンテナーはふだん 6 日以内に返信
-
github_actions
難易度 2/5 1〜3時間 初心者へのやさしさ 65/100
Hochfrequenz/aibap.mcp#578 ·
メンテナーはふだん 1 日以内に返信
-
bug
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
mishraprafful/multihull#150 ·
メンテナーはふだん 1 日以内に返信