Introducing AI Conversations: Natural Language Interaction for Your Apps! Learn More
Message Store
The IMessageStore interface provides optional chat history persistence. When configured, every user message and AI response is automatically stored.
Interface
Section titled “Interface”public interface IMessageStore{ Task Store(AiChatMessage chatMessage, CancellationToken cancellationToken); Task Clear(DateTimeOffset? beforeDate = null); Task<IReadOnlyList<AiChatMessage>> Query( string? messageContains = null, DateTimeOffset? fromDate = null, DateTimeOffset? toDate = null, int? limit = null, CancellationToken cancellationToken = default );}Registration
Section titled “Registration”builder.Services.AddShinyAiConversation(opts =>{ opts.SetChatClientProvider<MyChatClientProvider>(); opts.SetMessageStore<MyMessageStore>(addAiLookupTool: true);});The addAiLookupTool parameter (default true) registers a ChatLookupAITool that allows the AI to search its own conversation history when answering questions like “What did we talk about yesterday?”
AiChatMessage
Section titled “AiChatMessage”public record AiChatMessage( string Id, string Message, DateTimeOffset Timestamp, ChatMessageDirection Direction // User or AI);Querying History
Section titled “Querying History”The service exposes history through IAiConversationService:
// Get recent messagesvar recent = await aiService.GetChatHistory(limit: 50);
// Search by contentvar results = await aiService.GetChatHistory(messageContains: "weather");
// Filter by date rangevar today = await aiService.GetChatHistory( startDate: DateTimeOffset.Now.Date, endDate: DateTimeOffset.Now);
// Clear all historyawait aiService.ClearChatHistory();
// Clear history older than 30 daysawait aiService.ClearChatHistory(beforeDate: DateTimeOffset.Now.AddDays(-30));Example: In-Memory Store
Section titled “Example: In-Memory Store”public class InMemoryMessageStore : IMessageStore{ readonly List<AiChatMessage> messages = []; readonly object sync = new();
public Task Store(AiChatMessage chatMessage, CancellationToken cancellationToken) { lock (sync) messages.Add(chatMessage); return Task.CompletedTask; }
public Task Clear(DateTimeOffset? beforeDate = null) { lock (sync) { if (beforeDate.HasValue) messages.RemoveAll(m => m.Timestamp <= beforeDate.Value); else messages.Clear(); } return Task.CompletedTask; }
public Task<IReadOnlyList<AiChatMessage>> Query( string? messageContains = null, DateTimeOffset? fromDate = null, DateTimeOffset? toDate = null, int? limit = null, CancellationToken cancellationToken = default) { lock (sync) { IEnumerable<AiChatMessage> query = messages.OrderBy(m => m.Timestamp);
if (!String.IsNullOrWhiteSpace(messageContains)) query = query.Where(m => m.Message.Contains(messageContains, StringComparison.OrdinalIgnoreCase)); if (fromDate.HasValue) query = query.Where(m => m.Timestamp >= fromDate.Value); if (toDate.HasValue) query = query.Where(m => m.Timestamp <= toDate.Value); if (limit.HasValue) query = query.Take(limit.Value);
return Task.FromResult<IReadOnlyList<AiChatMessage>>(query.ToList().AsReadOnly()); } }}Example: DocumentDB Store
Section titled “Example: DocumentDB Store”The MAUI sample uses Shiny.DocumentDb for SQLite-backed persistence:
public class DocumentDbMessageStore(IDocumentStore store) : IMessageStore{ public Task Store(AiChatMessage chatMessage, CancellationToken cancellationToken) => store.Insert(chatMessage, cancellationToken: cancellationToken);
public Task Clear(DateTimeOffset? beforeDate = null) { var query = store.Query<AiChatMessage>(); if (beforeDate.HasValue) query = query.Where(x => x.Timestamp <= beforeDate.Value); return query.ExecuteDelete(); }
public Task<IReadOnlyList<AiChatMessage>> Query( string? messageContains = null, DateTimeOffset? fromDate = null, DateTimeOffset? toDate = null, int? limit = null, CancellationToken cancellationToken = default) { var query = store.Query<AiChatMessage>().OrderBy(x => x.Timestamp);
if (!String.IsNullOrWhiteSpace(messageContains)) query = query.Where(x => x.Message.Contains(messageContains)); if (fromDate.HasValue) query = query.Where(x => x.Timestamp >= fromDate.Value); if (toDate.HasValue) query = query.Where(x => x.Timestamp <= toDate.Value); if (limit.HasValue) query = query.Paginate(0, limit.Value);
return query.ToList(cancellationToken); }}You could also implement IMessageStore with Entity Framework Core, Cosmos DB, or any other storage backend.