From 505d520c80055bd18ad7d029a897f18f78186e52 Mon Sep 17 00:00:00 2001 From: Dominik Jain Date: Tue, 14 Apr 2026 14:59:56 +0200 Subject: [PATCH] SerenaAgent._create_base_toolset: Account for mode activation no longer being dynamic Fully apply exclusions when in a single-project context Fixes #1336 --- CHANGELOG.md | 2 ++ src/serena/agent.py | 36 ++++++++++++++++++++---------------- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 92a95e73..3ce06696 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ Status of the `main` branch. Changes prior to the next official version change w * General: - Support environment variable `SERENA_USAGE_REPORTING` (set to `false` to disable usage reporting) - Extended the list of always ignored directories (by language servers) with common cases. + - Improve exposed toolset: With mode switching no longer being a feature, we now fully apply tool exclusions + defined by modes when in a single-project context (limiting exposed tools to a minimum) - Fix: When scanning for `.gitignore` files, the presence of files that could not be made relative to the project root would cause the scan to fail. #1317 diff --git a/src/serena/agent.py b/src/serena/agent.py index 322db7c8..30ef7cc5 100644 --- a/src/serena/agent.py +++ b/src/serena/agent.py @@ -453,31 +453,35 @@ class SerenaAgent: tool_inclusion_definitions.append(serena_config) tool_inclusion_definitions.append(context) + # determine whether we are operating in a single-project context + # (i.e. the project that is activated at startup is the only project that will be worked with throughout the session) + is_single_project = context.single_project and project is not None + # consider modes - # Since modes can be dynamically turned on and off, we don't include their definitions directly, - # For the initially active dynamic modes, we make sure that the tools they enable are included. - for mode in modes.get_default_modes(): - tool_inclusion_definitions.append( - NamedToolInclusionDefinition( - name=f"InitialDynamicModeInclusions[{mode.name}]", included_optional_tools=mode.included_optional_tools - ) - ) - # For the base modes, we also apply the tool exclusions, since they apply throughout the entire session + # * base modes: These cannot be changed, so they are fully applied for base_mode in modes.get_base_modes(): - tool_inclusion_definitions.append( - NamedToolInclusionDefinition( - name=f"BaseMode[{base_mode.name}]", - included_optional_tools=base_mode.included_optional_tools, - excluded_tools=base_mode.excluded_tools, + tool_inclusion_definitions.append(base_mode) + # * default modes: When not in a single-project context, these modes are dynamic (can later be turned off), + # so we consider only their inclusions (but not their exclusions, because these must not be hard) + for mode in modes.get_default_modes(): + if is_single_project: + tool_inclusion_definitions.append(mode) + else: + # Since modes can be dynamically turned on and off, we don't include their definitions directly, + # For the initially active dynamic modes, we make sure that the tools they enable are included. + tool_inclusion_definitions.append( + NamedToolInclusionDefinition( + name=f"InitialDynamicModeInclusions[{mode.name}]", included_optional_tools=mode.included_optional_tools + ) ) - ) # When in a single-project context, the agent is assumed to work on a single project, and we thus # want to apply that project's tool exclusions/inclusions from the get-go, limiting the set # of tools that will be exposed to the client. # Furthermore, we disable tools that are only relevant for project activation. # So if the project exists, we apply all the aforementioned exclusions. - if context.single_project and project is not None: + if is_single_project: + assert project is not None log.info( "Applying tool inclusion/exclusion definitions for single-project context based on project '%s'", project.project_name,