Skip to content

Commit ed57f0d

Browse files
authored
Merge branch 'main' into features/diagnostics_and_ls_extensions
2 parents 715a705 + 4ce53ec commit ed57f0d

18 files changed

Lines changed: 283 additions & 193 deletions

File tree

.serena/project.yml

Lines changed: 25 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,18 @@ project_name: "serena"
33

44

55
# list of languages for which language servers are started; choose from:
6-
# al bash clojure cpp csharp
7-
# csharp_omnisharp dart elixir elm erlang
8-
# fortran fsharp go groovy haskell
9-
# java julia kotlin lua markdown
10-
# matlab nix pascal perl php
11-
# php_phpactor powershell python python_jedi r
12-
# rego ruby ruby_solargraph rust scala
13-
# swift terraform toml typescript typescript_vts
14-
# vue yaml zig
6+
# al ansible bash clojure cpp
7+
# cpp_ccls crystal csharp csharp_omnisharp dart
8+
# elixir elm erlang fortran fsharp
9+
# go groovy haskell haxe hlsl
10+
# java json julia kotlin lean4
11+
# lua luau markdown matlab msl
12+
# nix ocaml pascal perl php
13+
# php_phpactor powershell python python_jedi python_ty
14+
# r rego ruby ruby_solargraph rust
15+
# scala solidity swift systemverilog terraform
16+
# toml typescript typescript_vts vue yaml
17+
# zig
1518
# (This list may be outdated. For the current list, see values of Language enum here:
1619
# https://github.com/oraios/serena/blob/main/src/solidlsp/ls_config.py
1720
# For some languages, there are alternative language servers, e.g. csharp_omnisharp, ruby_solargraph.)
@@ -45,49 +48,12 @@ read_only: false
4548

4649
# list of tool names to exclude.
4750
# This extends the existing exclusions (e.g. from the global configuration)
48-
#
49-
# Below is the complete list of tools for convenience.
50-
# To make sure you have the latest list of tools, and to view their descriptions,
51-
# execute `uv run scripts/print_tool_overview.py`.
52-
# * `activate_project`: Activates a project based on the project name or path.
53-
# * `check_onboarding_performed`: Checks whether project onboarding was already performed.
54-
# * `create_text_file`: Creates/overwrites a file in the project directory.
55-
# * `delete_memory`: Delete a memory file. Should only happen if a user asks for it explicitly,
56-
# for example by saying that the information retrieved from a memory file is no longer correct
57-
# or no longer relevant for the project.
58-
# * `edit_memory`: Replaces content matching a regular expression in a memory.
59-
# * `execute_shell_command`: Executes a shell command.
60-
# * `find_file`: Finds files in the given relative paths
61-
# * `find_referencing_symbols`: Finds symbols that reference the given symbol using the language server backend
62-
# * `find_symbol`: Performs a global (or local) search using the language server backend.
63-
# * `get_current_config`: Prints the current configuration of the agent, including the active and available projects, tools, contexts, and modes.
64-
# * `get_symbols_overview`: Gets an overview of the top-level symbols defined in a given file.
65-
# * `initial_instructions`: Provides instructions Serena usage (i.e. the 'Serena Instructions Manual')
66-
# for clients that do not read the initial instructions when the MCP server is connected.
67-
# * `insert_after_symbol`: Inserts content after the end of the definition of a given symbol.
68-
# * `insert_before_symbol`: Inserts content before the beginning of the definition of a given symbol.
69-
# * `list_dir`: Lists files and directories in the given directory (optionally with recursion).
70-
# * `list_memories`: List available memories. Any memory can be read using the `read_memory` tool.
71-
# * `onboarding`: Performs onboarding (identifying the project structure and essential tasks, e.g. for testing or building).
72-
# * `read_file`: Reads a file within the project directory.
73-
# * `read_memory`: Read the content of a memory file. This tool should only be used if the information
74-
# is relevant to the current task. You can infer whether the information
75-
# is relevant from the memory file name.
76-
# You should not read the same memory file multiple times in the same conversation.
77-
# * `rename_memory`: Renames or moves a memory. Moving between project and global scope is supported
78-
# (e.g., renaming "global/foo" to "bar" moves it from global to project scope).
79-
# * `rename_symbol`: Renames a symbol throughout the codebase using language server refactoring capabilities.
80-
# For JB, we use a separate tool.
81-
# * `replace_content`: Replaces content in a file (optionally using regular expressions).
82-
# * `replace_symbol_body`: Replaces the full definition of a symbol using the language server backend.
83-
# * `safe_delete_symbol`:
84-
# * `search_for_pattern`: Performs a search for a pattern in the project.
85-
# * `write_memory`: Write some information (utf-8-encoded) about this project that can be useful for future tasks to a memory in md format.
86-
# The memory name should be meaningful.
51+
# Find the list of tools here: https://oraios.github.io/serena/01-about/035_tools.html
8752
excluded_tools: []
8853

8954
# list of tools to include that would otherwise be disabled (particularly optional tools that are disabled by default).
9055
# This extends the existing inclusions (e.g. from the global configuration).
56+
# Find the list of tools here: https://oraios.github.io/serena/01-about/035_tools.html
9157
included_optional_tools: []
9258

9359
# initial prompt for the project. It will always be given to the LLM upon activating the project
@@ -122,14 +88,17 @@ encoding: utf-8
12288
base_modes:
12389

12490
# list of mode names that are to be activated by default.
125-
# The full set of modes to be activated is base_modes + default_modes.
91+
# The full set of modes to be activated is base_modes (from global config) + default_modes + added_modes.
12692
# If the setting is undefined, the default_modes from the global configuration (serena_config.yml) apply.
12793
# Otherwise, this overrides the setting from the global configuration (serena_config.yml).
12894
# This setting can, in turn, be overridden by CLI parameters (--mode).
95+
# Set this to [] to not use the default modes defined in the global config for this project.
96+
# See https://oraios.github.io/serena/02-usage/050_configuration.html#modes
12997
default_modes:
13098

13199
# fixed set of tools to use as the base tool set (if non-empty), replacing Serena's default set of tools.
132100
# This cannot be combined with non-empty excluded_tools or included_optional_tools.
101+
# Find the list of tools here: https://oraios.github.io/serena/01-about/035_tools.html
133102
fixed_tools: []
134103

135104
# time budget (seconds) per tool call for the retrieval of additional symbol information
@@ -167,3 +136,10 @@ ignored_memory_patterns: []
167136
# Have a look at the docstring of the constructors of the LS implementations within solidlsp (e.g., for C# or PHP) to see which options are available.
168137
# No documentation on options means no options are available.
169138
ls_specific_settings: {}
139+
140+
# list of mode names to be activated additionally for this project.
141+
# The full set of modes to be activated is base_modes (from global config) + default_modes + added_modes.
142+
# Otherwise, this setting overrides the global configuration.
143+
# Set this to a list of mode names to always include the respective modes for this project.
144+
# See https://oraios.github.io/serena/02-usage/050_configuration.html#modes
145+
added_modes:

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22

33
Status of the `main` branch. Changes prior to the next official version change will appear here.
44

5+
* General:
6+
- Breaking change in mode definitions: Projects (project.yml) can no longer override `base_modes`.
7+
Instead, they can define `added_modes` to add modes on top of base and default modes.
8+
See updated [documentation on modes](https://oraios.github.io/serena/02-usage/050_configuration.html#modes).
9+
- Serena's default configuration now uses `interactive` and `editing` as `base_modes` instead of as `default_modes`.
10+
511
* Language Servers:
612
- Java (`eclipse.jdt.ls`): Add upstream JDTLS mode for offline / restricted-network use. Setting both `jdtls_path` and `lombok_path` in `ls_specific_settings.java` makes Serena use an existing upstream JDTLS installation (e.g. `brew install jdtls`) and the system JDK 21+, skipping the ~500 MB vscode-java VSIX, Gradle, and IntelliCode downloads. New related setting `java_home` lets the user override the JDK used to launch JDTLS. Default behavior unchanged — the JDTLS workspace hash is preserved bit-for-bit for users on the default route, so existing project caches are reused without a one-time reindex; the launcher path is mixed into the hash only when `jdtls_path` is set, isolating upstream installations from the default workspace. #1415
713

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
</p>
55

66
<h3 align="center">
7-
Serena is the IDE for your coding agent.
7+
The IDE for Your Coding Agent
88
</h3>
99

1010
<div align="center">

docs/02-usage/050_configuration.md

Lines changed: 17 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -118,32 +118,26 @@ Examples of built-in modes include:
118118
119119
Find the concrete definitions of these modes [here](https://github.com/oraios/serena/tree/main/src/serena/resources/config/modes).
120120
121-
Active modes are configured in (from lowest to highest precedence):
121+
The modes to be activated are configured in:
122122
* the global configuration file (`serena_config.yml`)
123+
- defines `base_modes`, which are always included
124+
- defines `default_modes`, which can be overridden by projects or command line parameters
123125
* the project configuration file (`project.yml`)
126+
- defines `default_modes` (overriding the default modes in the global configuration)
127+
- defines `added_modes`, which are added on top
124128
* at startup via command-line parameters
125-
126-
The two former sources define both **base modes** and **default modes**.
127-
Ultimately, the active modes are the union of base modes and default modes (after applying all overrides).
128-
Command-line parameters override default modes but not base modes.
129-
Base modes should thus be used to define modes that you always want to be active, regardless of command-line parameters.
130-
131-
Command-line parameters for overriding default modes:
132-
When launching the MCP sever, specify modes using `--mode <mode-name>`; multiple modes can be specified, e.g. `--mode planning --mode no-onboarding`.
133-
134-
:::{important}
135-
By default, Serena activates the two modes `interactive` and `editing` (as defined in the global configuration).
136-
137-
As soon as you start to specify modes via the command line, only the modes you explicitly specify will be active, however.
138-
Therefore, if you want to keep the default modes, you must specify them as well.
139-
For example, to add mode `no-memories` to the default behaviour, specify
140-
```shell
141-
--mode interactive --mode editing --mode no-memories
142-
```
143-
144-
If you want to keep certain modes as always active, regardless of command-line parameters,
145-
define them as *base modes* in the global or project configuration.
146-
:::
129+
- can override default modes with `--mode`
130+
- can define modes to be added on top with `--add-mode`
131+
132+
Ultimately, the active modes are given by the union of
133+
* `base_modes` defined in the global configuration (always active)
134+
* `default_modes` (defined in the global configuration, optionally overridden by the project/CLI)
135+
* `added_modes` (defined in the project configuration/via CLI parameters)
136+
137+
So you should
138+
* define modes you definitely always want to use in `base_modes`,
139+
* define modes that you typically want to use but sometimes want to override in `default_modes`,
140+
* use `added_modes` to add modes that you need only for specific projects/sessions.
147141
148142
:::{note}
149143
**Mode Compatibility**: While you can combine modes, some may be semantically incompatible (e.g., `interactive` and `one-shot`).

src/serena/agent.py

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
from serena.config.serena_config import (
3232
LanguageBackend,
3333
ModeSelectionDefinition,
34+
ModeSelectionDefinitionWithAddedModes,
35+
ModeSelectionDefinitionWithBaseModes,
3436
NamedToolInclusionDefinition,
3537
RegisteredProject,
3638
SerenaConfig,
@@ -206,18 +208,36 @@ class ActiveModes:
206208
def __init__(self) -> None:
207209
self._configured_base_modes: Sequence[str] | None = None
208210
self._configured_default_modes: Sequence[str] | None = None
211+
self._added_modes: set[str] = set()
212+
self._dynamically_activated_mode_names: set[str] = set()
213+
"""
214+
the subset of active mode names that are dynamically activated (not necessarily enabled after project change)
215+
"""
209216
self._active_mode_names: Sequence[str] = []
217+
"""
218+
the full list of active mode names
219+
"""
210220

211221
def apply(self, mode_selection: ModeSelectionDefinition) -> None:
222+
log.debug("Applying mode selection definition %s", mode_selection)
223+
212224
# apply overrides
213-
log.debug("Applying mode selection: default_modes=%s, base_modes=%s", mode_selection.default_modes, mode_selection.base_modes)
214-
if mode_selection.base_modes is not None:
215-
self._configured_base_modes = mode_selection.base_modes
225+
if isinstance(mode_selection, ModeSelectionDefinitionWithBaseModes):
226+
if mode_selection.base_modes is not None:
227+
self._configured_base_modes = mode_selection.base_modes
216228
if mode_selection.default_modes is not None:
217229
self._configured_default_modes = mode_selection.default_modes
218230
log.debug("Current mode selection: base_modes=%s, default_modes=%s", self._configured_base_modes, self._configured_default_modes)
219231

220-
self._active_mode_names = sorted(set(self._configured_base_modes or []) | set(self._configured_default_modes or []))
232+
# apply added modes (if any)
233+
if isinstance(mode_selection, ModeSelectionDefinitionWithAddedModes):
234+
if mode_selection.added_modes:
235+
log.debug("Adding modes: %s", mode_selection.added_modes)
236+
self._added_modes.update(mode_selection.added_modes)
237+
log.debug("Current added modes: %s", self._added_modes)
238+
239+
self._dynamically_activated_mode_names = set(self._configured_default_modes or []) | self._added_modes
240+
self._active_mode_names = sorted(set(self._configured_base_modes or []) | self._dynamically_activated_mode_names)
221241

222242
def get_mode_names(self) -> Sequence[str]:
223243
return self._active_mode_names
@@ -231,8 +251,8 @@ def get_mode_instance(cls, mode_name: str) -> SerenaAgentMode:
231251
def get_modes(self) -> Sequence[SerenaAgentMode]:
232252
return [self.get_mode_instance(mode_name) for mode_name in self._active_mode_names]
233253

234-
def get_default_modes(self) -> Sequence[SerenaAgentMode]:
235-
return [self.get_mode_instance(mode_name) for mode_name in self._configured_default_modes or []]
254+
def get_dynamically_activated_modes(self) -> Sequence[SerenaAgentMode]:
255+
return [self.get_mode_instance(mode_name) for mode_name in self._dynamically_activated_mode_names]
236256

237257
def get_base_modes(self) -> Sequence[SerenaAgentMode]:
238258
return [self.get_mode_instance(mode_name) for mode_name in self._configured_base_modes or []]
@@ -511,8 +531,7 @@ def __init__(
511531
:param serena_config: the Serena configuration or None to read the configuration from the default location.
512532
:param context: the context in which the agent is operating, None for default context.
513533
The context may adjust prompts, tool availability, and tool descriptions.
514-
:param modes: list of modes in which the agent is operating (they will be combined), None for default modes.
515-
The modes may adjust prompts, tool availability, and tool descriptions.
534+
:param modes: mode selection definition to apply for this session
516535
:param memory_log_handler: a MemoryLogHandler instance from which to read log messages; if None, a new one will be created
517536
if necessary.
518537
"""
@@ -521,7 +540,7 @@ def __init__(
521540
self._gui_log_viewer: Optional["GuiLogViewer"] = None
522541
self._dashboard_manager: DashboardManager | None = None
523542
self._project_prompt_status = ProjectPromptProvisionStatus()
524-
self._mode_overrides = modes
543+
self._session_mode_selection_definition = modes
525544
self.version = serena_version()
526545

527546
# obtain serena configuration using the decoupled factory function
@@ -712,9 +731,11 @@ def _create_base_toolset(
712731
# * base modes: These cannot be changed, so they are fully applied
713732
for base_mode in modes.get_base_modes():
714733
tool_inclusion_definitions.append(base_mode)
715-
# * default modes: When not in a single-project context, these modes are dynamic (can later be turned off),
716-
# so we consider only their inclusions (but not their exclusions, because these must not be hard)
717-
for mode in modes.get_default_modes():
734+
# * dynamically activated modes:
735+
# - When not in a single-project context, these modes can later be turned off,
736+
# so we consider only their inclusions (but not their exclusions, because these must not be hard).
737+
# - In a single-project context, we can consider them fully.
738+
for mode in modes.get_dynamically_activated_modes():
718739
if is_single_project:
719740
tool_inclusion_definitions.append(mode)
720741
else:
@@ -986,8 +1007,8 @@ def _update_active_modes(self, log_message: bool = True) -> None:
9861007
self._active_modes.apply(self.serena_config)
9871008
if self._active_project:
9881009
self._active_modes.apply(self._active_project.project_config)
989-
if self._mode_overrides:
990-
self._active_modes.apply(self._mode_overrides)
1010+
if self._session_mode_selection_definition:
1011+
self._active_modes.apply(self._session_mode_selection_definition)
9911012
if log_message:
9921013
active_mode_names = self._active_modes.get_mode_names()
9931014
log.info(f"Active modes ({len(active_mode_names)}): {', '.join(active_mode_names)}")

0 commit comments

Comments
 (0)