Skip to content

Add tool approval middleware for HITL parity - #138

Merged
Quim Muntal (qmuntal) merged 9 commits into
mainfrom
dev/gadams/hitl
May 7, 2026
Merged

Add tool approval middleware for HITL parity#138
Quim Muntal (qmuntal) merged 9 commits into
mainfrom
dev/gadams/hitl

Conversation

@gdams

Copy link
Copy Markdown
Member

Summary

Adds a toolapproval middleware package for .NET ToolApprovalAgent parity, closing the primary Human-in-the-Loop gap identified in the feature comparison.

New: agent/middleware/toolapproval

  • Implements the .NET ToolApprovalAgent pattern as idiomatic Go middleware
  • One-at-a-time surfacing: When the inner agent returns multiple approval requests, only the first is surfaced to the caller; the rest are queued in session state
  • Standing rules ("don't ask again"): Callers can respond with AlwaysApproveToolResponse() or AlwaysApproveToolWithArgsResponse() to create rules that auto-approve matching future tool calls for the session lifetime
  • Auto-approve loop: When all approval requests match standing rules, the middleware automatically approves them and re-calls the inner agent without surfacing anything to the caller
  • Session persistence: Rules, queued requests, and collected responses are persisted across turns via agent.Session

Changes to message package

  • Added AlwaysApproveTool and AlwaysApproveToolWithArgs fields to FunctionApprovalResponseContent
  • Added AlwaysApproveToolResponse() and AlwaysApproveToolWithArgsResponse() convenience methods on FunctionApprovalRequestContent

Tests

  • Passthrough (no approval requests)
  • First request surfacing with queuing
  • Always-approve tool rule creation and auto-approval
  • Queued requests surfaced one at a time
  • AlwaysApproveToolWithArgs response creation

Copilot AI review requested due to automatic review settings May 6, 2026 16:04
@gdams
George Adams (gdams) requested a review from a team as a code owner May 6, 2026 16:04
@github-actions

This comment has been minimized.

@gdams

This comment has been minimized.

Copilot AI commented May 6, 2026

Copy link
Copy Markdown
Contributor

Cross-repo Parity Review — toolapproval middleware

This PR successfully fills the primary HITL gap and the overall logic (one-at-a-time surfacing, standing rules, queued drain, auto-appr...

Addressed in 72df83e (with follow-up nits in 07b6d7f and 8dc0de1). I switched always-approve to a dedicated wrapper content type (AlwaysApproveToolApprovalResponseContent) that middleware unwraps before forwarding, added AlwaysApproveToolWithArgumentsResponse, and made tool+args rule matching order-independent by canonicalizing JSON arguments before comparison.

@github-actions

This comment has been minimized.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generated by Go API Consistency Review Agent for issue #138 · ● 704.8K

Comment thread agent/middleware/toolapproval/toolapproval.go Outdated

@qmuntal Quim Muntal (qmuntal) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! Some minor comments,

Comment thread agent/middleware/toolapproval/toolapproval.go Outdated
Comment thread agent/middleware/toolapproval/toolapproval.go Outdated
Comment thread message/content.go Outdated
@gdams

Copy link
Copy Markdown
Member Author

Copilot linter failures

Copilot AI commented May 7, 2026

Copy link
Copy Markdown
Contributor

Copilot linter failures

Fixed in acd2ffe. I traced the failing workflow run (25461521092) and addressed the gofumpt error by grouping the toolapproval constants into a single const block.

Comment thread agent/middleware/toolapproval/toolapproval.go Outdated
Comment thread agent/middleware/toolapproval/toolapproval.go Outdated
Comment thread agent/middleware/toolapproval/toolapproval.go Outdated
Comment thread agent/middleware/toolapproval/toolapproval.go Outdated
@gdams

Copy link
Copy Markdown
Member Author

Copilot resolve this merge conflict

George Adams (gdams) and others added 5 commits May 7, 2026 08:27
- Add toolapproval middleware (agent/middleware/toolapproval) implementing
  the .NET ToolApprovalAgent pattern: surfaces approval requests one at a
  time, queues remaining requests in session state, and supports standing
  'don't ask again' rules that auto-approve matching tool calls
- Add AlwaysApproveTool and AlwaysApproveToolWithArgs fields to
  FunctionApprovalResponseContent for standing rule signaling
- Add AlwaysApproveToolResponse() and AlwaysApproveToolWithArgsResponse()
  convenience methods on FunctionApprovalRequestContent
- Add tests for passthrough, surfacing, queuing, always-approve rules
@github-actions

github-actions Bot commented May 7, 2026

Copy link
Copy Markdown
Contributor

Cross-Repo Consistency Review

Summary

The core toolapproval middleware concept is consistent with upstream .NETToolApprovalRequestContent and ToolApprovalResponseContent are first-class types in the .NET AIAgentHostExecutor (see dotnet/src/Microsoft.Agents.AI.Workflows/Specialized/AIAgentHostExecutor.cs), and the Go middleware correctly wraps them. No Python equivalent was found.

Parity Gap: AlwaysApproveToolApprovalResponseContent and standing rules

The new AlwaysApproveToolApprovalResponseContent type (exported from message) and the standing-rules pattern (always-approve-tool / always-approve-with-args) introduced in this PR have no counterpart in the upstream .NET or Python implementations. The .NET AIAgentHostExecutor surfaces ToolApprovalRequestContent and ToolApprovalResponseContent to the workflow graph for routing, but does not expose any "don't ask again" / standing-rule mechanism on those types.

This is a new public Go type exported from the message package:

type AlwaysApproveToolApprovalResponseContent struct {
    AlwaysApproveTool              bool
    AlwaysApproveToolWithArguments bool
    InnerResponse                  *ToolApprovalResponseContent
}

And new public methods on ToolApprovalRequestContent:

  • AlwaysApproveToolResponse() *AlwaysApproveToolApprovalResponseContent
  • AlwaysApproveToolWithArgumentsResponse() *AlwaysApproveToolApprovalResponseContent
  • AlwaysApproveToolWithArgsResponse() (deprecated alias)

Recommendation: Since this is a meaningful public API extension that isn't present in .NET or Python, the upstream team should be aware so they can decide whether to add an analogous standing-rule concept to the other SDKs. If this is intentionally a Go-first feature, that intent should be documented in the PR/commit.

Other observations

  • The Config struct is exported but empty — this appears intentional for forward-compatibility and is reasonable.
  • The session-based state persistence approach (agent.Session) is the correct Go idiom and is semantically equivalent to how .NET persists this state during workflow checkpointing.
  • No example was added in examples/ for the new middleware, while .NET has samples in dotnet/samples/ for the HITL pattern. Consider adding a usage example for consistency.

Generated by Go API Consistency Review Agent for issue #138 · ● 2.1M ·

@qmuntal
Quim Muntal (qmuntal) merged commit 97e0143 into main May 7, 2026
11 checks passed
@qmuntal
Quim Muntal (qmuntal) deleted the dev/gadams/hitl branch May 7, 2026 07:48
github-actions Bot added a commit that referenced this pull request May 7, 2026
…-in-workflow parity

- Mark 'Tool approval' as Aligned: Go now has agent/middleware/toolapproval
  (PR #138) implementing the .NET ToolApprovalAgent pattern with standing
  rules, queued-request batching, and AlwaysApprove* response content.
- Mark 'Agent in workflow' as Aligned: Go's workflowhosting.Config already
  has InterceptUserInputRequests and InterceptUnterminatedFunctionCalls,
  matching the .NET AIAgentHostOptions surface.
- Add agent/middleware/toolapproval to the Go Feature Checklist.
- Bump doc date to May 7, 2026.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Quim Muntal (qmuntal) added a commit that referenced this pull request May 7, 2026
…in-workflow parity (#164)

* docs: update feature comparison for toolapproval middleware and agent-in-workflow parity

- Mark 'Tool approval' as Aligned: Go now has agent/middleware/toolapproval
  (PR #138) implementing the .NET ToolApprovalAgent pattern with standing
  rules, queued-request batching, and AlwaysApprove* response content.
- Mark 'Agent in workflow' as Aligned: Go's workflowhosting.Config already
  has InterceptUserInputRequests and InterceptUnterminatedFunctionCalls,
  matching the .NET AIAgentHostOptions surface.
- Add agent/middleware/toolapproval to the Go Feature Checklist.
- Bump doc date to May 7, 2026.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants