using Orleans; namespace OrleansAspireLab.Grains; // Deux familles de cles dans ce lab : // - IConversationGrain : IGrainWithGuidKey — identite GENEE par l'appelant // (Guid.NewGuid()). Aucun registre central de noms : deux conversations // ouvertes simultanement ne peuvent pas entrer en collision. // - ITokenCounterGrain : IGrainWithStringKey — cle NOMMEE (le nom du modele), // partagee entre toutes les conversations du cluster. public interface IConversationGrain : IGrainWithGuidKey { Task AppendTurnAsync(string role, string content); Task> GetHistoryAsync(); Task TurnCountAsync(); Task SummaryAsync(); Task RouteTokensAsync(string modelKey, int tokens); Task GetTokenTotalAsync(); } public interface ITokenCounterGrain : IGrainWithStringKey { Task RecordUsage(int tokens); Task GetTotalAsync(); Task EstimateCostAsync(int centsPerThousandTokens); } public class ConversationGrain : Grain, IConversationGrain { private readonly List<(string Role, string Content)> _turns = new(); private int _tokenTotal; public Task AppendTurnAsync(string role, string content) { _turns.Add((role, content)); return Task.FromResult(_turns.Count); } public Task> GetHistoryAsync() => Task.FromResult>( _turns.Select(t => $"{t.Role} : {t.Content}").ToList()); public Task TurnCountAsync() => Task.FromResult(_turns.Count); // Exercice 1 : retourner une ligne de resume au format exact // " tours, dernier role : " (chaine vide si aucun tour). public Task SummaryAsync() { Console.WriteLine("Exercice a completer"); return Task.FromResult(string.Empty); // TODO etudiant } // Exercice 2 : cumuler les tokens LOCALEMENT (_tokenTotal) ET deleguer au // grain ITokenCounterGrain identifie par modelKey (via la propriete protegee GrainFactory). public Task RouteTokensAsync(string modelKey, int tokens) { Console.WriteLine("Exercice a completer"); return Task.CompletedTask; // TODO etudiant } public Task GetTokenTotalAsync() => Task.FromResult(_tokenTotal); } public class TokenCounterGrain : Grain, ITokenCounterGrain { private int _total; public Task RecordUsage(int tokens) { _total += tokens; return Task.FromResult(_total); } public Task GetTotalAsync() => Task.FromResult(_total); // Exercice 3 : retourner le cout total en cents pour un tarif de // centsPerThousandTokens (arrondi a 2 decimales, Math.Round). public Task EstimateCostAsync(int centsPerThousandTokens) { Console.WriteLine("Exercice a completer"); return Task.FromResult(-1m); // TODO etudiant } }