Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions src/rlm/prompt.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,17 @@
"Always assign read/search results to named variables so you can revisit "
"them later."
)
EDIT_SKILL_PROMPT = (
"For file changes that are exact replacements, prefer the pre-imported "
"`edit` skill over manual file writes. Use exactly "
"`await edit(path=\"relative/file.py\", old_str=\"\"\"old text\"\"\", "
"new_str=\"\"\"new text\"\"\")`. The target `old_str` must appear exactly "
"once. The supported keyword arguments are `path`, `old_str`, `new_str`, "
"and optional `cwd`; do not use `file`, `old`, `new`, line numbers, "
"`after`, or `insert`. If the replacement is not unique or the change is "
"too broad for an exact string replacement, then use normal Python file "
"I/O."
)


def build_system_prompt(
Expand Down Expand Up @@ -108,6 +119,8 @@ def build_system_prompt(
"Each skill is also available as a shell command by the same name: `<skill> ...`. "
"Discover its CLI usage with `<skill> --help`."
)
if "edit" in installed_skills:
skill_lines.append(EDIT_SKILL_PROMPT)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Edit prompt without IPython tool

Medium Severity

EDIT_SKILL_PROMPT is appended whenever edit appears in installed_skills, but it instructs agents to call await edit(...), which only works inside the IPython kernel. If RLM_TOOLS omits ipython (e.g. bash,edit), that guidance is injected even though skills are not pre-imported and await cannot run.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 90ba4c9. Configure here.

if skill_lines:
parts.extend(["", *skill_lines])

Expand Down
24 changes: 22 additions & 2 deletions tests/test_prompt.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from dataclasses import dataclass

from rlm.prompt import (
EDIT_SKILL_PROMPT,
GIT_HISTORY_GUARD_PROMPT,
IPYTHON_CONTROL_PROMPT,
build_system_prompt,
Expand All @@ -16,11 +17,15 @@ class _Tool:
name: str


def _prompt(active_tools: list[_Tool]) -> str:
def _prompt(
active_tools: list[_Tool],
*,
installed_skills: list[str] | None = None,
) -> str:
return build_system_prompt(
"/repo",
None,
[],
installed_skills or [],
"/repo/.rlm/messages.jsonl",
allow_recursion=False,
active_tools=active_tools,
Expand Down Expand Up @@ -62,3 +67,18 @@ def test_ipython_control_prompt_included_for_ipython_tool():

def test_ipython_control_prompt_omitted_without_ipython_tool():
assert IPYTHON_CONTROL_PROMPT not in _prompt([_Tool("bash")])


def test_edit_skill_prompt_included_when_edit_is_installed():
prompt = _prompt([_Tool("ipython")], installed_skills=["edit"])

assert EDIT_SKILL_PROMPT in prompt
assert 'await edit(path="relative/file.py"' in prompt
assert "`old_str` must appear exactly once" in prompt
assert "do not use `file`, `old`, `new`, line numbers" in prompt


def test_edit_skill_prompt_omitted_without_edit_skill():
prompt = _prompt([_Tool("ipython")], installed_skills=["search_docs"])

assert EDIT_SKILL_PROMPT not in prompt
Loading