From ae89b68b908b110bcde733c8efdc563c2d6f1a84 Mon Sep 17 00:00:00 2001 From: roboomp Date: Fri, 5 Jun 2026 14:15:07 +0000 Subject: [PATCH] fix(robomp): parameterized bot identity in system prompts system_append.md and system_append_pr_review.md hardcoded the literal 'robomp' as the bot persona, so the agent self-mentioned an account that does not exist when deployments configure ROBOMP_BOT_LOGIN to a different login. Affected users saw the agent ask for @robomp mentions that GitHub never resolved to the actual bot. Thread the configured login through persona.system_append and persona.system_append_pr_review as a bot_login keyword, render it via the existing {{bot_login}} placeholder, and pass settings.bot_login at the worker callsite. Regression test asserts the templated login lands in both prompts and the legacy literal is gone. Fixes #1932 --- python/robomp/src/persona.py | 14 +++++++---- python/robomp/src/prompts/system_append.md | 2 +- .../src/prompts/system_append_pr_review.md | 2 +- python/robomp/src/worker.py | 14 +++++++++-- python/robomp/tests/test_persona.py | 24 +++++++++++++++++++ python/robomp/tests/test_worker.py | 2 +- 6 files changed, 49 insertions(+), 9 deletions(-) diff --git a/python/robomp/src/persona.py b/python/robomp/src/persona.py index 7119857ef..cfb7e2f13 100644 --- a/python/robomp/src/persona.py +++ b/python/robomp/src/persona.py @@ -128,12 +128,18 @@ def classify_next_step(primary: str) -> str: ) -def system_append(*, repo: RepoInfo, issue: IssueInfo, workspace: Workspace) -> str: - return render(_load("system_append.md"), {"repo": repo, "issue": issue, "workspace": workspace}) +def system_append(*, repo: RepoInfo, issue: IssueInfo, workspace: Workspace, bot_login: str) -> str: + return render( + _load("system_append.md"), + {"repo": repo, "issue": issue, "workspace": workspace, "bot_login": bot_login}, + ) -def system_append_pr_review(*, repo: RepoInfo, issue: IssueInfo, workspace: Workspace) -> str: - return render(_load("system_append_pr_review.md"), {"repo": repo, "issue": issue, "workspace": workspace}) +def system_append_pr_review(*, repo: RepoInfo, issue: IssueInfo, workspace: Workspace, bot_login: str) -> str: + return render( + _load("system_append_pr_review.md"), + {"repo": repo, "issue": issue, "workspace": workspace, "bot_login": bot_login}, + ) def kickoff(*, repo: RepoInfo, issue: IssueInfo, workspace: Workspace) -> str: diff --git a/python/robomp/src/prompts/system_append.md b/python/robomp/src/prompts/system_append.md index f6d1c5e40..70b71a36d 100644 --- a/python/robomp/src/prompts/system_append.md +++ b/python/robomp/src/prompts/system_append.md @@ -1,4 +1,4 @@ -You are **robomp**, an autonomous triage-and-fix bot operating on `{{repo.full_name}}`. +You are **@{{bot_login}}**, an autonomous triage-and-fix bot operating on `{{repo.full_name}}`. - **Triage first.** Fresh, unclassified issue → first action is `classify_issue(primary=..., rationale=...)`. NEVER comment, push, open a PR, or run a repro until labels land. diff --git a/python/robomp/src/prompts/system_append_pr_review.md b/python/robomp/src/prompts/system_append_pr_review.md index 34cbf2b46..28175814a 100644 --- a/python/robomp/src/prompts/system_append_pr_review.md +++ b/python/robomp/src/prompts/system_append_pr_review.md @@ -1,4 +1,4 @@ -You are **robomp**, reviewing an incoming pull request on `{{repo.full_name}}`. +You are **@{{bot_login}}**, reviewing an incoming pull request on `{{repo.full_name}}`. - **Read-only PR review.** Never edit files, commit, push, open a PR, approve, request changes, merge, or close. diff --git a/python/robomp/src/worker.py b/python/robomp/src/worker.py index 6c2e02fa7..d0a6f03e2 100644 --- a/python/robomp/src/worker.py +++ b/python/robomp/src/worker.py @@ -512,9 +512,19 @@ def _run_rpc_blocking( ) inputs.db.set_event_model(inputs.delivery_id, chosen_model) append_system_prompt = ( - persona.system_append_pr_review(repo=inputs.repo, issue=inputs.issue, workspace=inputs.workspace) + persona.system_append_pr_review( + repo=inputs.repo, + issue=inputs.issue, + workspace=inputs.workspace, + bot_login=inputs.settings.bot_login, + ) if task_kind == "review_pr" - else persona.system_append(repo=inputs.repo, issue=inputs.issue, workspace=inputs.workspace) + else persona.system_append( + repo=inputs.repo, + issue=inputs.issue, + workspace=inputs.workspace, + bot_login=inputs.settings.bot_login, + ) ) with RpcClient( diff --git a/python/robomp/tests/test_persona.py b/python/robomp/tests/test_persona.py index 6d9f1e2a3..71dff98d8 100644 --- a/python/robomp/tests/test_persona.py +++ b/python/robomp/tests/test_persona.py @@ -181,3 +181,27 @@ def test_review_completion_reminder_mentions_submit_only() -> None: ) assert "submit_pr_review" in out assert "gh_open_pr" not in out + + +def test_system_append_renders_configured_bot_login() -> None: + out = persona.system_append( + repo=_Repo(), + issue=_Issue(), + workspace=_Workspace(), + bot_login="Svitter", + ) + # The hardcoded persona name MUST be replaced by the configured login so + # the agent self-mentions the account that actually receives webhooks. + assert "You are **@Svitter**" in out + assert "**robomp**" not in out + + +def test_system_append_pr_review_renders_configured_bot_login() -> None: + out = persona.system_append_pr_review( + repo=_Repo(), + issue=_Issue(), + workspace=_Workspace(), + bot_login="Svitter", + ) + assert "You are **@Svitter**" in out + assert "**robomp**" not in out diff --git a/python/robomp/tests/test_worker.py b/python/robomp/tests/test_worker.py index 8a1edd593..a9b070599 100644 --- a/python/robomp/tests/test_worker.py +++ b/python/robomp/tests/test_worker.py @@ -149,7 +149,7 @@ def _patch_worker(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None: monkeypatch.setattr("robomp.worker.host_tools.build", lambda _b: ()) monkeypatch.setattr( "robomp.worker.persona.system_append", - lambda *, repo, issue, workspace: "SYS", + lambda *, repo, issue, workspace, bot_login: "SYS", ) monkeypatch.setattr( "robomp.worker.persona.seed_phases",