diff --git a/dotnet/src/Microsoft.Agents.AI.Hosting.A2A.AspNetCore/Microsoft.Agents.AI.Hosting.A2A.AspNetCore.csproj b/dotnet/src/Microsoft.Agents.AI.Hosting.A2A.AspNetCore/Microsoft.Agents.AI.Hosting.A2A.AspNetCore.csproj
index 200aa29ccc..b91ea40baa 100644
--- a/dotnet/src/Microsoft.Agents.AI.Hosting.A2A.AspNetCore/Microsoft.Agents.AI.Hosting.A2A.AspNetCore.csproj
+++ b/dotnet/src/Microsoft.Agents.AI.Hosting.A2A.AspNetCore/Microsoft.Agents.AI.Hosting.A2A.AspNetCore.csproj
@@ -27,6 +27,7 @@
+
diff --git a/dotnet/src/Microsoft.Agents.AI.Hosting.AspNetCore/ServiceCollectionExtensions.cs b/dotnet/src/Microsoft.Agents.AI.Hosting.AspNetCore/ServiceCollectionExtensions.cs
new file mode 100644
index 0000000000..1ba2a16db8
--- /dev/null
+++ b/dotnet/src/Microsoft.Agents.AI.Hosting.AspNetCore/ServiceCollectionExtensions.cs
@@ -0,0 +1,42 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+using System;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace Microsoft.Agents.AI.Hosting;
+
+///
+/// Extension methods for configuring AI hosting services in an .
+///
+public static class ServiceCollectionExtensions
+{
+ ///
+ /// Registers a that uses claims from the current user's identity
+ /// to generate session isolation keys.
+ ///
+ /// The to add services to.
+ /// Optional configuration for the claims-based session isolation key provider.
+ /// The so that additional calls can be chained.
+ ///
+ /// This method requires to be registered in the service collection.
+ /// Ensure that services.AddHttpContextAccessor() has been called before using this method.
+ ///
+ public static IServiceCollection UseClaimsBasedSessionIsolation(
+ this IServiceCollection services,
+ ClaimsIdentitySessionIsolationKeyProviderOptions? options = null)
+ {
+ options ??= new();
+ ServiceDescriptor descriptor = new(typeof(SessionIsolationKeyProvider), CreateIsolationKeyProvider, ServiceLifetime.Scoped);
+ services.Add(descriptor);
+
+ return services;
+
+ object CreateIsolationKeyProvider(IServiceProvider serviceProvider)
+ {
+ IHttpContextAccessor contextAccessor = serviceProvider.GetRequiredService();
+
+ return new ClaimsIdentitySessionIsolationKeyProvider(contextAccessor, options);
+ }
+ }
+}
diff --git a/dotnet/src/Microsoft.Agents.AI.Hosting/HostedAgentBuilderExtensions.cs b/dotnet/src/Microsoft.Agents.AI.Hosting/HostedAgentBuilderExtensions.cs
index d1397fcda4..ed11840f5e 100644
--- a/dotnet/src/Microsoft.Agents.AI.Hosting/HostedAgentBuilderExtensions.cs
+++ b/dotnet/src/Microsoft.Agents.AI.Hosting/HostedAgentBuilderExtensions.cs
@@ -3,6 +3,7 @@
using System;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Options;
using Microsoft.Shared.Diagnostics;
namespace Microsoft.Agents.AI.Hosting;
@@ -16,12 +17,11 @@ public static class HostedAgentBuilderExtensions
/// Configures the host agent builder to use an in-memory session store for agent session management.
///
/// The host agent builder to configure with the in-memory session store.
+ /// When , wraps the session store with an
+ /// to provide isolation-key-based scoping for sessions. Defaults to .
/// The same instance, configured to use an in-memory session store.
- public static IHostedAgentBuilder WithInMemorySessionStore(this IHostedAgentBuilder builder)
- {
- builder.ServiceCollection.AddKeyedSingleton(builder.Name, new InMemoryAgentSessionStore());
- return builder;
- }
+ public static IHostedAgentBuilder WithInMemorySessionStore(this IHostedAgentBuilder builder, bool withIsolation = true)
+ => builder.WithSessionStore(new InMemoryAgentSessionStore(), withIsolation);
///
/// Registers the specified agent session store with the host agent builder, enabling session-specific storage for
@@ -29,12 +29,11 @@ public static class HostedAgentBuilderExtensions
///
/// The host agent builder to configure with the session store. Cannot be null.
/// The agent session store instance to register. Cannot be null.
+ /// When , wraps the session store with an
+ /// to provide isolation-key-based scoping for sessions. Defaults to .
/// The same host agent builder instance, allowing for method chaining.
- public static IHostedAgentBuilder WithSessionStore(this IHostedAgentBuilder builder, AgentSessionStore store)
- {
- builder.ServiceCollection.AddKeyedSingleton(builder.Name, store);
- return builder;
- }
+ public static IHostedAgentBuilder WithSessionStore(this IHostedAgentBuilder builder, AgentSessionStore store, bool withIsolation = true)
+ => builder.WithSessionStore((sp, key) => store, ServiceLifetime.Singleton, withIsolation);
///
/// Configures the host agent builder to use a custom session store implementation for agent sessions.
@@ -44,16 +43,36 @@ public static class HostedAgentBuilderExtensions
/// name.
/// The DI service lifetime for the session store registration. Defaults to
/// because session stores persist conversation state across requests and are consumed independently of the agent's lifetime.
+ /// When , wraps the session store with an
+ /// to provide isolation-key-based scoping for sessions. Defaults to .
/// The same host agent builder instance, enabling further configuration.
- public static IHostedAgentBuilder WithSessionStore(this IHostedAgentBuilder builder, Func createAgentSessionStore, ServiceLifetime lifetime = ServiceLifetime.Singleton)
+ public static IHostedAgentBuilder WithSessionStore(this IHostedAgentBuilder builder, Func createAgentSessionStore, ServiceLifetime lifetime = ServiceLifetime.Singleton, bool withIsolation = true)
{
builder.ServiceCollection.AddKeyedService(builder.Name, (sp, key) =>
{
Throw.IfNull(key);
var keyString = key as string;
Throw.IfNullOrEmpty(keyString);
- return createAgentSessionStore(sp, keyString) ??
+
+ AgentSessionStore store = createAgentSessionStore(sp, keyString) ??
throw new InvalidOperationException($"The agent session store factory did not return a valid {nameof(AgentSessionStore)} instance for key '{keyString}'.");
+
+ if (withIsolation && store.GetService() is null)
+ {
+ var isolationKeyProvider = sp.GetService();
+
+ // Best efforts options getting
+ IsolationKeyScopedAgentSessionStoreOptions? options = sp.GetService();
+ if (options is null)
+ {
+ var optionsProvider = sp.GetService>();
+ options = optionsProvider?.Value;
+ }
+
+ store = new IsolationKeyScopedAgentSessionStore(store, isolationKeyProvider, options ?? new());
+ }
+
+ return store;
}, lifetime);
return builder;
}