Add documentation on the REPL interface

* Tools section: Add REPL interface description, advantages and full list of functions
* Config section: Add information on REPL configuration
This commit is contained in:
Dominik Jain authored and Dominik Jain committed 2026-09-17 10:58:14 +02:00
1 parent a0bc785e0a
commit da1accf7e1
5 files changed
+172 -41

No files matched your search

+32 -1
View File
@@ -26,7 +26,7 @@ Some of the configurable settings include:
* the language backend to use by default (i.e., the JetBrains plugin or language servers);
this can also be [overridden per project](per-project-language-backend)
* UI settings affecting the [Serena Dashboard and GUI tool](060_dashboard.md)
* the set of tools to enable/disable by default
* the set of tools or REPL API functions to enable/disable by default
* the set of [modes](modes) to use by default
* tool execution parameters (timeout, max. answer length)
* global ignore rules
@@ -55,6 +55,37 @@ You can access it
```shell
serena config edit
```
(agent-interfaces)=
### Agent Interfaces
Serena provides its functionality to the agent (LLM) through one of two interfaces
(see [Tools and APIs](../01-about/035_tools) for the operations they offer):
* **tools**: every operation is a separate tool of the MCP server.
* **REPL** (new in Serena v2): a single tool executes Python code, through which the agent accesses the operations
programmatically, being able to combine several of them in one call.
The interface is selected via the `agent_interface` setting in the global configuration.
It can be overridden in the project configuration or via the `--agent-interface` command-line option,
and it is fixed for the duration of a session.
The two interfaces are configured differently:
* With the **tool interface**, the set of tools results from the tool inclusion/exclusion settings
(`excluded_tools`, `included_optional_tools`, `fixed_tools`) of the global configuration, the context,
the modes and the project configuration.
* With the **REPL interface**, the set of tools is fixed (the REPL tool and the tools which have no
counterpart within the REPL, e.g. for project activation); the tool settings above consequently do not apply.
The operations available *within* the REPL are configured via `included_apis`/`excluded_apis` instead,
which are supported in the same configuration layers and reference either a group of operations
(e.g. `lsp`) or an individual operation (e.g. `lsp.find_symbol`).
```{note}
Restricting the operations available in the REPL is a means of steering the agent, not a security mechanism:
the Python code that is executed can, in principle, do anything the Serena process can do.
See [Security](070_security) for isolation options.
```
## Modes and Contexts
+102 -22
View File
@@ -150,30 +150,110 @@ def autogen_tool_list(target_filename = "01-about/035_tools.md"):
from serena.tools import ToolRegistry
target_file = Path(__file__).parent / target_filename
with open(target_file, "w") as f:
with open(target_file, "w", encoding="utf-8") as f:
f.write("<!-- This file is auto-generated by docs/autogen_docs.py. Do not edit it manually. -->\n\n")
f.write("# Tools\n\n")
f.write("Find the full list of Serena's tools below.\n\n")
f.write("Note that in most configurations, only a subset of these tools will be enabled simultaneously.\n")
f.write("Tools marked as *optional* are disabled by default.\n\n")
f.write("Tools marked as [BETA] were recently introduced and may not be fully robust yet.\n\n")
tools_by_module = ToolRegistry().get_registered_tools_by_module()
priority_modules = {"serena.tools.symbol_tools": 1, "serena.tools.jetbrains_tools": 2}
f.write("# Tools and APIs\n\n")
f.write(
"Serena provides an agent (LLM) with its functionality through one of two interfaces (configured in Serena's [global configuration](global-config)):\n\n"
"* **Tools** (the classic interface): every operation is a separate tool of the MCP server.\n"
"* **REPL** (new in Serena v2): a single tool executes Python code, through which the agent accesses the operations\n"
" programmatically. The agent can thus combine several operations in one call, process the results\n"
" in code and return only the information it actually needs.\n\n"
"While both interfaces offer the same general functionality for the most part, "
"the REPL interface addresses several limitations inherent in the tool-based approach (see [advantages](repl-advantages) below).\n\n"
)
text = TextBuilder()
sorted_modules = sorted(tools_by_module.keys(), key=lambda m: (priority_modules.get(m, 3), m))
for module in sorted_modules:
tools = tools_by_module[module]
module = module.replace("serena.tools.", "")
text.with_line(f"* **{module}**")
for tool in tools:
info = ""
if tool.is_optional:
info += " *(optional)*"
if tool.is_beta:
info += " [BETA]"
text.with_line(f"* `{tool.tool_name}`{info}: {tool.class_docstring}", indent=2)
f.write(text.build())
def tools_section():
f.write("## Tools (Classic Interface)\n\n")
f.write("Find the full list of Serena's tools below.\n\n")
f.write("Note that in most configurations, only a subset of these tools will be enabled simultaneously.\n")
f.write("Tools marked as *optional* are disabled by default.\n\n")
f.write("Tools marked as [BETA] were recently introduced and may not be fully robust yet.\n\n")
tools_by_module = ToolRegistry().get_registered_tools_by_module()
priority_modules = {"serena.tools.symbol_tools": 1, "serena.tools.jetbrains_tools": 2}
text = TextBuilder()
sorted_modules = sorted(tools_by_module.keys(), key=lambda m: (priority_modules.get(m, 3), m))
for module in sorted_modules:
tools = tools_by_module[module]
module = module.replace("serena.tools.", "")
text.with_line(f"* **{module}**")
for tool in tools:
info = ""
if tool.is_optional:
info += " *(optional)*"
if tool.is_beta:
info += " [BETA]"
text.with_line(f"* `{tool.tool_name}`{info}: {tool.class_docstring}", indent=2)
f.write(text.build())
def facades_section():
from serena.repl.facade import ApiScope
from serena.agent import SerenaAgent, SerenaConfig
from serena.config.serena_config import LanguageBackend
f.write("\n\n## Serena's REPL (Code Execution-Based Interface)\n\n")
f.write(
"With the REPL interface, the agent uses a single tool, which executes Python code. The code accesses\n"
"Serena's functionality through the entrypoint object `s`, whose attributes are *facades*, each of which\n"
"groups the operations of one domain. For instance, this code finds a class and returns the names of its\n"
"members in a single call:\n\n"
"```python\n"
'result = s.lsp.find_symbol("SerenaAgent", depth=1)\n'
"[member.name for member in result.symbols[0].iter_children()]\n"
"```\n\n"
"The agent retrieves the details it requires (signatures, documentation, result types) at runtime via\n"
"`s.info(...)` (principle of *progressive disclosure*).\n\n"
"As with tools, only a subset of the operations is available in a given configuration:\n\n"
"* The facades `lsp` and `jb` are mutually exclusive, being tied to the respective language backend.\n"
"* Operations marked as *optional*, as well as all operations of facades marked as *optional*,\n"
" are disabled by default and must be enabled explicitly.\n\n"
"(repl-advantages)=\n\n"
"### Advantages\n\n"
"* **Composition**: The agent can combine several operations in a single call, using control flow,\n"
" filtering and aggregation. Multi-step retrievals that would otherwise require a series of\n"
" round-trips (find a symbol, inspect its members, find their references) become one call.\n"
"* **Context economy**: Only the result the agent actually needs enters the conversation.\n"
" Intermediate results remain in the Python runtime instead of consuming the context window\n"
" — which, for large result sets, is the difference between a summary and thousands of tokens.\n"
"* **Results as objects**: Operations return objects which can be processed programmatically\n"
" rather than plain text.\n"
"* **Progressive disclosure**: Instead of the schemas of dozens of tools, the agent is given a list of\n"
" the available operations, retrieving the details it requires (signatures, documentation, result\n"
" types) on demand. This eliminates the need for a client-specific tool search/dynamic tool discovery mechanism.\n"
"* **Reusability within a session**: Variables and helper functions defined by the agent persist\n"
" across calls, allowing intermediate results to be revisited and recurring logic to be applied\n"
" repeatedly.\n"
"* **Dynamic adaptation**: The set of available operations can change at runtime.\n"
" For MCP tools, changes to the toolset are not widely supported by clients and are therefore not\n"
" applied; within the REPL, the operations can follow the current situation.\n"
" This is what allows the language backend to be switched during a session, e.g. when a project\n"
" whose configuration demands a different backend is activated..\n\n"
"### List of Facades\n\n"
)
api_scope = ApiScope()
agent = SerenaAgent(serena_config=SerenaConfig().with_headless_mode_overrides())
facades = []
for backend in LanguageBackend:
facades.extend(backend.create_facades(agent, api_scope))
facades.extend(agent.create_default_facade_list(api_scope))
text = TextBuilder()
for facade in facades:
facade_info = " *(optional)*" if facade.is_optional() else ""
text.with_line(f"* **{facade.name}**{facade_info}: {facade.description}")
for method in facade.get_methods():
method_info = ""
if method.info.optional:
method_info += " *(optional)*"
if method.info.beta:
method_info += " [BETA]"
summary = method.get_summary().replace("`", "")
text.with_line(f"* `{method.qualified_name}`{method_info}: {summary}", indent=2)
f.write(text.build())
tools_section()
facades_section()
def autogen_about_intro_features():