diff --git a/src/Agents/ChatMessageStoreFactory.cs b/src/Agents/ChatMessageStoreFactory.cs
new file mode 100644
index 0000000..0bf6cb8
--- /dev/null
+++ b/src/Agents/ChatMessageStoreFactory.cs
@@ -0,0 +1,24 @@
+using Microsoft.Agents.AI;
+using static Microsoft.Agents.AI.ChatClientAgentOptions;
+
+namespace Devlooped.Agents.AI;
+
+///
+/// An implementation of a factory as a class that can provide
+/// the functionality to and integrates
+/// more easily into a service collection.
+///
+///
+/// The is a key extensibility point in Microsoft.Agents.AI, allowing
+/// storage and retrieval of chat messages.
+///
+public abstract class ChatMessageStoreFactory
+{
+ ///
+ /// Provides the implementation of
+ /// to provide message persistence.
+ ///
+ /// The context to potentially hydrate state from.
+ /// The message store that will handle chat messages.
+ public abstract ChatMessageStore CreateStore(ChatMessageStoreFactoryContext context);
+}
diff --git a/src/Agents/ConfigurableAIAgent.cs b/src/Agents/ConfigurableAIAgent.cs
index eaa9f34..b0fe1c5 100644
--- a/src/Agents/ConfigurableAIAgent.cs
+++ b/src/Agents/ConfigurableAIAgent.cs
@@ -98,6 +98,15 @@ public override IAsyncEnumerable RunStreamingAsync(IEnum
options.AIContextProviderFactory = contextFactory.CreateProvider;
}
+ if (options.ChatMessageStoreFactory is null)
+ {
+ var storeFactory = services.GetKeyedService(name) ??
+ services.GetService();
+
+ if (storeFactory is not null)
+ options.ChatMessageStoreFactory = storeFactory.CreateStore;
+ }
+
LogConfigured(name);
return (new ChatClientAgent(client, options, services.GetRequiredService(), services), options, client);
diff --git a/src/Tests/ConfigurableAgentTests.cs b/src/Tests/ConfigurableAgentTests.cs
index 66784c8..392a259 100644
--- a/src/Tests/ConfigurableAgentTests.cs
+++ b/src/Tests/ConfigurableAgentTests.cs
@@ -131,8 +131,63 @@ public void AssignsContextProviderFromService()
var options = agent.GetService();
Assert.NotNull(options?.AIContextProviderFactory);
- Assert.Same(context, options?.AIContextProviderFactory?.Invoke(new ChatClientAgentOptions.AIContextProviderFactoryContext()));
+ Assert.Same(context, options?.AIContextProviderFactory?.Invoke(new()));
+ }
+
+ [Fact]
+ public void AssignsMessageStoreFactoryFromKeyedService()
+ {
+ var builder = new HostApplicationBuilder();
+ var context = Mock.Of();
+
+ builder.Services.AddKeyedSingleton("bot",
+ Mock.Of(x
+ => x.CreateStore(It.IsAny()) == context));
+
+ builder.Configuration.AddInMemoryCollection(new Dictionary
+ {
+ ["ai:clients:chat:modelid"] = "gpt-4.1-nano",
+ ["ai:clients:chat:apikey"] = "sk-asdfasdf",
+ ["ai:agents:bot:client"] = "chat",
+ ["ai:agents:bot:options:temperature"] = "0.5",
+ });
+
+ builder.AddAIAgents();
+
+ var app = builder.Build();
+ var agent = app.Services.GetRequiredKeyedService("bot");
+ var options = agent.GetService();
+
+ Assert.NotNull(options?.ChatMessageStoreFactory);
+ Assert.Same(context, options?.ChatMessageStoreFactory?.Invoke(new()));
}
+ [Fact]
+ public void AssignsMessageStoreFactoryFromService()
+ {
+ var builder = new HostApplicationBuilder();
+ var context = Mock.Of();
+
+ builder.Services.AddSingleton(
+ Mock.Of(x
+ => x.CreateStore(It.IsAny()) == context));
+
+ builder.Configuration.AddInMemoryCollection(new Dictionary
+ {
+ ["ai:clients:chat:modelid"] = "gpt-4.1-nano",
+ ["ai:clients:chat:apikey"] = "sk-asdfasdf",
+ ["ai:agents:bot:client"] = "chat",
+ ["ai:agents:bot:options:temperature"] = "0.5",
+ });
+
+ builder.AddAIAgents();
+
+ var app = builder.Build();
+ var agent = app.Services.GetRequiredKeyedService("bot");
+ var options = agent.GetService();
+
+ Assert.NotNull(options?.ChatMessageStoreFactory);
+ Assert.Same(context, options?.ChatMessageStoreFactory?.Invoke(new()));
+ }
}