Merge branch 'main' into habaneraa/main

This commit is contained in:
Michael Panchenko committed 2026-03-23 14:34:49 +01:00
commit 6734e5d03c
11 files changed
+40 -16

No files matched your search

+2 -2
View File
@@ -80,8 +80,8 @@ Serena incorporates a powerful abstraction layer for the integration of language
that implement the language server protocol (LSP).
The underlying language servers are typically open-source projects (like Serena) or at least freely available for use.
With Serena's LSP library, we provide **support for over 30 programming languages**, including
AL, Ansible, Bash, C#, C/C++, Clojure, Dart, Elixir, Elm, Erlang, Fortran, GLSL, Go, Groovy (partial support), Haskell, HLSL, Java, Javascript, Julia, Kotlin, Lean 4, Lua, Luau, Markdown, MATLAB, Nix, OCaml, Perl, PHP, PowerShell, Python, R, Ruby, Rust, Scala, Solidity, Swift, TOML, TypeScript, WGSL, YAML, and Zig.
With Serena's LSP library, we provide **support for over 40 programming languages**, including
AL, Ansible, Bash, C#, C/C++, Clojure, Dart, Elixir, Elm, Erlang, Fortran, F# (currently with some bugs), GLSL, Go, Groovy (partial support), Haskell, HLSL, Java, Javascript, Julia, Kotlin, Lean 4, Lua, Luau, Markdown, MATLAB, Nix, OCaml, Perl, PHP, PowerShell, Python, R, Ruby, Rust, Scala, Solidity, Swift, TOML, TypeScript, WGSL, YAML, and Zig.
> [!IMPORTANT]
> Some language servers require additional dependencies to be installed; see the [Language Support](https://oraios.github.io/serena/01-about/020_programming-languages.html) page for details.
+8 -2
View File
@@ -483,7 +483,7 @@ class SerenaAgent:
else:
log_path = SerenaPaths().last_returned_log_file_path
if log_path is not None:
return f"Find the current log file here: f{log_path}"
return f"Find the current log file here: {log_path}"
else:
return "Unfortunately, logs are not available. We recommend enabling the web dashboard/logging in general."
@@ -699,6 +699,11 @@ class SerenaAgent:
f"(2) Configure one MCP server per backend in your client."
)
# shut down the previously active project to release its language server processes
if self._active_project is not None:
log.info(f"Shutting down previously active project '{self._active_project.project_name}' before switching")
self._active_project.shutdown()
self._active_project = project
project.set_agent(self)
@@ -845,7 +850,8 @@ class SerenaAgent:
"""
Shuts down the agent, freeing resources and stopping background tasks.
"""
if not hasattr(self, "_is_initialized"):
# guard against __del__ being called on a partially constructed instance
if not hasattr(self, "_active_project"):
return
log.info("SerenaAgent is shutting down ...")
if self._active_project is not None:
+5 -1
View File
@@ -5,7 +5,7 @@ from collections.abc import Callable
from pathlib import Path
from typing import TYPE_CHECKING, Any, Self
from flask import Flask, Response, request, send_from_directory
from flask import Flask, Response, redirect, request, send_from_directory
from pydantic import BaseModel
from sensai.util import logging
@@ -148,6 +148,10 @@ class SerenaDashboardAPI:
return self._memory_log_handler
def _setup_routes(self) -> None:
@self._app.route("/")
def redirect_to_dashboard() -> Response:
return redirect("/dashboard/") # type: ignore[return-value]
# Static files
@self._app.route("/dashboard/<path:filename>")
def serve_dashboard(filename: str) -> Response:
+6 -2
View File
@@ -341,8 +341,12 @@ class SerenaMCPFactory:
openai_tool_compatible = self.context.name in ["chatgpt", "codex", "oaicompat-agent"]
self._set_mcp_tools(mcp_server, openai_tool_compatible=openai_tool_compatible)
log.info("MCP server lifetime setup complete")
yield
log.info("MCP server shutting down")
try:
yield
finally:
log.info("MCP server shutting down")
if self.agent is not None:
self.agent.shutdown()
def _get_initial_instructions(self) -> str:
assert self.agent is not None
@@ -118,7 +118,7 @@ class CCLS(SolidLanguageServer):
"workspaceFolders": [
{
"uri": root_uri,
"name": "$name",
"name": os.path.basename(repository_absolute_path),
}
],
# ccls supports initializationOptions but none are required for basic functionality
@@ -228,7 +228,7 @@ class ClangdLanguageServer(SolidLanguageServer):
"workspaceFolders": [
{
"uri": root_uri,
"name": "$name",
"name": os.path.basename(repository_absolute_path),
}
],
}
@@ -2,6 +2,7 @@
import logging
import os
import pathlib
import shutil
import subprocess
import threading
@@ -134,7 +135,7 @@ class ErlangLanguageServer(SolidLanguageServer):
initialize_params = {
"processId": None,
"rootPath": self.repository_root_path,
"rootUri": f"file://{self.repository_root_path}",
"rootUri": pathlib.Path(self.repository_root_path).as_uri(),
"capabilities": {
"textDocument": {
"synchronization": {"didSave": True},
@@ -166,7 +166,7 @@ class FSharpLanguageServer(SolidLanguageServer):
"documentHighlight": {"dynamicRegistration": True},
"documentSymbol": {
"dynamicRegistration": True,
"symbolKind": {"valueSet": list(range(1, 26))}, # All SymbolKind values
"symbolKind": {"valueSet": list(range(1, 27))}, # All SymbolKind values (1-26)
"hierarchicalDocumentSymbolSupport": True,
},
"codeAction": {
+1 -1
View File
@@ -817,7 +817,7 @@ class SolidLanguageServer(ABC):
Delete text between the given start and end positions in the given file and return the deleted text.
"""
if not self.server_started:
log.error("insert_text_at_position called before Language Server started")
log.error("delete_text_between_positions called before Language Server started")
raise SolidLSPException("Language Server not started")
absolute_file_path = str(PurePath(self.repository_root_path, relative_file_path))
+11 -4
View File
@@ -1,4 +1,5 @@
import platform
import shlex
import subprocess
@@ -15,8 +16,14 @@ def subprocess_kwargs() -> dict:
def quote_arg(arg: str) -> str:
"""
Adds quotes around an argument if it contains spaces.
Quotes a shell argument to prevent interpretation of metacharacters.
Uses :func:`shlex.quote` on POSIX systems for proper escaping of all
shell-special characters. On Windows, wraps arguments containing spaces
in double quotes (Windows shell does not interpret single-quoted strings).
"""
if " " not in arg:
return arg
return f'"{arg}"'
if platform.system() == "Windows":
if " " not in arg:
return arg
return f'"{arg}"'
return shlex.quote(arg)
@@ -10,7 +10,9 @@ from solidlsp.ls_utils import SymbolUtils
from test.conftest import is_ci
# Currently, most F# tests fail, there seems to be a regression or instability.
@pytest.mark.fsharp
@pytest.mark.skipif(is_ci, reason="F# language server is currently unreliable")
class TestFSharpLanguageServer:
@pytest.mark.parametrize("language_server", [Language.FSHARP], indirect=True)
def test_find_symbol(self, language_server: SolidLanguageServer) -> None: