Skip to content

[dotnet-port-fixes] Execute invocable tool siblings - #863

Open
Michelle Clayton (michelle-clayton-work) wants to merge 3 commits into
mainfrom
copilot/dotnet-port-fixes-toolautocall-mixed-calls-d7ea5478fe3d9fd5
Open

[dotnet-port-fixes] Execute invocable tool siblings#863
Michelle Clayton (michelle-clayton-work) wants to merge 3 commits into
mainfrom
copilot/dotnet-port-fixes-toolautocall-mixed-calls-d7ea5478fe3d9fd5

Conversation

@michelle-clayton-work

Copy link
Copy Markdown
Contributor

Summary

Updated agent/harness/toolautocall so invocable local tool calls still run when the same assistant turn also includes declaration-only schema tools. The middleware now executes the invocable siblings, leaves declaration-only calls actionable for the caller, and marks only the executed local calls informational-only. Added a regression test covering mixed-call ordering.

Ported .NET PRs

Breaking Changes

No.

Tests and Examples

  • go test ./agent/harness/toolautocall
  • Added TestFunctionInvoking_MixedInvocableAndNonInvocableSchemaToolExecutesInvocableSibling
  • No examples changed

Notes

  • Kept the fix internal to agent/harness/toolautocall; no exported Go API changed.
  • Preserved existing TerminateOnUnknownCalls behavior for unknown tools and only realigned mixed invocable/declaration-only schema-tool handling.

Generated by .NET to Go Fixes and Test Porting Agent · gpt54 · 212.2 AIC · ⌖ 12.4 AIC · ⊞ 24.2K ·

Closes #842

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI lite review requested due to automatic review settings August 18, 2026 21:21
@github-actions github-actions Bot added area:agent Changes files in the agent area size:medium At most 100 changed lines across at most 5 files labels Aug 18, 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.

Pull request overview

Updates the agent/harness/toolautocall middleware to correctly handle mixed assistant turns that contain both (a) invocable local function calls and (b) declaration-only (non-invocable) schema tool calls. The middleware now executes the invocable siblings, leaves declaration-only calls actionable for the caller, and only marks the executed local calls as informational-only, with a regression test covering the mixed-call ordering.

Changes:

  • Added an execution-plan step to split function calls into “processable now” vs “terminate after processing” to avoid bypassing invocable siblings.
  • Updated the main loop to use the plan for termination decisions and for selecting which calls to execute/mark informational-only.
  • Added a regression test for mixed invocable + non-invocable schema tool calls to ensure invocable siblings still execute.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
agent/harness/toolautocall/autocall.go Builds and uses a function-call execution plan so invocable siblings execute even when non-invocable schema tools are present.
agent/harness/toolautocall/autocall_test.go Adds regression coverage ensuring mixed-call ordering executes the invocable tool and leaves declaration-only calls actionable.

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

@github-actions

This comment has been minimized.

@github-actions github-actions Bot added parity-approved Go API consistency review found no parity issues kind:code Changes production behavior or code kind:tests Changes tests, fixtures, or test infrastructure failed-auto-risk Automatic risk classification was inconclusive or failed risk:medium Contained production impact requiring normal review depth and removed failed-auto-risk Automatic risk classification was inconclusive or failed labels Aug 18, 2026

@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.

microsoft/agent-framework#7388 implements a new feature, it doesn't fix a bug, but the Go PR landed as part of the dotnet-port-fixes. AFAIU, this shouldn't have happened. Also, the port seems incomplete, as the .NET feature is opt-in.

@michelle-clayton-work

Copy link
Copy Markdown
Contributor Author

Quim Muntal (@qmuntal) opened up #872 to improve the wording of the workflow prompts

@github-actions github-actions Bot added size:large At most 300 changed lines across at most 10 files public-api-change Pull Request changes public APIs kind:docs Changes documentation or comments pending-auto-risk Automatic risk classification is in progress risk:medium Contained production impact requiring normal review depth and removed size:medium At most 100 changed lines across at most 5 files parity-approved Go API consistency review found no parity issues risk:medium Contained production impact requiring normal review depth pending-auto-risk Automatic risk classification is in progress labels Aug 21, 2026
@michelle-clayton-work

Copy link
Copy Markdown
Contributor Author

Quim Muntal (@qmuntal) I added the public experimental Config.EnableExecutableFunctionBypassing option, defaulting to false, with tests for both disabled and enabled behavior

@github-actions github-actions Bot added pending-auto-risk Automatic risk classification is in progress and removed risk:medium Contained production impact requiring normal review depth labels Aug 21, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Go API Consistency Review

Scope

This PR adds EnableExecutableFunctionBypassing bool to toolautocall.Config (exported field — public-api-change label is correct) and makes the mixed invocable/declaration-only call behavior opt-in. The label public-api-change should remain.

Upstream reference

The PR is described as a port of microsoft/agent-framework#7388, commit aaaa56bc.

Parity finding — behavioral divergence (requires confirmation)

The upstream .NET feature (ChatClientAgentOptions.EnableInvocableFunctionBypassing, marked [Experimental]) is implemented via InvocableFunctionBypassingChatClient, which uses a store-and-defer strategy:

  1. When a mixed response (invocable + declaration-only) is detected, invocable calls are removed from the response and stored in AgentSessionStateBag.
  2. Only the declaration-only calls are returned to the caller for the current turn.
  3. On the next request, stored calls are re-injected as pre-approved ToolApprovalResponseContent and executed by FunctionInvokingChatClient.

The Go implementation uses a different strategy: invocable siblings are executed immediately in the same turn, and only declaration-only calls are returned to the caller. There is no session-state storage or cross-turn re-injection.

This means the observable semantics differ: in .NET, tool results from invocable calls appear in the next turn's history; in Go, they appear in the current turn's tool result messages. In multi-turn or stateful scenarios this difference may affect conversation coherence.

What needs resolution

  • Confirm whether the immediate-execution approach is an intentional, language-idiomatic divergence from the upstream store-and-defer model. If so, document it in docs/dotnet-go-sdk-feature-comparison.md.
  • Consider adding an experimental marker analogous to the .NET [Experimental] attribute, since EnableInvocableFunctionBypassing is marked experimental upstream.
  • Verify correctness in multi-turn scenarios where the provider's orphaned call_id problem manifests — the Go approach avoids the orphan by executing immediately, but confirm this covers the same failure cases the .NET store-and-defer was designed to fix.

This review does not block correctness of the opt-in guard added in this PR (which is a clear improvement over the prior unconditional behavior). The concern is semantic alignment with upstream for anyone relying on parity between SDKs.

Generated by Go API Consistency Review Agent for #863 · sonnet46 · 39.5 AIC · ⌖ 4.99 AIC · ⊞ 6K ·

@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 #863 · sonnet46 · 39.5 AIC · ⌖ 4.99 AIC · ⊞ 6K

if !f.enableExecutableFunctionBypassing {
return functionCallExecutionPlan{terminate: true}
}
terminate = true

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.

Parity gap vs upstream .NET — execution strategy diverges from InvocableFunctionBypassingChatClient

The upstream .NET commit aaaa56bc solves the mixed-call problem via a store-and-defer approach: InvocableFunctionBypassingChatClient removes invocable calls from the current response, stores them in AgentSessionStateBag, and returns only declaration-only calls to the caller. On the next request, the stored calls are re-injected as pre-approved ToolApprovalResponseContent so FunctionInvokingChatClient reconstructs and executes them.

The Go implementation here takes a different approach: it executes invocable siblings immediately in the same turn.

Concern .NET EnableInvocableFunctionBypassing Go EnableExecutableFunctionBypassing
Invocable call timing Deferred to next request via session state Executed immediately in current turn
Session state used Yes (AgentSessionStateBag) No
Re-injection mechanism Pre-approved ToolApprovalResponseContent N/A
Experimental gate [Experimental] attribute opt-in field (no experimental marker)

This is a meaningful behavioral divergence. The PR description calls it a port of #7388, but the execution model is structurally different. Please either:

  1. Confirm this is an intentional, language-idiomatic divergence and document it in docs/dotnet-go-sdk-feature-comparison.md, or
  2. Align with the upstream store-and-defer model if cross-turn session-state persistence is required for correctness in multi-turn scenarios.

@github-actions github-actions Bot added risk:medium Contained production impact requiring normal review depth and removed pending-auto-risk Automatic risk classification is in progress labels Aug 21, 2026
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 kind:code Changes production behavior or code kind:docs Changes documentation or comments kind:tests Changes tests, fixtures, or test infrastructure public-api-change Pull Request changes public APIs risk:medium Contained production impact requiring normal review depth size:large At most 300 changed lines across at most 10 files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[dotnet-port-fixes] Execute invocable tool siblings

4 participants