From 6fc82d9edd0404f9df1eb746d43b6ae053eeed87 Mon Sep 17 00:00:00 2001 From: Aran Yogesh Date: Fri, 20 Mar 2026 12:05:30 -0700 Subject: [PATCH] feat: default org to langchain-ai when repo name specified without org (#1099) * feat: default org to langchain-ai when repo: is used without org prefix * chore: use SLACK_REPO_OWNER for repo shorthand default org and document in CUSTOMIZATION.md --------- Co-authored-by: open-swe[bot] --- CUSTOMIZATION.md | 2 +- agent/webapp.py | 9 +++++++-- tests/test_slack_context.py | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 3 deletions(-) diff --git a/CUSTOMIZATION.md b/CUSTOMIZATION.md index 3fee1dbc..924de38a 100644 --- a/CUSTOMIZATION.md +++ b/CUSTOMIZATION.md @@ -289,7 +289,7 @@ SLACK_REPO_OWNER="my-org" SLACK_REPO_NAME="my-repo" ``` -Users can override per-message with `repo:owner/name` syntax in their Slack message. +Users can override per-message with `repo:owner/name` syntax in their Slack message. A shorthand `repo:name` (without the org) is also supported — the org defaults to the value of `SLACK_REPO_OWNER`. ### Adding a new trigger diff --git a/agent/webapp.py b/agent/webapp.py index e680117c..a44d86b9 100644 --- a/agent/webapp.py +++ b/agent/webapp.py @@ -355,9 +355,14 @@ async def get_slack_repo_config(message: str, channel_id: str, thread_ts: str) - name: str | None = None if "repo:" in message or "repo " in message: - match = re.search(r"repo[: ]([a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+)", message) + match = re.search(r"repo[: ]([a-zA-Z0-9_.\-/]+)", message) if match: - owner, name = match.group(1).split("/", 1) + value = match.group(1).rstrip("/") + if "/" in value: + owner, name = value.split("/", 1) + else: + owner = default_owner + name = value if not owner or not name: github_match = re.search(r"github\.com/([a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+)", message) diff --git a/tests/test_slack_context.py b/tests/test_slack_context.py index 6a114107..c438d314 100644 --- a/tests/test_slack_context.py +++ b/tests/test_slack_context.py @@ -321,3 +321,39 @@ def test_get_slack_repo_config_github_url_beats_thread_metadata( ) assert repo == {"owner": "langchain-ai", "name": "langgraph-api"} + + +def test_get_slack_repo_config_repo_name_only_defaults_org( + monkeypatch: pytest.MonkeyPatch, +) -> None: + """repo:name without org should default owner to langchain-ai.""" + threads_client = _FakeThreadsClient(raise_not_found=True) + + async def fake_post_slack_thread_reply(channel_id: str, thread_ts: str, text: str) -> bool: + return True + + monkeypatch.setattr(webapp, "get_client", lambda url: _FakeClient(threads_client)) + monkeypatch.setattr(webapp, "post_slack_thread_reply", fake_post_slack_thread_reply) + + repo = asyncio.run( + webapp.get_slack_repo_config("fix bug in repo:langchainplus", "C123", "1.234") + ) + + assert repo == {"owner": "langchain-ai", "name": "langchainplus"} + + +def test_get_slack_repo_config_repo_name_only_space_syntax( + monkeypatch: pytest.MonkeyPatch, +) -> None: + """repo name (space syntax, no org) should default owner to langchain-ai.""" + threads_client = _FakeThreadsClient(raise_not_found=True) + + async def fake_post_slack_thread_reply(channel_id: str, thread_ts: str, text: str) -> bool: + return True + + monkeypatch.setattr(webapp, "get_client", lambda url: _FakeClient(threads_client)) + monkeypatch.setattr(webapp, "post_slack_thread_reply", fake_post_slack_thread_reply) + + repo = asyncio.run(webapp.get_slack_repo_config("fix bug in repo open-swe", "C123", "1.234")) + + assert repo == {"owner": "langchain-ai", "name": "open-swe"}