diff --git a/CHANGELOG.md b/CHANGELOG.md index c467cc96..c6e1ba4d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ Status of the `main` branch. Changes prior to the next official version change w - Serena's system prompt (a.k.a. the 'Serena Instructions Manual') is now provided lazily. At MCP connection time, only a one-sentence bootstrap prompt is provided. The `initial_instructions` tool provides the full prompt on demand, keeping the initial context lean. + - Add `serena_info` tool for on-demand retrieval of usage information * JetBrains: - Add `debug` tool: The agent can set breakpoints, inspect variables, evaluate expressions and control execution flow diff --git a/src/serena/generated/generated_prompt_factory.py b/src/serena/generated/generated_prompt_factory.py index 58070fd2..43f866d7 100644 --- a/src/serena/generated/generated_prompt_factory.py +++ b/src/serena/generated/generated_prompt_factory.py @@ -14,6 +14,9 @@ class PromptFactory(PromptFactoryBase): A class for retrieving and rendering prompt templates and prompt lists. """ + def create_info_jet_brains_debug_repl(self) -> str: + return self._render_prompt("info_jet_brains_debug_repl", locals()) + def create_onboarding_prompt(self, *, system: Any) -> str: return self._render_prompt("onboarding_prompt", locals()) diff --git a/src/serena/resources/config/internal_modes/jetbrains.yml b/src/serena/resources/config/internal_modes/jetbrains.yml index 7f76271f..34baf6ce 100644 --- a/src/serena/resources/config/internal_modes/jetbrains.yml +++ b/src/serena/resources/config/internal_modes/jetbrains.yml @@ -24,3 +24,4 @@ included_optional_tools: - jet_brains_rename - jet_brains_safe_delete - jet_brains_debug + - serena_info diff --git a/src/serena/resources/config/prompt_templates/info_prompts.yml b/src/serena/resources/config/prompt_templates/info_prompts.yml new file mode 100644 index 00000000..4c896429 --- /dev/null +++ b/src/serena/resources/config/prompt_templates/info_prompts.yml @@ -0,0 +1,64 @@ +# Defines prompts the SerenaInfoTool +prompts: + info_jet_brains_debug_repl: | + Note: The debugger uses 0-based line numbers like other Serena tools (while humans typically communicate 1-based ones). + You rely on the user to provide suitable run configurations for you to work with. + + State (objects, variables assigned) persists across calls within the same repl_key. + + Pre-bound variables: ``debug`` (debugger interface) + + Run configurations: + debug.listRunConfigs() + session = debug.startDebug("MyTestRun") # returns a DebugSession + debug.startRun("MyApp") # non-debug run, fire-and-forget + + Session discovery: + debug.sessions() + session = debug.currentSession() + session = debug.session(id) + + Breakpoints (project-global, set before or during debugging): + debug.addBreakpoint(file, line) + debug.addBreakpoint(file, line, condition) + debug.addLogpoint(file, line, logExpression) + debug.listBreakpoints() + debug.removeBreakpointAt(file, line) + + Execution control (on a DebugSession, e.g. ``session``):: + session.stepOver() | .stepInto() | .stepOut() + session.resume() | .pause() | .stop() + session.runToLine(file, line) + + Wait for pause (blocks until the session pauses or times out): + session.waitForPause(timeoutSeconds) + session.stepOverAndWait(timeoutSeconds) # step + wait in one call + session.resumeAndWait(timeoutSeconds) + + Inspection (when paused): + session.status() # location + source + variable values in one call + session.variables() # overview of locals/args (values may be truncated) + session.variable(name) # single variable (VariableInfo instance) + session.frames() | .frame() # stack trace | current frame + session.sourceContext(lines) # source around current line + session.threads() + + VariableInfo members: name, value (String as presented by the debugger), type + + Evaluation & modification: + session.eval("expr") # evaluate in current frame + session.setVar("x", "42") # set variable via assignment + + Example sequence of expressions one might execute in a REPL: + debug.addBreakpoint("src/main/java/Foo.java", 42) + session = debug.startDebug("MyTest") + session.waitForPause(30) + session.status() + + You can pass multiple statements at once; the result of the final expression is returned: + session = debug.startDebug("MyTest"); session.waitForPause(30); session.status() + + Control flow statements are also possible: + while (session.variable("count").value.equals("0")) { session.stepOverAndWait(5) } + + When done, close the REPL by passing an empty expression. diff --git a/src/serena/tools/jetbrains_tools.py b/src/serena/tools/jetbrains_tools.py index 58076ddc..0664fb03 100644 --- a/src/serena/tools/jetbrains_tools.py +++ b/src/serena/tools/jetbrains_tools.py @@ -579,74 +579,13 @@ class JetBrainsDebugTool(Tool, ToolMarkerOptional, ToolMarkerBeta): repl_key: str = "default", ) -> str: """ - Evaluates a Groovy expression in a persistent REPL, which can be used to debug - code interactively. + Debug code interactively by evaluating Groovy expressions in a persistent REPL. Important: Debugging should only be applied if the user has requested it! - You rely on the user to provide suitable run configurations for you to work with. - Note: The debugger uses 0-based line numbers like other Serena tools (while humans typically communicate 1-based ones). - - State (objects, variables assigned) persists across calls within the same repl_key. - - Pre-bound variables: ``debug`` (debugger interface) - - Run configurations: - debug.listRunConfigs() - session = debug.startDebug("MyTestRun") # returns a DebugSession - debug.startRun("MyApp") # non-debug run, fire-and-forget - - Session discovery: - debug.sessions() - session = debug.currentSession() - session = debug.session(id) - - Breakpoints (project-global, set before or during debugging): - debug.addBreakpoint(file, line) - debug.addBreakpoint(file, line, condition) - debug.addLogpoint(file, line, logExpression) - debug.listBreakpoints() - debug.removeBreakpointAt(file, line) - - Execution control (on a DebugSession, e.g. ``session``):: - session.stepOver() | .stepInto() | .stepOut() - session.resume() | .pause() | .stop() - session.runToLine(file, line) - - Wait for pause (blocks until the session pauses or times out): - session.waitForPause(timeoutSeconds) - session.stepOverAndWait(timeoutSeconds) # step + wait in one call - session.resumeAndWait(timeoutSeconds) - - Inspection (when paused): - session.status() # location + source + variable values in one call - session.variables() # overview of locals/args (values may be truncated) - session.variable(name) # single variable (VariableInfo instance) - session.frames() | .frame() # stack trace | current frame - session.sourceContext(lines) # source around current line - session.threads() - - VariableInfo members: name, value (String as presented by the debugger), type - - Evaluation & modification: - session.eval("expr") # evaluate in current frame - session.setVar("x", "42") # set variable via assignment - - Example sequence of expressions one might execute in a REPL: - debug.addBreakpoint("src/main/java/Foo.java", 42) - session = debug.startDebug("MyTest") - session.waitForPause(30) - session.status() - - You can pass multiple statements at once; the result of the final expression is returned: - session = debug.startDebug("MyTest"); session.waitForPause(30); session.status() - - Control flow statements are also possible: - while (session.variable("count").value.equals("0")) { session.stepOverAndWait(5) } - - When done, close the REPL by passing an empty expression. + Use the `serena_info` tool with topic `jet_brains_debug_repl` for usage information. :param expression: a Groovy/Java expression/statement to evaluate in the REPL. - If empty/null, closes the REPL with the given key, discarding its state. + If empty/null, closes the REPL with the given key. :param repl_key: identifier for the REPL instance. State persists across calls with the same key. :return: string representation of the result """ diff --git a/src/serena/tools/workflow_tools.py b/src/serena/tools/workflow_tools.py index e50ec9b5..461da9ea 100644 --- a/src/serena/tools/workflow_tools.py +++ b/src/serena/tools/workflow_tools.py @@ -4,7 +4,7 @@ Tools supporting the general workflow of the agent import platform -from serena.tools import ReadMemoryTool, Tool, ToolMarkerDoesNotRequireActiveProject, WriteMemoryTool +from serena.tools import ReadMemoryTool, Tool, ToolMarkerDoesNotRequireActiveProject, ToolMarkerOptional, WriteMemoryTool class CheckOnboardingPerformedTool(Tool): @@ -72,3 +72,20 @@ class InitialInstructionsTool(Tool, ToolMarkerDoesNotRequireActiveProject): as it will critically inform you! """ return self.agent.create_system_prompt(session_id=session_id) + + +class SerenaInfoTool(Tool, ToolMarkerOptional, ToolMarkerDoesNotRequireActiveProject): + """ + Provides information about an advanced topic on demand, facilitating context-efficiency. + """ + + def apply(self, topic: str) -> str: + """ + Retrieves Serena-specific information + :param topic: the topic, which you must have been given explicitly + """ + match topic: + case "jet_brains_debug_repl": + return self.agent.prompt_factory.create_info_jet_brains_debug_repl() + case _: + raise ValueError("Invalid topic: " + topic)