Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
7efe0a9
baseline branch for the next major release
aaronpowell Oct 22, 2025
2ebfea3
Updating nightly
aaronpowell Oct 23, 2025
06d5985
Remove deprecated IDistributedApplicationLifecycleHook interface (#915)
Copilot Oct 24, 2025
3998714
Merge branch 'main' into aspire-13
aaronpowell Oct 24, 2025
8854f05
Adjusting the version of keycloak
aaronpowell Oct 24, 2025
8ed05c2
Updating aspire nightly
aaronpowell Oct 24, 2025
021a7ae
Merge branch 'main' into aspire-13
aaronpowell Oct 27, 2025
573fa53
New nightly
aaronpowell Oct 27, 2025
18787c3
Remove npm functionality moved to Aspire 13 (#928)
Copilot Nov 3, 2025
eef3b5c
Merge branch 'main' into aspire-13
aaronpowell Nov 3, 2025
7c3b2aa
Merge branch 'aspire-13' of https://github.com/CommunityToolkit/Aspir…
aaronpowell Nov 4, 2025
76cfd8e
Fixing failing test
aaronpowell Nov 4, 2025
f592c54
Merge branch 'main' into aspire-13
aaronpowell Nov 4, 2025
3522e4a
Remove deprecated EventStore integrations (#946)
Copilot Nov 5, 2025
61ce4e7
Creating a new agent for generating hosting integrations
aaronpowell Nov 5, 2025
716dfba
Creating a new agent for generating client integrations
aaronpowell Nov 5, 2025
6e9a600
Expanded the hosting agent a bit
aaronpowell Nov 5, 2025
c87861c
Removing the legacy approach to checking resource health and updated …
aaronpowell Nov 5, 2025
1274efb
Bumping go and removing pnpm setup
aaronpowell Nov 6, 2025
93cd270
maybe we need an explicit health check
aaronpowell Nov 6, 2025
0f6b66e
Using the new JavaScriptAppResource so we can leverage the new method…
aaronpowell Nov 6, 2025
a837d2f
Disabling tests on Windows due to https://github.com/modelcontextprot…
aaronpowell Nov 6, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 3 additions & 9 deletions .github/actions/setup-runtimes-caching/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,12 @@ runs:
with:
enable-cache: false

- uses: actions/setup-go@v5
- uses: actions/setup-go@v6
name: Set up Go
with:
go-version: "^1.22.1"
go-version: "^1.25.4"
cache-dependency-path: |
./**/go.sum
./examples/golang/gin-api/go.sum

- uses: actions/setup-java@v4
name: Set up Java
Expand All @@ -57,12 +57,6 @@ runs:
with:
node-version: "latest"

- uses: pnpm/action-setup@v4
name: Setup pnpm
with:
version: 9
run_install: false

- uses: denoland/setup-deno@v2
name: Setup Deno
with:
Expand Down
288 changes: 288 additions & 0 deletions .github/agents/client-integration-creator.agent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,288 @@
---
description: "This agent helps users create new client integrations in Aspire by scaffolding the correct projects and files based on user input."
tools:
[
"runCommands",
"runTasks",
"edit/createFile",
"edit/createDirectory",
"edit/editFiles",
"search",
"runTests",
"usages",
"problems",
"testFailure",
"fetch",
"githubRepo",
]
name: Client Integration Creator
---

You are an expert in Aspire and C# development, specializing in creating CLIENT integrations (library/service consumer integrations, not hosting). The repo you are working in is a monorepo that contains multiple hosting and client integrations. Focus your guidance and scaffolding ONLY on client integrations for this agent.

## Repo Structure (Recap)

- `src`: All integration projects. New client integration goes here: `CommunityToolkit.Aspire.[IntegrationName]`.
- `tests`: Test projects. Client test project name: `CommunityToolkit.Aspire.[IntegrationName].Tests`.
- `examples`: Example usage applications. Provide an AppHost plus (optionally) a sample consumer project demonstrating usage of the client services.

## Client Integration Naming & Scope

- Project name format: `CommunityToolkit.Aspire.[IntegrationName]` (NO `Hosting.` segment).
- Provide capabilities that simplify registration, configuration binding, telemetry, health checks, and keyed service resolution.

## Core Project Files

Each client integration must minimally contain:

1. `CommunityToolkit.Aspire.[IntegrationName].csproj`
2. `[IntegrationName]Settings.cs` – strongly typed settings bound from configuration sections and optionally connection strings.
3. `Aspire[IntegrationName]Extensions.cs` – extension methods on `IHostApplicationBuilder` under `namespace Microsoft.Extensions.Hosting`.
4. Any auxiliary builders (`Aspire[IntegrationName]ClientBuilder.cs`) if chaining additional feature registrations (pattern from `AspireOllamaApiClientBuilder`).
5. Optional: Health check class (e.g. `KurrentDBHealthCheck.cs`) when a connectivity probe is feasible.
6. `README.md` (overview + quick start).

When using other projects as a reference, an `api` folder exists. The contents of this folder are auto-generated, so **DO NOT** create any files in this folder, that will be created automatically when the API is reviewed.

## csproj Conventions

Example template:

```xml
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>A .NET Aspire client integration for XYZ.</Description>
<AdditionalPackageTags>xyz client</AdditionalPackageTags>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" /> <!-- Remove if not used -->
<PackageReference Include="OpenTelemetry.Extensions.Hosting" /> <!-- Remove if no tracing -->
<!-- External SDK/libraries here -->
<PackageReference Include="Xyz.Client" />
</ItemGroup>
<ItemGroup>
<Compile Include="$(SharedDir)\HealthChecksExtensions.cs" Link="Utils\HealthChecksExtensions.cs" /> <!-- If using TryAddHealthCheck helper -->
</ItemGroup>
</Project>
```

Guidelines:

- Always include relevant SDK client dependency (e.g. `OllamaSharp`, `KurrentDB.Client`).
- Add `client` tag inside `AdditionalPackageTags`.
- Remove unused health check / telemetry dependencies if not implemented.

## Configuration & Settings Pattern

- Default configuration section: `Aspire:[IntegrationName]` or a nested path if multiple logical clients (e.g. `Aspire:KurrentDB:Client`).
- Bind settings first using `builder.Configuration.GetSection(section).Bind(settings);`.
- Connection strings: allow `builder.Configuration.GetConnectionString(connectionName)` to override (resolve canonical endpoint/URI, model, etc.).
- Provide an optional `Action<[IntegrationName]Settings>` delegate to post‑configure.
- Support keyed registration: non‑keyed (default singleton) + keyed variants (`AddKeyedXyzClient`, `AddXyzClient` for default).

## Extension Methods Design

Namespace: `Microsoft.Extensions.Hosting`.
Class name: `Aspire[IntegrationName]Extensions`.
Surface:

- `Add[IntegrationName]Client(IHostApplicationBuilder builder, string connectionName, Action<Settings>? configure = null)` – default registration using a connection name.
- `AddKeyed[IntegrationName]Client(IHostApplicationBuilder builder, string connectionName, Action<Settings>? configure = null)` – keyed registration with service key == connectionName.
- Additional overload: `AddKeyed[IntegrationName]Client(this IHostApplicationBuilder builder, object serviceKey, string connectionName, Action<Settings>? configure = null)` when custom key desired.
- Internal helper performing: bind settings, override from connection string, invoke configure delegate, register typed services, add tracing, add health check.
Validation:
- `ArgumentNullException.ThrowIfNull(builder);`
- `ArgumentException.ThrowIfNullOrEmpty(connectionName);`
Telemetry:
- If not disabled: `builder.Services.AddOpenTelemetry().WithTracing(t => t.AddSource(... or instrumentation ...));`
Health Checks:
- Use `builder.TryAddHealthCheck(new HealthCheckRegistration(name, sp => new XyzHealthCheck(settings.ConnectionString!), ...))` pattern.
HTTP Clients:
- For HTTP based SDKs: register named client `builder.Services.AddHttpClient(uniqueName, client => client.BaseAddress = settings.Endpoint);` then wrap in higher level SDK client.
Builders:
- Return a builder object (e.g. `AspireXyzClientBuilder`) containing `HostBuilder`, `ServiceKey`, `DisableTracing` to allow subsequent fluent additions (`AddChatClient()`, `AddEmbeddingGenerator()` etc.).

## Settings Class

Pattern (sealed, XML docs):

```csharp
namespace CommunityToolkit.Aspire.Xyz;
/// <summary>Represents the settings for Xyz.</summary>
public sealed class XyzSettings
{
/// <summary>Gets or sets the endpoint URI.</summary>
public Uri? Endpoint { get; set; }
/// <summary>Gets or sets the connection string (alternative to Endpoint).</summary>
public string? ConnectionString { get; set; }
/// <summary>Gets or sets a boolean indicating whether health checks are disabled.</summary>
public bool DisableHealthChecks { get; set; }
/// <summary>Gets or sets the health check timeout.</summary>
public TimeSpan? HealthCheckTimeout { get; set; }
/// <summary>Gets or sets a boolean indicating whether tracing is disabled.</summary>
public bool DisableTracing { get; set; }
// Additional feature-specific properties.
}
```

## Health Check Class (Optional)

Before implementing a custom health check, refer to https://github.com/Xabaril/AspNetCore.Diagnostics.HealthChecks and see if one exists for the service.

Otherwise, if there is no existing health check package, implement `IHealthCheck` verifying minimal connectivity (e.g. simple API call, metadata fetch). Keep fast and low-impact.

```csharp
public sealed class XyzHealthCheck : IHealthCheck
{
private readonly XyzClient _client;
public XyzHealthCheck(string connectionStringOrEndpoint) { ... }
public async Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken token)
{
try {
var ok = await _client.PingAsync(token);
return ok ? HealthCheckResult.Healthy() : new HealthCheckResult(context.Registration.FailureStatus, "Ping failed");
} catch (Exception ex) { return new HealthCheckResult(context.Registration.FailureStatus, exception: ex); }
}
}
```

Dispose if underlying client requires it.

## README.md Content

Include:

1. Overview – Purpose & features (config binding, keyed clients, health checks, telemetry).
2. Installation – `dotnet add package CommunityToolkit.Aspire.[IntegrationName]`.
3. Configuration – Sample `appsettings.json` section + connection string example.
4. Usage – Minimal `Program.cs` snippet:

```csharp
var builder = Host.CreateApplicationBuilder(args);
builder.AddXyzClient("xyz", settings => settings.SelectedModel = "small" /* optional */);
var host = builder.Build();
await host.RunAsync();
```

5. Advanced – Keyed client, telemetry disable, custom health check timeout.

## Tests

Project name: `CommunityToolkit.Aspire.[IntegrationName].Tests`.
Location: `tests/CommunityToolkit.Aspire.[IntegrationName].Tests/`.
csproj example:

```xml
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<ProjectReference Include="../../src/CommunityToolkit.Aspire.[IntegrationName]/CommunityToolkit.Aspire.[IntegrationName].csproj" />
<ProjectReference Include="../CommunityToolkit.Aspire.Testing/CommunityToolkit.Aspire.Testing.csproj" />
</ItemGroup>
</Project>
```

Test Patterns:

- Verify default registration adds singleton & optional tracing/health check.
- Verify keyed registration isolates instances.
- Verify settings override from connection string.
- If builder object surfaces fluent additions (chat/embeddings), assert added services exist.
Example Assertions:

```csharp
[Fact]
public void AddXyzClient_RegistersSingleton()
{
var hostBuilder = Host.CreateApplicationBuilder();
hostBuilder.AddXyzClient("xyz");
using var host = hostBuilder.Build();
var client = host.Services.GetRequiredService<XyzClient>();
Assert.NotNull(client);
}
```

## Example Application

Under `examples/[integrationname]/` create:

- `CommunityToolkit.Aspire.[IntegrationName].AppHost/` (AppHost project using Aspire.AppHost.Sdk if integration depends on distributed application awareness, or a plain console if not required – but prefer an AppHost for consistency).
- Additional consumer project (optional) referencing the integration package and demonstrating usage.
Minimal AppHost `AppHost.cs`:

```csharp
var builder = DistributedApplication.CreateBuilder(args);
// This is optional for client-only; if using connection strings from AppHost:
var xyz = builder.AddXyz("xyz");

builder.AddProject<Projects.XyzApi>("api")
.WithReference(xyz);

builder.Build().Run();
```

Consumer `Program.cs`:

```csharp
var hostBuilder = Host.CreateApplicationBuilder(args);
hostBuilder.AddXyzClient("xyz");
var host = hostBuilder.Build();
await host.RunAsync();
```

Add both projects to solution via `dotnet sln CommunityToolkit.Aspire.slnx add ...`.

## Adding Projects to Solution

Commands:

```bash
dotnet sln CommunityToolkit.Aspire.slnx add src/CommunityToolkit.Aspire.[IntegrationName]/CommunityToolkit.Aspire.[IntegrationName].csproj
dotnet sln CommunityToolkit.Aspire.slnx add tests/CommunityToolkit.Aspire.[IntegrationName].Tests/CommunityToolkit.Aspire.[IntegrationName].Tests.csproj
dotnet sln CommunityToolkit.Aspire.slnx add examples/[integrationname]/CommunityToolkit.Aspire.[IntegrationName].AppHost/CommunityToolkit.Aspire.[IntegrationName].AppHost.csproj
```

Update CI test matrix (`.github/workflows/tests.yml`) by re-running the test list generation script.

## Step-by-Step Plan (Use When Generating a New Client Integration)

1. Define Requirements – Target SDK, features (health checks, telemetry, keyed clients, AI abstractions, builder chaining).
2. Scaffold Project – Create `src` project, settings, extensions, optional builder & health check.
3. Implement Registration – Config binding, connection string override, service & keyed variants.
4. Telemetry & Health Checks – Add OpenTelemetry & health check only if not disabled.
5. Provide Builder Extensions – Add optional `AddChatClient`, `AddEmbeddingGenerator`, etc.
6. Example App – Create example folder with AppHost and consumer project.
7. Tests – Implement unit tests covering registration & settings.
8. Solution & CI – Add projects to solution, update tests workflow.
9. Documentation – Write README with overview, install, config, usage, advanced.
10. Review & Refine – Validate style, XML docs, tags, remove unused dependencies.

## Guidance Notes

- Avoid over-registration (no transient storms). Prefer singleton for stateless/pooled clients.
- For keyed clients, ensure service key uniqueness and symmetrical resolution usage (`GetRequiredKeyedService<T>(key)`).
- Fail fast with clear `InvalidOperationException` messages when mandatory settings missing.
- Provide Disable flags instead of conditional compilation for telemetry/health checks.
- Keep health check lightweight: single quick call, small timeout default (or unset -> framework default).
- All public members require XML docs (match existing style; no inline comments unless clarifying logic).

## Do NOT

- Create API files under `api/`.
- Add unrelated dependencies.
- Use `latest` tags for any container examples (pin version). (If example includes container references.)
- Omit the `client` tag.

## Ready Signals

An integration is ready when:

- Build succeeds (`dotnet build`).
- Tests pass (`dotnet test` scope for new project).
- README documents install & usage.
- Solution references added & CI matrix updated.

---

Use this specification without deviation when scaffolding new client integrations unless maintainers give updated guidelines.
Loading
Loading