diff --git a/src/RockBot.Agent/ClearContextHandler.cs b/src/RockBot.Agent/ClearContextHandler.cs
new file mode 100644
index 0000000..ed93c76
--- /dev/null
+++ b/src/RockBot.Agent/ClearContextHandler.cs
@@ -0,0 +1,42 @@
+using Microsoft.Extensions.Logging;
+using RockBot.Host;
+using RockBot.Messaging;
+using RockBot.UserProxy;
+
+namespace RockBot.Agent;
+
+///
+/// Handles by clearing conversation memory
+/// for the session. Long-term memory and conversation logs are preserved.
+///
+internal sealed class ClearContextHandler(
+ IConversationMemory conversationMemory,
+ ISessionTracker sessionTracker,
+ IMessagePublisher publisher,
+ AgentIdentity agent,
+ ILogger logger) : IMessageHandler
+{
+ public async Task HandleAsync(ClearContextRequest message, MessageHandlerContext context)
+ {
+ var ct = context.CancellationToken;
+
+ // Cancel any in-flight work for this session
+ var handle = sessionTracker.BeginSession(message.SessionId, ct);
+ sessionTracker.EndSession(message.SessionId, handle.Generation);
+
+ // Clear conversation memory (ephemeral turns only — logs are preserved)
+ await conversationMemory.ClearAsync(message.SessionId, ct);
+
+ logger.LogInformation("Cleared conversation context for session {SessionId}", message.SessionId);
+
+ var reply = new AgentReply
+ {
+ Content = "Context cleared — starting fresh.",
+ SessionId = message.SessionId,
+ AgentName = agent.Name,
+ IsFinal = true
+ };
+ var envelope = reply.ToEnvelope(source: agent.Name);
+ await publisher.PublishAsync(UserProxyTopics.UserResponse, envelope, ct);
+ }
+}
diff --git a/src/RockBot.Agent/Program.cs b/src/RockBot.Agent/Program.cs
index d925722..2200462 100644
--- a/src/RockBot.Agent/Program.cs
+++ b/src/RockBot.Agent/Program.cs
@@ -227,6 +227,7 @@ IChatClient BuildClient(LlmTierConfig config)
agent.HandleMessage();
agent.HandleMessage();
agent.HandleMessage();
+ agent.HandleMessage();
agent.HandleMessage();
agent.HandleMessage();
agent.WithSavedResponses();
@@ -237,6 +238,7 @@ IChatClient BuildClient(LlmTierConfig config)
agent.SubscribeTo(UserProxyTopics.UserMessage);
agent.SubscribeTo(UserProxyTopics.UserFeedback);
agent.SubscribeTo(UserProxyTopics.CancelSession);
+ agent.SubscribeTo(UserProxyTopics.ClearContext);
agent.SubscribeTo(UserProxyTopics.ConversationHistoryRequest);
agent.SubscribeTo(UserProxyTopics.AgentInfoRequest);
agent.SubscribeTo(UserProxyTopics.SaveResponseRequest);
diff --git a/src/RockBot.UserProxy.Abstractions/ClearContextRequest.cs b/src/RockBot.UserProxy.Abstractions/ClearContextRequest.cs
new file mode 100644
index 0000000..f5c7b31
--- /dev/null
+++ b/src/RockBot.UserProxy.Abstractions/ClearContextRequest.cs
@@ -0,0 +1,10 @@
+namespace RockBot.UserProxy;
+
+///
+/// Message sent from the user proxy to clear conversation context for a session.
+/// Long-term memory and conversation logs are preserved.
+///
+public sealed record ClearContextRequest
+{
+ public required string SessionId { get; init; }
+}
diff --git a/src/RockBot.UserProxy.Abstractions/UserProxyTopics.cs b/src/RockBot.UserProxy.Abstractions/UserProxyTopics.cs
index 12fae4e..4a92fc9 100644
--- a/src/RockBot.UserProxy.Abstractions/UserProxyTopics.cs
+++ b/src/RockBot.UserProxy.Abstractions/UserProxyTopics.cs
@@ -8,6 +8,7 @@ public static class UserProxyTopics
public const string UserMessage = "user.message";
public const string UserResponse = "user.response";
public const string CancelSession = "user.cancel";
+ public const string ClearContext = "user.context.clear";
public const string ConversationHistoryRequest = "user.history.request";
public const string ConversationHistoryResponse = "user.history.response";
public const string UserFeedback = "user.feedback";
diff --git a/src/RockBot.UserProxy.Blazor/Pages/Chat.razor b/src/RockBot.UserProxy.Blazor/Pages/Chat.razor
index 7db3a48..af9bab4 100644
--- a/src/RockBot.UserProxy.Blazor/Pages/Chat.razor
+++ b/src/RockBot.UserProxy.Blazor/Pages/Chat.razor
@@ -420,6 +420,21 @@
currentMessage = string.Empty;
await JSRuntime.InvokeVoidAsync("chatHelpers.addToHistory", messageInput, messageContent);
+ // Handle /clear command — pure plumbing, no LLM involved
+ if (messageContent.Equals("/clear", StringComparison.OrdinalIgnoreCase))
+ {
+ ChatState.ClearMessages();
+ try
+ {
+ await ProxyService.ClearContextAsync(SessionId);
+ }
+ catch (Exception ex)
+ {
+ ChatState.AddError($"Could not clear agent context: {ex.Message}");
+ }
+ return;
+ }
+
ChatState.AddUserMessage(messageContent, UserId, SessionId);
ChatState.SetProcessing(true);
diff --git a/src/RockBot.UserProxy.Blazor/Services/ChatStateService.cs b/src/RockBot.UserProxy.Blazor/Services/ChatStateService.cs
index bb6cb1d..f459689 100644
--- a/src/RockBot.UserProxy.Blazor/Services/ChatStateService.cs
+++ b/src/RockBot.UserProxy.Blazor/Services/ChatStateService.cs
@@ -273,6 +273,20 @@ public void AddError(string message)
NotifyStateChanged();
}
+ // ── Clear context ───────────────────────────────────────────────────────
+
+ public void ClearMessages()
+ {
+ lock (_lock)
+ {
+ _messages.Clear();
+ _activeActivityLogs.Clear();
+ }
+ _currentThinkingMessage = null;
+ _isProcessing = false;
+ NotifyStateChanged();
+ }
+
// ── Saved references ────────────────────────────────────────────────────
public void AddSavedReference(string id, string label, string content, string agentName)
diff --git a/src/RockBot.UserProxy/UserProxyService.cs b/src/RockBot.UserProxy/UserProxyService.cs
index 429e4b6..7d67e2b 100644
--- a/src/RockBot.UserProxy/UserProxyService.cs
+++ b/src/RockBot.UserProxy/UserProxyService.cs
@@ -333,6 +333,18 @@ public async Task CancelSessionAsync(string sessionId, CancellationToken cancell
logger.LogInformation("Published cancel request for session {SessionId}", sessionId);
}
+ ///
+ /// Publishes a clear context request to reset conversation memory for the given session.
+ /// Long-term memory and conversation logs are preserved.
+ ///
+ public async Task ClearContextAsync(string sessionId, CancellationToken cancellationToken = default)
+ {
+ var request = new ClearContextRequest { SessionId = sessionId };
+ var envelope = request.ToEnvelope(source: options.ProxyId);
+ await publisher.PublishAsync(UserProxyTopics.ClearContext, envelope, cancellationToken);
+ logger.LogInformation("Published clear context request for session {SessionId}", sessionId);
+ }
+
internal Task HandleResponseAsync(MessageEnvelope envelope, CancellationToken ct)
{
AgentReply? reply;