feat: Squad.Agents.AI - Microsoft Agent Framework adapter for the Squad CLI#1207
feat: Squad.Agents.AI - Microsoft Agent Framework adapter for the Squad CLI#1207tamirdresher wants to merge 19 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a new src/Squad.Agents.AI .NET package that wraps the Squad CLI (via GitHub Copilot SDK) as a Microsoft Agent Framework AIAgent, plus tests, a runnable sample, and CI/release automation for publishing to NuGet.
Changes:
- Introduces
SquadAgent+ DI registration extensions (including keyed DI) and connection-string parsing/binding. - Adds a comprehensive test suite and a console sample demonstrating basic DI, keyed DI, BYOK (
ConfigureCopilotClient), and streaming. - Adds GitHub Actions workflows for CI and NuGet publishing, plus Dependabot config for NuGet/GitHub Actions updates.
Reviewed changes
Copilot reviewed 22 out of 23 changed files in this pull request and generated 12 comments.
Show a summary per file
| File | Description |
|---|---|
src/Squad.Agents.AI/SquadAgent.cs |
AIAgent wrapper over Copilot SDK + BYOK routing guard + streaming delegation. |
src/Squad.Agents.AI/SquadAgentOptions.cs |
Options model with redaction + JSON ignore for sensitive fields. |
src/Squad.Agents.AI/SquadAgentOptionsConfigurator.cs |
Binds/merges options from ConnectionStrings:* before user configuration. |
src/Squad.Agents.AI/SquadConnectionFactory.cs |
Parses PATH/URI connection strings into SquadAgentOptions. |
src/Squad.Agents.AI/SquadServiceCollectionExtensions.cs |
DI registration APIs (scoped/lifetime overloads + keyed DI). |
src/Squad.Agents.AI/Squad.Agents.AI.csproj |
NuGet packaging metadata + dependencies for the new library. |
src/Squad.Agents.AI/README.md |
Package documentation (usage, DI shapes, BYOK, streaming, sample instructions). |
src/Squad.Agents.AI/samples/Squad.Agents.AI.Sample/Program.cs |
Sample app demonstrating 4 integration flows + error handling. |
src/Squad.Agents.AI/samples/Squad.Agents.AI.Sample/Squad.Agents.AI.Sample.csproj |
Sample project definition and dependencies. |
src/Squad.Agents.AI/samples/Squad.Agents.AI.Sample/README.md |
Pointer README for sample discoverability. |
test/Squad.Agents.AI.Tests/SquadServiceCollectionExtensionsTests.cs |
Tests DI registration + config/connection-string binding behavior. |
test/Squad.Agents.AI.Tests/SquadKeyedDITests.cs |
Tests keyed DI registration/resolution semantics. |
test/Squad.Agents.AI.Tests/SquadConnectionFactoryTests.cs |
Tests connection-string parsing for PATH/URI forms. |
test/Squad.Agents.AI.Tests/SquadBYOKTests.cs |
Tests ConfigureCopilotClient behavior + routing guard expectations. |
test/Squad.Agents.AI.Tests/SquadAgentRoutingTests.cs |
Tests agent naming/instructions and routing through Copilot options. |
test/Squad.Agents.AI.Tests/SquadAgentOptionsSecurityTests.cs |
Tests redaction/JSON serialization behavior for sensitive fields. |
test/Squad.Agents.AI.Tests/Squad.Agents.AI.Tests.csproj |
Test project configuration and dependencies. |
.github/workflows/squad-agents-ai-ci.yml |
CI build/test/pack on Ubuntu + Windows for the new package. |
.github/workflows/squad-agents-ai-release.yml |
Branch-driven NuGet publish workflow (dev prerelease, main stable). |
.github/dependabot.yml |
Enables Dependabot updates for NuGet and GitHub Actions for this package. |
README.md |
Adds a top-level callout to the new .NET package docs. |
CHANGELOG.md |
Adds an entry describing the new Squad.Agents.AI preview. |
.gitignore |
Ignores common .NET build artifacts (bin/, obj/, artifacts/). |
| // Snapshot routing properties before the delegate runs | ||
| var snapshotCwd = clientOptions.Cwd; | ||
| var snapshotCliPath = clientOptions.CliPath; | ||
| var snapshotCliArgs = clientOptions.CliArgs; | ||
|
|
| if (!ReferenceEquals(clientOptions.CliArgs, snapshotCliArgs)) | ||
| { | ||
| logger?.LogWarning( | ||
| "ConfigureCopilotClient delegate replaced CliArgs; " + | ||
| "restoring original value to preserve Squad routing."); | ||
| clientOptions.CliArgs = snapshotCliArgs; | ||
| restored = true; | ||
| } |
| public static IServiceCollection AddSquadAgent( | ||
| this IServiceCollection services, | ||
| string name, | ||
| Action<SquadAgentOptions>? configure = null) | ||
| => AddSquadAgentCore(services, name, ServiceLifetime.Scoped, configure); |
| public static IServiceCollection AddSquadAgent( | ||
| this IServiceCollection services, | ||
| string name, | ||
| ServiceLifetime lifetime, | ||
| Action<SquadAgentOptions>? configure = null) | ||
| => AddSquadAgentCore(services, name, lifetime, configure); |
| public static IServiceCollection AddKeyedSquadAgent( | ||
| this IServiceCollection services, | ||
| string serviceKey, | ||
| string name, | ||
| Action<SquadAgentOptions>? configure = null) | ||
| => AddKeyedSquadAgentCore(services, serviceKey, name, ServiceLifetime.Scoped, configure); |
| - Added `Squad.Agents.AI`, a `net10.0` Microsoft Agent Framework package that exposes a Squad team as an `AIAgent`. | ||
| - Public surface: `SquadAgent`, `SquadAgentOptions`, `SquadConnectionFactory`, and `SquadServiceCollectionExtensions`. | ||
| - Added DI registration, PATH/URI connection-string parsing, GitHub token/provider options, and XML documentation for the public preview surface. | ||
| - Documented PR #3 lineage for the v0.1-preview package in `src/Squad.Agents.AI/README.md`. |
| | [.NET 10 SDK](https://dotnet.microsoft.com/download/dotnet/10.0) | `dotnet --version` should print `10.x.x` | | ||
| | GitHub Copilot CLI on `PATH` | Install from [github.com/github/copilot-cli](https://github.com/github/copilot-cli); verify with `copilot --version` | | ||
| | Squad CLI installed | Follow the install guide in the [Squad repository README](https://github.com/tamirdresher/squad#readme) | | ||
| | Initialized Squad team root | Run `squad init` in a directory; this becomes your team root | | ||
| | GitHub Copilot authentication | Run `gh auth login` or `copilot auth login` once before running the sample | |
| <PackageTags>squad;agents;ai;copilot;maf;multi-agent</PackageTags> | ||
| <PackageProjectUrl>https://github.com/tamirdresher/squad</PackageProjectUrl> | ||
| <RepositoryUrl>https://github.com/tamirdresher/squad.git</RepositoryUrl> | ||
| <RepositoryType>git</RepositoryType> |
| // Simulate a token from a credential store (never hardcode real tokens). | ||
| // In production replace this with Key Vault, managed identity, etc. | ||
| const string simulatedToken = "ghp_EXAMPLE_REPLACE_WITH_REAL_TOKEN"; | ||
|
|
| <PropertyGroup> | ||
| <TargetFramework>net10.0</TargetFramework> | ||
| <Nullable>enable</Nullable> |
Squad CLI as Microsoft.Extensions.AI IChatClient, composing GitHub.Copilot.SDK via AsAIAgent() from Microsoft.Agents.AI.GitHub.Copilot 1.7.0-preview. Closes Track A of the Q1-Q7 design lock (see tamresearch1 .squad/decisions.md Decisions 441, 443, 444, 447). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- SquadAgent now properly inherits from Microsoft.Agents.AI.AIAgent - Removed (IChatClient)(object)agent force-cast - Overrides all AIAgent abstract members (CreateSessionCoreAsync, RunCoreAsync, etc.) - DI registration now registers AIAgent (not IChatClient) - README updated to use AIAgent.RunAsync API - No more abstraction inversion; AIAgent is the correct layer Fixes the architectural error identified by Tamir.
…eshooting, preview callout Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Adds async token provider pattern for production scenarios (KeyVault/MSI integration). - GitHubTokenProvider property takes precedence over GitHubToken - GitHubToken marked [JsonIgnore] to prevent serialization leaks - SquadAgentOptions.ToString() redacts GitHubToken field - Updated CreateCopilotClient to resolve token from provider first Mitigates P0 #3: token leakage via ILogger structured-log calls, IOptions snapshots, and serializers. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…n token management Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…+ add smoke tests Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
WithTeamRoot was deleted in commit 35767c90 in favor of mandatory positional teamRoot constructor argument on AddSquad. The Aspire example in the Squad.Agents.AI README still showed the old fluent API, which would now fail at compile time for anyone copy-pasting. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Closes the routing-verification gap identified during squad-squad onboarding: the API surface existed but routing semantics weren't functionally tested. New tests verify persona pass-through, boundary-instruction injection on first turn, WorkingDirectory isolation (Decision 452a), and CopilotClientOptions-based routing (Decision 447). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
PR #3 CI was Node/docs-only — adding the .NET gate so green actually reflects the package code. Matrix on ubuntu + windows, restore/build/test/pack, uploads TestResults and nupkg artifacts. Closes the build-verification gap identified during squad-squad onboarding (see .squad/decisions.md adoption record, 2026-06-02). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- .github/workflows/squad-agents-ai-release.yml: workflow_dispatch and tag-driven publish to nuget.org with --skip-duplicate idempotency, fail-fast on missing NUGET_API_KEY secret, optional GitHub Release on tag - .github/dependabot.yml: nuget (src + test) + github-actions, weekly, M.A.AI major allowed, OpenTelemetry major deferred (per Decision 602) Closes the release-pipeline + supply-chain-tracking gaps identified during squad-squad onboarding. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- README updates / XML docs on public surface - CHANGELOG.md with [0.1.0-preview] - 2026-06-02 entry - .csproj: Description, RepositoryUrl, Authors, PackageTags, PackageReadmeFile - Verified via dotnet pack — .nupkg contains README, LICENSE, xml-docs Closes the docs-readiness gap for v0.1-preview publish. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Per Tamir's release-strategy directive (decisions.md 2026-06-02): - dev merges → prerelease publish (suffix scheme mirrors Squad CLI) - main merges → stable publish - workflow_dispatch retained as manual escape hatch - tag-driven trigger removed (branches are the source of truth) Version derivation pattern adapted from the Squad CLI's existing release workflow. --skip-duplicate retained for idempotent reruns. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… connections
- Rewrite the package README and PR validation flow around the AIAgent surface and ambient Copilot authentication.
- Keep public docs free of internal process references and remove obsolete deferral language.
- Preserve connection-string cliArgs through CopilotClientOptions and cover the behavior with a routing test.
- Add named connection-string lookup via AddSquadAgent("name") using ConnectionStrings:squad-{name}.
- Document the new public overloads and verify the package builds without warnings.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ning - Add ConfigureCopilotClient delegate on SquadAgentOptions for BYOK - Add routing gate: snapshot/restore Cwd/CliPath/CliArgs after delegate (Picard C1) - Add 4 AddKeyedSquadAgent overloads with .NET 8+ keyed DI - Fix Environment credential leak: [JsonIgnore] on Environment, GitHubTokenProvider, ConfigureCopilotClient - ToString() redacts token-pattern keys (TOKEN/KEY/SECRET/HMAC/PASSWORD/CREDENTIAL) - Add 21 new tests (43 total): security redaction, keyed DI, BYOK routing gate - Update README: streaming, keyed DI, BYOK, security sections Complies with: Picard C1-C4, Worf SC-1 through SC-8. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…, and streaming - samples/squad-agents-ai-sample/Program.cs: four runnable flows Flow 1 -- AddSquadAgent + RunAsync (basic DI) Flow 2 -- AddKeyedSquadAgent x2 + GetRequiredKeyedService<SquadAgent> Flow 3 -- ConfigureCopilotClient delegate (BYOK token + env var injection) Flow 4 -- RunStreamingAsync with await foreach token-by-token output - samples/squad-agents-ai-sample/Squad.Agents.AI.Sample.csproj: net10.0, project reference to src/Squad.Agents.AI, Microsoft.Extensions.Hosting 10.0.0 - samples/squad-agents-ai-sample/README.md: prerequisites, run commands, per-flow walkthrough, troubleshooting table - .github/workflows/squad-agents-ai-ci.yml: adds paths trigger and restore + build steps for the sample (no run step -- requires live CLI) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…e README - Moves the sample app from samples/squad-agents-ai-sample/ to src/Squad.Agents.AI/samples/Squad.Agents.AI.Sample/ so it lives alongside the package it demonstrates. - Folds the sample's standalone README into the package README, giving consumers one canonical doc for both the API and the runnable demo. - Adds <Compile Remove="samples/**/*.cs" /> to Squad.Agents.AI.csproj so the library's wildcard glob does not pick up Program.cs in the co-located samples subdirectory. - Updates the .csproj project reference, and CI workflow paths to match the new layout. - Verified end-to-end: dotnet build, dotnet test (43/43 passing), and a sample sanity-check run (clear CLI-not-found error, no stack trace). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The standalone pr-body.md was an early draft authored before the live PR description took its final shape. The PR body on GitHub is the canonical source; this file is dead weight and would confuse maintainers reviewing the diff. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
beec9cf to
87645bf
Compare
…12 items) - Snapshot CliArgs by value, not reference, so in-place mutation by SDK consumers is also caught by the routing guard. - Validate name/connectionName/serviceKey is non-empty in all DI registration overloads; previously null/whitespace produced invalid connection-string keys. - Replace ghp_-prefixed placeholder in the sample with a clearly-fake token to avoid tripping secret-scanning and to remove a real-token lookalike. - Remove brittle 'PR #3' references from README and CHANGELOG; describe the feature without tying to a specific PR thread. - Update NuGet metadata and README links to point to bradygaster/squad (canonical repo) instead of the tamirdresher fork. - Multi-target the test project to match the package's target framework set so CI exercises every framework the package ships against. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
| /// </code> | ||
| /// </example> | ||
| /// </remarks> | ||
| public sealed class SquadAgent : AIAgent, IAsyncDisposable |
There was a problem hiding this comment.
As mentioned earlier, check out https://github.com/microsoft/agent-framework/blob/main/dotnet/src/Microsoft.Agents.AI.Abstractions/DelegatingAIAgent.cs, which should help reduce some boilerplate.
| /// </summary> | ||
| /// <param name="options">Options that describe the Squad team root, CLI process, authentication, logging, and instructions.</param> | ||
| /// <param name="loggerFactory">Optional logger factory used for wrapper logs and SDK trace logging when enabled.</param> | ||
| public SquadAgent(SquadAgentOptions options, ILoggerFactory? loggerFactory = null) |
There was a problem hiding this comment.
Not sure how closely you want to follow MAF, but a pattern we follow is that required settings are on the constructor and optional are in options, with options itself being optional. loggerFactory, while optional, is an exception, since you may typically want it to be injected via DI, so it stays on the constructor, including anything else that similarly may need to be injected via DI.
E.g. (string requiredParam, OptionsClass? options = null, ILoggerFactory? loggerFactory = null)
Closes #1205
What
This PR adds
Squad.Agents.AI, a community .NET package that exposes a Squad agent team as a Microsoft Agent FrameworkAIAgent. Applications using the Microsoft Agents library can now integrate Squad's capabilities via standardRunAsyncandRunStreamingAsyncpatterns.Why
Teams adopting the Microsoft Agent Framework need a way to invoke Squad agent teams directly from their
AIAgentworkloads. This package provides a thin, secure integration layer that composes the Squad CLI through the GitHub Copilot SDK, allowing DI-based registration and streaming support without reimplementing Squad's agent orchestration.How
Public API surface:
services.AddSquadAgent(options => ...)— Single agent registration via DIservices.AddKeyedSquadAgent("name", options => ...)— Keyed services for multiple agents (.NET 8+)options.ConfigureCopilotClient = client => ...— Bring-your-own-client delegate for custom Copilot SDK configurationagent.RunAsync(thread, options, ct)— Synchronous invocation returning structured responseagent.RunStreamingAsync(thread, options, ct)— Token-by-token streamingSecurity posture:
Environmentoption redacted inToString()to prevent credential leaks in logsCwd,CliPath,CliArgs) are snapshotted before and restored after anyConfigureCopilotClientdelegate to prevent SDK customizers from pivoting the agent to a different CLI binary; deviations are logged as warningsTesting:
net8.0,net9.0, andnet10.0ubuntu-latestandwindows-latestto verify cross-platform compatibilitySample application:
The repository includes a runnable .NET console app demonstrating all four core patterns:
AddSquadAgent+RunAsyncAddKeyedSquadAgentwithGetRequiredKeyedService<AIAgent>ConfigureCopilotClientdelegate for token injection and environment customizationRunStreamingAsyncfor token-by-token outputRun the sample:
To execute a specific flow:
Documentation:
README at
src/Squad.Agents.AI/README.mdcovers:dotnet add package Squad.Agents.AI --prereleasesrc/Squad.Agents.AI/samples/Squad.Agents.AI.Sample/Breaking changes: None.
Quick Check
dotnet test test/Squad.Agents.AI.Tests/ -c Release— 43/43 greendotnet build src/Squad.Agents.AI/Squad.Agents.AI.csproj -c Releaseubuntu-latestandwindows-latest## SamplesectionPR Readiness Checklist
dotnet buildpassesdotnet testpasses (43/43 green)src/Squad.Agents.AI/samples/Squad.Agents.AI.Sample/