diff --git a/src/langbot/pkg/plugin/connector.py b/src/langbot/pkg/plugin/connector.py index d47cb448..1229881a 100644 --- a/src/langbot/pkg/plugin/connector.py +++ b/src/langbot/pkg/plugin/connector.py @@ -633,11 +633,12 @@ class PluginRuntimeConnector: Raises: ValueError: If plugin_id is not in the expected 'author/name' format. """ - if '/' not in plugin_id: + segments = plugin_id.split('/') + if len(segments) != 2 or not all(segments): raise ValueError( f"Invalid plugin_id format: '{plugin_id}'. Expected 'author/name' format (e.g. 'langbot/rag-engine')." ) - return plugin_id.split('/', 1) + return segments[0], segments[1] async def call_rag_ingest(self, plugin_id: str, context_data: dict[str, Any]) -> dict[str, Any]: """Call plugin to ingest document. diff --git a/tests/unit_tests/plugin/test_plugin_id_parsing.py b/tests/unit_tests/plugin/test_plugin_id_parsing.py new file mode 100644 index 00000000..c6d479fb --- /dev/null +++ b/tests/unit_tests/plugin/test_plugin_id_parsing.py @@ -0,0 +1,25 @@ +"""Test plugin ID parsing validation.""" + +import pytest + +from src.langbot.pkg.plugin.connector import PluginRuntimeConnector + + +def test_parse_plugin_id_accepts_author_name(): + assert PluginRuntimeConnector._parse_plugin_id('langbot/rag-engine') == ('langbot', 'rag-engine') + + +@pytest.mark.parametrize( + 'plugin_id', + [ + '', + 'author', + 'author/', + '/name', + 'author/name/extra', + '/', + ], +) +def test_parse_plugin_id_rejects_malformed_ids(plugin_id): + with pytest.raises(ValueError, match='Expected'): + PluginRuntimeConnector._parse_plugin_id(plugin_id)