using System.Collections.Concurrent; using Agent.Planner; namespace Agent.Core.Sessions; public sealed class AgentSession(Guid sessionId) { private readonly object _sync = new(); private readonly List _conversation = []; private readonly List _executionResults = []; private readonly ConcurrentDictionary _taskGraphs = new(); public Guid SessionId { get; } = sessionId; public DateTimeOffset CreatedAt { get; } = DateTimeOffset.UtcNow; public DateTimeOffset LastAccessAt { get; private set; } = DateTimeOffset.UtcNow; public string? Summary { get; private set; } public IReadOnlyList Conversation { get { lock (_sync) return _conversation.ToArray(); } } public IReadOnlyList ExecutionResults { get { lock (_sync) return _executionResults.ToArray(); } } /// /// TaskGraphs owned by this session, keyed by MCP Task ID. /// One TaskGraph per agent_run execution (not shared across tasks). /// public ConcurrentDictionary TaskGraphs => _taskGraphs; public void Append(ConversationMessage message) { ArgumentNullException.ThrowIfNull(message); lock (_sync) { _conversation.Add(message); LastAccessAt = DateTimeOffset.UtcNow; } } public void AppendExecutionResult(ExecutionResult result) { ArgumentNullException.ThrowIfNull(result); lock (_sync) { _executionResults.Add(result); LastAccessAt = DateTimeOffset.UtcNow; } } public void SetSummary(string summary) { ArgumentException.ThrowIfNullOrWhiteSpace(summary); lock (_sync) { Summary = summary; LastAccessAt = DateTimeOffset.UtcNow; } } /// /// Removes old conversation entries from the active context set after summary compaction. /// Audit/LLM logs are NOT affected — only the context-active representation is compacted. /// public void CompactConversation(int keepLastN) { lock (_sync) { if (_conversation.Count > keepLastN) _conversation.RemoveRange(0, _conversation.Count - keepLastN); LastAccessAt = DateTimeOffset.UtcNow; } } /// /// Removes old execution results from the active context set after summary compaction. /// public void CompactExecutionResults(int keepLastN) { lock (_sync) { if (_executionResults.Count > keepLastN) _executionResults.RemoveRange(0, _executionResults.Count - keepLastN); LastAccessAt = DateTimeOffset.UtcNow; } } }