Skip to content

Support tool middleware in third-party providers - #1159

Merged
Quim Muntal (qmuntal) merged 1 commit into
mainfrom
qmuntal/provider-tool-middleware
Sep 22, 2026
Merged

Quim Muntal (qmuntal) merged 1 commit into
mainfrom
qmuntal/provider-tool-middleware

Conversation

@qmuntal

Copy link
Copy Markdown
Member

Summary

Third-party providers cannot import the internal wrapper used for function invocation middleware. Add ProviderConfig.ManagesToolExecution so the agent wraps WithTool function tools immediately before the provider's Run, after provider middleware, without changing caller-owned options.

Expose agent.WithFuncCallID for provider-owned callbacks and enable the capability in Copilot. Automatic tool execution keeps its existing internal wrapping for request tools and AdditionalTools.

Add regression tests for capability opt-in, dynamic tools, middleware composition and short-circuiting, call IDs, schema and approval preservation, unchanged options, and repeated invocations.

Validation

  • Passed agent, toolautocall, and agentmode unit suites.
  • Passed focused Copilot and OpenAI middleware tests and Copilot session configuration tests.
  • Go formatting and staged whitespace checks passed.
  • E2E and replay-harness tests were not run.

Add ProviderConfig.ManagesToolExecution so providers receive function
tools wrapped with middleware without importing internal packages.
Apply wrapping immediately before the provider runs while preserving
the options seen by outer middleware.

Expose WithFuncCallID for provider-owned invocations and enable the
capability in Copilot. Keep harness wrapping for additional tools.

Test capability opt-in, dynamic tools, middleware behavior, option
preservation, and repeated invocations.
@qmuntal
Quim Muntal (qmuntal) requested a review from a team as a code owner September 22, 2026 15:32
Copilot AI lite review requested due to automatic review settings September 22, 2026 15:32
@github-actions github-actions Bot added area:agent Changes files in the agent area area:provider Changes files in the provider area area:provider/copilot Changes files in the provider / copilot area size:xlarge More than 300 changed lines or 10 files labels Sep 22, 2026

Copilot AI 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.

Copilot review overview

🟢 Approval recommended

No unresolved review comments remain.

Review effort: Lite
Findings: None

What changed in this PR

Adds provider-managed tool execution middleware support for third-party providers, including Copilot integration and public function call IDs.

Changes:

  • Adds ManagesToolExecution and non-mutating function-tool wrapping.
  • Exposes WithFuncCallID and updates Copilot/autocall execution.
  • Adds regression coverage for middleware, metadata, approvals, and repeated invocations.
File Description
provider/​copilotprovider/​copilot.go Enables managed execution and applies call IDs.
provider/​copilotprovider/​copilot_internal_test.go Updates Copilot middleware test coverage.
agent/​middleware.go Wraps provider-executed tools and exposes call IDs.
agent/​middleware_test.go Tests middleware composition and preservation behavior.
agent/​harness/​toolautocall/​autocall.go Uses the public call-ID helper.
agent/​agent.go Adds provider tool-execution capability configuration.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@github-actions github-actions Bot added the public-api-change Pull Request changes public APIs label Sep 22, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Scope: public API, user-visible behavior

Changed Go contract: New exported field agent.ProviderConfig.ManagesToolExecution bool; new exported function agent.WithFuncCallID(ctx, callID) context.Context; copilotprovider.NewAgent now sets ManagesToolExecution: true, so Copilot's WithTool function tools are wrapped with Config.FunctionMiddlewares immediately before Run (previously this wrapping happened inline inside copilotTools, functionally equivalent but now routed through the generic agent package hook).

Upstream evidence reviewed:

  • dotnet/src/Microsoft.Agents.AI/FunctionInvocationDelegatingAgent.cs — internal delegating agent that wraps AIFunction tools found in ChatOptions.Tools with a middleware chain immediately before invocation, preserving schema/approval metadata and exposing a call-context (FunctionInvocationContext) analogous to Go's FunctionInvocationContext/WithFuncCallID.
  • dotnet/src/Microsoft.Agents.AI/FunctionInvocationDelegatingAgentBuilderExtensions.cs — public AIAgentBuilder.Use(...) extension gating the wrapper behind a check that the inner agent exposes a FunctionInvokingChatClient, i.e. an explicit capability/opt-in check comparable to Go's ManagesToolExecution bool.
  • python/packages/core/agent_framework/_agents.py (session_context.get_middleware(), categorize_middleware(... supported_categories=("chat","function")), lines ~1678-1703) — the closest Python analogue: providers contribute function/chat middleware into the client-level middleware chain through SessionContext.extend_middleware, rather than a boolean capability flag, but the underlying intent (let a provider-owned execution path still receive framework function middleware) matches.

Result: aligned. The new ManagesToolExecution opt-in and WithFuncCallID context helper are a faithful, idiomatically-Go mapping of the .NET capability-gated wrapping model (opt-in flag vs. .NET's inner-agent capability check), and conceptually match Python's provider-middleware injection path. The Copilot provider change is a refactor of existing behavior (moving inline tool-wrapping in copilotTools to the new generic wrapFuncTools hook) rather than a new default; observable results for Copilot are unchanged, confirmed by the updated copilot_internal_test.go assertion and the new agent/middleware_test.go coverage (composition, short-circuiting, call IDs, approval/schema preservation, unchanged caller options, repeated invocations). No default-disabled upstream feature is being enabled unconditionally here — this PR only exposes an extension point that Copilot then explicitly opts into. No cross-repo parity issues found.

Generated by Go API Consistency Review Agent for #1159 · copilot · auto · 81.7 AIC · ⌖ 7 AIC · ⊞ 9.2K · ◷

@github-actions github-actions Bot added kind:code Changes production behavior or code kind:tests Changes tests, fixtures, or test infrastructure labels Sep 22, 2026
@qmuntal
Quim Muntal (qmuntal) added this pull request to the merge queue Sep 22, 2026
Merged via the queue into main with commit 98d5c26 Sep 22, 2026
29 checks passed
@qmuntal
Quim Muntal (qmuntal) deleted the qmuntal/provider-tool-middleware branch September 22, 2026 17:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:agent Changes files in the agent area area:provider/copilot Changes files in the provider / copilot area area:provider Changes files in the provider area kind:code Changes production behavior or code kind:tests Changes tests, fixtures, or test infrastructure public-api-change Pull Request changes public APIs size:xlarge More than 300 changed lines or 10 files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants