Skip to content

.NET: Make GitHub.Copilot.SDK build targets reach transitive consumers (#6455)#6457

Merged
westey-m merged 2 commits into
microsoft:mainfrom
tamirdresher:tamirdresher/issue-6455-buildtransitive-copilot-sdk
Jun 10, 2026
Merged

.NET: Make GitHub.Copilot.SDK build targets reach transitive consumers (#6455)#6457
westey-m merged 2 commits into
microsoft:mainfrom
tamirdresher:tamirdresher/issue-6455-buildtransitive-copilot-sdk

Conversation

@tamirdresher

Copy link
Copy Markdown
Contributor

Motivation and Context

Fixes #6455.

Consumers who reference Microsoft.Agents.AI.GitHub.Copilot (the normal way to use the adapter) currently get only the managed .dll — no copilot.exe in their output, and the SDK throws InvalidOperationException: Copilot CLI not found at runtimes\{rid}\native\copilot.exe on the first RunAsync. Root cause is purely packaging: GitHub.Copilot.SDK ships its CLI binary-download MSBuild targets under build/, which NuGet only auto-imports for projects with a direct PackageReference to the SDK. Transitive consumers never see those targets and the binary never lands.

The SDK targets themselves are correct — adding <PackageReference Include="GitHub.Copilot.SDK" /> directly to a consumer alongside the MAF reference makes the SDK targets fire and ~115 MB copilot.exe shows up at the right path. So the fix here is to make those targets reachable to consumers of the adapter package as well.

Long-term, relocating the targets from build/ to buildTransitive/ in github/copilot-sdk itself is the cleaner SDK-side fix and would benefit every downstream package, not just this one. Issue #6455 covers both options; this PR implements the adapter-side fix (Option A) so MAF users get unblocked immediately without an SDK-side coordination cycle.

Description

Adds a tiny buildTransitive/ bridge to Microsoft.Agents.AI.GitHub.Copilot so the SDK's binary-download targets reach transitive consumers.

Files added:

  • dotnet/src/Microsoft.Agents.AI.GitHub.Copilot/buildTransitive/Microsoft.Agents.AI.GitHub.Copilot.targets — static bridge. Imports the SDK's build/GitHub.Copilot.SDK.targets from the NuGet cache ($(NuGetPackageRoot)/github.copilot.sdk/$(_MicrosoftAgentsAICopilotSdkVersion)/build/...). The version-pin condition no-ops gracefully when the resolved SDK version differs from what we baked, so this is purely additive — consumers already pinning the SDK directly see no behavior change.
  • dotnet/src/Microsoft.Agents.AI.GitHub.Copilot/buildTransitive/.gitignore — ignores the auto-generated props file (regenerated on every pack, similar to how GitHub.Copilot.SDK itself generates build/GitHub.Copilot.SDK.props at pack time).

Files modified:

  • dotnet/src/Microsoft.Agents.AI.GitHub.Copilot/Microsoft.Agents.AI.GitHub.Copilot.csproj — adds a _GenerateBuildTransitiveProps target that runs BeforeTargets="_GetPackageFiles". It resolves the SDK version from @(PackageVersion) items (Central Package Management surface) and writes buildTransitive/Microsoft.Agents.AI.GitHub.Copilot.props setting $(_MicrosoftAgentsAICopilotSdkVersion). Both files are then packed under buildTransitive/. Same pattern the SDK uses for its own props (_GenerateVersionProps in GitHub.Copilot.SDK.csproj).

Compatibility:

  • No API surface change — public surface of the assembly is untouched.
  • No behavior change for projects with a direct <PackageReference Include="GitHub.Copilot.SDK" />. The SDK's build/ targets still fire for them as today; our bridge's condition Exists($(_MicrosoftAgentsAICopilotSdkBuildDir)/GitHub.Copilot.SDK.targets) succeeds and re-imports the same file — <Import> is idempotent in MSBuild and only schedules each target once.
  • Consumers can opt out of the binary download via the SDK's existing $(CopilotSkipCliDownload)=true, which our bridge passes through unchanged.

Verification:

Built the package locally on this branch (Microsoft.Agents.AI.GitHub.Copilot 1.9.0-preview.260603.1), confirmed both buildTransitive/*.props and buildTransitive/*.targets ship in the resulting nupkg, then created a brand-new console app with only:

<PackageReference Include="Microsoft.Agents.AI.GitHub.Copilot" Version="1.9.0-preview.260603.1" />

(no direct SDK reference) restored from a local feed pointed at the freshly-built nupkgs. On dotnet build, the bridge fired, the SDK's _DownloadCopilotCli target downloaded @github/copilot-win32-x64/1.0.57.tgz from npm, extracted, and copilot.exe (141.8 MB) landed at bin\Debug\net10.0\runtimes\win-x64\native\copilot.exe. copilot --version reports 1.0.61 as expected (the npm subpackage version differs from the bundled binary's self-reported version, both correct).

Contribution Checklist

  • The code builds clean without any errors or warnings
  • The PR follows the Contribution Guidelines
  • All unit tests pass, and I have added new tests where possible (MSBuild packaging change — no managed surface to unit-test; verification covered end-to-end via the consumer test above)
  • Is this a breaking change? No. Pure addition, no API surface change, no behavior change for existing consumers.

microsoft#6455)

Microsoft.Agents.AI.GitHub.Copilot now ships a buildTransitive/ bridge so
consumers who only reference this package (the normal use case) get the
GitHub.Copilot.SDK's CLI binary-download MSBuild targets executed at build
time. Without this, the SDK shipped its targets under build/ which NuGet
only auto-imports for projects with a direct PackageReference to the SDK,
so consumers of the adapter package got only the managed .dll, no
copilot.exe in their output, and a runtime InvalidOperationException on
the first RunAsync.

The bridge consists of two files under buildTransitive/:

* Microsoft.Agents.AI.GitHub.Copilot.props is generated at this package's
  pack time and pins the SDK version (from PackageVersion items in
  Directory.Packages.props) into _MicrosoftAgentsAICopilotSdkVersion.

* Microsoft.Agents.AI.GitHub.Copilot.targets is static and imports the
  SDK's own build/GitHub.Copilot.SDK.targets from the NuGet cache using
  the pinned version. The version-pin condition no-ops gracefully if the
  resolved SDK differs from what was baked in (e.g. consumer overrides
  the SDK version directly), so this is purely additive.

Verified by packing locally, restoring from a flat local feed, and
building a transitive-only consumer (PackageReference to MAF only, no
direct SDK ref). copilot.exe lands at bin/{cfg}/{tfm}/runtimes/{rid}/
native/copilot.exe as expected, matching the path the SDK's runtime
CopilotClient looks at.

Fixes microsoft#6455

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 10, 2026 15:46
@moonbox3 moonbox3 added the .NET label Jun 10, 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

Note

Copilot was unable to run its full agentic suite in this review.

Adds a buildTransitive bridge so transitive consumers of Microsoft.Agents.AI.GitHub.Copilot also import GitHub.Copilot.SDK’s build/ targets, ensuring the Copilot CLI binary download/copy steps run without requiring a direct PackageReference to the SDK.

Changes:

  • Added a transitive .targets file that locates the SDK in the NuGet cache and imports GitHub.Copilot.SDK.targets.
  • Added pack-time generation of a buildTransitive .props file to bake in the resolved GitHub.Copilot.SDK version.
  • Added a .gitignore entry for the generated .props file.

Reviewed changes

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

File Description
dotnet/src/Microsoft.Agents.AI.GitHub.Copilot/buildTransitive/Microsoft.Agents.AI.GitHub.Copilot.targets Imports SDK build targets for transitive consumers based on a generated SDK version property.
dotnet/src/Microsoft.Agents.AI.GitHub.Copilot/buildTransitive/.gitignore Ignores the generated buildTransitive props file.
dotnet/src/Microsoft.Agents.AI.GitHub.Copilot/Microsoft.Agents.AI.GitHub.Copilot.csproj Generates and packs the transitive .props, and packs the static transitive .targets.

- buildTransitive/.targets: compute the full SDK targets path with a single
  Path.Combine call into one property (_MicrosoftAgentsAICopilotSdkTargetsPath),
  used in both Project= and Exists() — no more split between Path.Combine for
  the directory and inline / separator for the file name.

- Split the version-defaulting Condition between the two files: the generated
  .props now just bakes the packaged SDK version into a dedicated property
  (_MicrosoftAgentsAICopilotSdkPackagedVersion), and the static .targets file
  is the single place that defaults _MicrosoftAgentsAICopilotSdkVersion to it.
  Removes the need for any MSBuild escape gymnastics in the pack-time string
  construction, and keeps the consumer override path the same.

- _GenerateBuildTransitiveProps now hangs off public BeforeTargets (Build, Pack)
  in addition to _GetPackageFiles, so the file is generated even without a
  full pack, and we're not solely dependent on an underscore-prefixed internal
  target. The <None Pack=true /> items live in a top-level ItemGroup so they
  are collected at evaluation time instead of being added from inside the
  Target.

End-to-end retested with a transitive-only consumer (PackageReference to MAF
only, no direct GitHub.Copilot.SDK ref): copilot.exe lands at
bin/Debug/net10.0/runtimes/win-x64/native/copilot.exe (141.8 MB) as before.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@westey-m westey-m added this pull request to the merge queue Jun 10, 2026
Merged via the queue into microsoft:main with commit 60cc5ee Jun 10, 2026
27 checks passed
tamirdresher added a commit to tamirdresher/Aspire-1 that referenced this pull request Jun 10, 2026
…DK direct ref

Squad.Agents.AI 0.2.0-preview.4 (released earlier today from bradygaster/squad#1259)
brings the package onto Microsoft.Agents.AI.GitHub.Copilot 1.10.0-rc1, which
transitively pulls GitHub.Copilot.SDK 1.0.0 GA. The earlier 0.1.0-preview.3 was
wedged on SDK 1.0.0-beta.2 + a CLI protocol the current copilot CLI no longer
speaks — verified by running the example ApiApp in this branch against a real
.squad-initialised team root and seeing the agent successfully read .squad/team.md
and dispatch work to multiple specialists.

Also add a direct PackageReference to GitHub.Copilot.SDK 1.0.0. This is a
temporary workaround: the SDK ships its CLI-binary-download MSBuild targets
under build/ (only auto-imported for projects with a *direct* PackageReference),
not buildTransitive/. microsoft/agent-framework#6457 (merged 2026-06-10) fixes
this at the MAF adapter level — once a MAF preview ships with that change, the
direct GitHub.Copilot.SDK ref can be dropped from Directory.Packages.props and
the ApiApp csproj. Both edit sites carry an inline comment explaining the lifecycle.

Verified: the hosting library, the ApiApp, and the AppHost all build clean, and
copilot.exe lands at the expected 'bin/{cfg}/{tfm}/runtimes/{rid}/native/' path
in the ApiApp output.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
tamirdresher added a commit to tamirdresher/Aspire-1 that referenced this pull request Jun 11, 2026
…DK direct ref

Squad.Agents.AI 0.2.0-preview.4 (released earlier today from bradygaster/squad#1259)
brings the package onto Microsoft.Agents.AI.GitHub.Copilot 1.10.0-rc1, which
transitively pulls GitHub.Copilot.SDK 1.0.0 GA. The earlier 0.1.0-preview.3 was
wedged on SDK 1.0.0-beta.2 + a CLI protocol the current copilot CLI no longer
speaks — verified by running the example ApiApp in this branch against a real
.squad-initialised team root and seeing the agent successfully read .squad/team.md
and dispatch work to multiple specialists.

Also add a direct PackageReference to GitHub.Copilot.SDK 1.0.0. This is a
temporary workaround: the SDK ships its CLI-binary-download MSBuild targets
under build/ (only auto-imported for projects with a *direct* PackageReference),
not buildTransitive/. microsoft/agent-framework#6457 (merged 2026-06-10) fixes
this at the MAF adapter level — once a MAF preview ships with that change, the
direct GitHub.Copilot.SDK ref can be dropped from Directory.Packages.props and
the ApiApp csproj. Both edit sites carry an inline comment explaining the lifecycle.

Verified: the hosting library, the ApiApp, and the AppHost all build clean, and
copilot.exe lands at the expected 'bin/{cfg}/{tfm}/runtimes/{rid}/native/' path
in the ApiApp output.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

.NET: [Bug]: GitHub.Copilot.SDK build targets don't propagate to transitive consumers — copilot.exe missing from output

5 participants