Skip to content

Set FunctionResultContent.Error on failed Copilot tool executions#698

Open
PratikDhanave wants to merge 2 commits into
microsoft:mainfrom
PratikDhanave:copilot-tool-error-result
Open

Set FunctionResultContent.Error on failed Copilot tool executions#698
PratikDhanave wants to merge 2 commits into
microsoft:mainfrom
PratikDhanave:copilot-tool-error-result

Conversation

@PratikDhanave

Copy link
Copy Markdown
Contributor

What

When the Copilot provider converts a tool.execution_complete event with success == false, toolExecutionCompleteUpdate now sets FunctionResultContent.Error in addition to Result. The error is built from the SDK ToolExecutionCompleteError: the human-readable Message, combined with the machine-readable Code when present ("<message> (<code>)"), falling back to a default when the SDK omits error details. Result is still populated for display continuity.

Why

The framework treats FunctionResultContent.Error as the canonical failure channel: autocall collects tool errors via frc.Error != nil, and the mcptool tests set Error on failure. Previously the Copilot provider only ever set Result and left Error nil, so a failed Copilot tool call looked identical to a successful one to any consumer that inspects Error. This matches the .NET/Python semantics where a failed function result carries its exception/error rather than folding it into the result payload, keeping cross-SDK behavior aligned.

How tested

Extended the existing tests in copilot_test.go:

  • The failure test now asserts Error != nil and that its message includes both the SDK Message and Code.
  • The success test now asserts Error == nil.

go build ./..., go vet ./provider/copilotprovider/..., and go test ./provider/copilotprovider/... all pass.

Copilot AI review requested due to automatic review settings July 24, 2026 02:10
@PratikDhanave
PratikDhanave requested a review from a team as a code owner July 24, 2026 02:10
@PratikDhanave
PratikDhanave force-pushed the copilot-tool-error-result branch from f41c6ea to e2065cc Compare July 24, 2026 02:14

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 Copilot provider’s tool.execution_complete handling so failed tool executions populate FunctionResultContent.Error (the framework’s canonical failure channel) while still keeping Result populated for continuity.

Changes:

  • Set FunctionResultContent.Error on failed tool.execution_complete events using SDK error details (message + optional code).
  • Added tests to assert Error == nil on success and Error != nil with message/code on failure.

Reviewed changes

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

File Description
provider/copilotprovider/copilot.go Populate FunctionResultContent.Error for failed tool executions via toolExecutionError.
provider/copilotprovider/copilot_test.go Extend tool execution completion tests to validate Error behavior on success/failure.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread provider/copilotprovider/copilot.go Outdated
Comment on lines +593 to +599
if data.Error != nil && data.Error.Message != "" {
if data.Error.Code != nil {
return fmt.Errorf("%s (%s)", data.Error.Message, *data.Error.Code)
}
return errors.New(data.Error.Message)
}
return errors.New("tool execution failed")

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good catch — fixed in 8da0f1b: toolExecutionError now reads Error.Code independently of Message, so a code-only failure yields "tool execution failed (CODE)" instead of dropping the code, and an empty code no longer produces a stray "message ()" suffix.

Comment on lines +420 to +425
if result.Error == nil {
t.Fatalf("Error = nil, want non-nil failure error")
}
if msg := result.Error.Error(); !strings.Contains(msg, "Access denied to resource") || !strings.Contains(msg, "PERMISSION_DENIED") {
t.Fatalf("Error = %q, want message and code", msg)
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good catch — fixed in 8da0f1b: the failure-without-error-details test now asserts result.Error is non-nil and carries the default "tool execution failed" message, locking in the new FunctionResultContent.Error behavior.

@github-actions

This comment has been minimized.

@github-actions github-actions Bot added the parity-approved Go API consistency review found no parity issues label Jul 24, 2026
@github-actions

This comment has been minimized.

toolExecutionCompleteUpdate only populated Result, leaving Error nil even
when data.Success was false. Callers that detect tool failures via
FunctionResultContent.Error (e.g. autocall error collection) therefore
treated failed Copilot tool calls as successful.

Populate Error from data.Error, combining Message with Code when present
and falling back to a default when the SDK omits error details, while
keeping Result populated for display continuity. This aligns the Copilot
provider with the framework's cross-provider failure-channel convention.
@PratikDhanave
PratikDhanave force-pushed the copilot-tool-error-result branch from 8da0f1b to 0fbd5b1 Compare July 24, 2026 09:34
@github-actions

Copy link
Copy Markdown
Contributor

Parity Review

Scope: provider/copilotprovider/copilot.go + test

Exported API change: None. toolExecutionError is unexported; FunctionResultContent.Error is an existing exported field.

Behavioral change: Failed Copilot tool executions now populate FunctionResultContent.Error (previously left nil). This closes a gap with .NET/Python semantics where a failed function result carries its error in the error channel rather than folding it into the result payload. The autocall harness and mcptool tests already rely on frc.Error != nil as the canonical failure signal, so this change brings the Copilot provider into alignment with the rest of the framework.

Parity verdict: This change increases cross-SDK consistency. No upstream divergence found. parity-approved label is appropriate.

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • awmgmcpg

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "awmgmcpg"

See Network Configuration for more information.

Generated by Go API Consistency Review Agent · 24 AIC · ⌖ 3.94 AIC · ⊞ 5.9K ·

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

parity-approved Go API consistency review found no parity issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants