From 45554623f8ba9413c6abb3ebaa447667f0c63817 Mon Sep 17 00:00:00 2001 From: MischaPanch Date: Tue, 28 Oct 2025 11:15:10 +0100 Subject: [PATCH] Dashboard: added section displaying memories, show path to mode/context on hover [ci skip] --- src/serena/dashboard.py | 12 ++++- src/serena/resources/dashboard/dashboard.js | 50 ++++++++++++++++----- 2 files changed, 49 insertions(+), 13 deletions(-) diff --git a/src/serena/dashboard.py b/src/serena/dashboard.py index 0468e0fa..7f90d1e2 100644 --- a/src/serena/dashboard.py +++ b/src/serena/dashboard.py @@ -49,6 +49,7 @@ class ResponseConfigOverview(BaseModel): available_tools: list[dict[str, str | bool]] available_modes: list[dict[str, str | bool]] available_contexts: list[dict[str, str | bool]] + available_memories: list[str] | None class SerenaDashboardAPI: @@ -162,11 +163,12 @@ class SerenaDashboardAPI: context_info = { "name": context.name, "description": context.description, + "path": SerenaAgentContext.get_path(context.name), } # Get active modes modes = self._agent.get_active_modes() - modes_info = [{"name": mode.name, "description": mode.description} for mode in modes] + modes_info = [{"name": mode.name, "description": mode.description, "path": SerenaAgentMode.get_path(mode.name)} for mode in modes] active_mode_names = [mode.name for mode in modes] # Get active tools @@ -203,6 +205,7 @@ class SerenaDashboardAPI: { "name": mode_name, "is_active": mode_name in active_mode_names, + "path": SerenaAgentMode.get_path(mode_name), } ) @@ -214,6 +217,7 @@ class SerenaDashboardAPI: { "name": context_name, "is_active": context_name == context.name, + "path": SerenaAgentContext.get_path(context_name), } ) @@ -223,6 +227,11 @@ class SerenaDashboardAPI: full_stats = self._tool_usage_stats.get_tool_stats_dict() tool_stats_summary = {name: {"num_calls": stats["num_times_called"]} for name, stats in full_stats.items()} + # Get available memories if ReadMemoryTool is active + available_memories = None + if self._agent.tool_is_active("read_memory") and project is not None: + available_memories = project.memories_manager.list_memories() + return ResponseConfigOverview( active_project=project_info, context=context_info, @@ -233,6 +242,7 @@ class SerenaDashboardAPI: available_tools=available_tools, available_modes=available_modes, available_contexts=available_contexts, + available_memories=available_memories, ) def _shutdown(self) -> None: diff --git a/src/serena/resources/dashboard/dashboard.js b/src/serena/resources/dashboard/dashboard.js index b1c53bc3..1c5a34b8 100644 --- a/src/serena/resources/dashboard/dashboard.js +++ b/src/serena/resources/dashboard/dashboard.js @@ -210,9 +210,11 @@ class Dashboard { } displayConfig(config) { - // Check if tools section is currently expanded - const $existingContent = $('#tools-content'); - const wasExpanded = $existingContent.is(':visible'); + // Check if tools and memories sections are currently expanded + const $existingToolsContent = $('#tools-content'); + const $existingMemoriesContent = $('#memories-content'); + const wasToolsExpanded = $existingToolsContent.is(':visible'); + const wasMemoriesExpanded = $existingMemoriesContent.is(':visible'); let html = '
'; @@ -225,17 +227,16 @@ class Dashboard { // Context info html += '
Context:
'; - html += '
' + config.context.name + '
'; + html += '
' + config.context.name + '
'; // Modes info html += '
Active Modes:
'; html += '
'; if (config.modes.length > 0) { - html += '
    '; - config.modes.forEach(function(mode) { - html += '
  • ' + mode.name + '
  • '; + const modeSpans = config.modes.map(function(mode) { + return '' + mode.name + ''; }); - html += '
'; + html += modeSpans.join(', '); } else { html += 'None'; } @@ -247,15 +248,30 @@ class Dashboard { html += '
'; html += '

'; html += 'Active Tools (' + config.active_tools.length + ')'; - html += '▼'; + html += '▼'; html += '

'; - html += '
'; + html += '
'; config.active_tools.forEach(function(tool) { html += '
' + tool + '
'; }); html += '
'; html += '
'; + // Available memories - collapsible (only show if memories exist) + if (config.available_memories && config.available_memories.length > 0) { + html += '
'; + html += '

'; + html += 'Available Memories (' + config.available_memories.length + ')'; + html += '▼'; + html += '

'; + html += '
'; + config.available_memories.forEach(function(memory) { + html += '
' + memory + '
'; + }); + html += '
'; + html += '
'; + } + this.$configDisplay.html(html); // Re-attach collapsible handler for the newly created tools header @@ -267,6 +283,16 @@ class Dashboard { $content.slideToggle(300); $icon.toggleClass('expanded'); }); + + // Re-attach collapsible handler for the newly created memories header + $('#memories-header').click(function() { + const $header = $(this); + const $content = $('#memories-content'); + const $icon = $header.find('.toggle-icon'); + + $content.slideToggle(300); + $icon.toggleClass('expanded'); + }); } displayBasicStats(stats) { @@ -340,7 +366,7 @@ class Dashboard { let html = ''; modes.forEach(function(mode) { const activeClass = mode.is_active ? ' active' : ''; - html += '
' + mode.name + '
'; + html += '
' + mode.name + '
'; }); this.$availableModesDisplay.html(html); @@ -355,7 +381,7 @@ class Dashboard { let html = ''; contexts.forEach(function(context) { const activeClass = context.is_active ? ' active' : ''; - html += '
' + context.name + '
'; + html += '
' + context.name + '
'; }); this.$availableContextsDisplay.html(html);