diff --git a/semantic_router/layer.py b/semantic_router/layer.py index f0fff7b53ce002b3ae8becd324b02fa2cb4c3da7..08afccfab19b590a1fc975e9325c69d6cb961d0b 100644 --- a/semantic_router/layer.py +++ b/semantic_router/layer.py @@ -289,6 +289,27 @@ class RouteLayer: # add route to routes list self.routes.append(route) + def list_route_names(self) -> List[str]: + return [route.name for route in self.routes] + + def remove(self, name: str): + if name not in [route.name for route in self.routes]: + err_msg = f"Route `{name}` not found" + logger.error(err_msg) + raise ValueError(err_msg) + else: + self.routes = [route for route in self.routes if route.name != name] + logger.info(f"Removed route `{name}`") + # Also remove from index and categories + if self.categories is not None and self.index is not None: + indices_to_remove = [ + i + for i, route_name in enumerate(self.categories) + if route_name == name + ] + self.index = np.delete(self.index, indices_to_remove, axis=0) + self.categories = np.delete(self.categories, indices_to_remove, axis=0) + def _add_routes(self, routes: List[Route]): # create embeddings for all routes all_utterances = [ diff --git a/tests/unit/test_layer.py b/tests/unit/test_layer.py index 5cf403ce72ae049066739029c5da05a8819e1aa2..9669d594a0e560bea125c75d8cc5cd46caaac7df 100644 --- a/tests/unit/test_layer.py +++ b/tests/unit/test_layer.py @@ -167,6 +167,42 @@ class TestRouteLayer: assert set(route_layer.categories) == {"Route 1", "Route 2"} del route_layer + def test_list_route_names(self, openai_encoder, routes): + route_layer = RouteLayer(encoder=openai_encoder, routes=routes) + route_names = route_layer.list_route_names() + assert set(route_names) == { + route.name for route in routes + }, "The list of route names should match the names of the routes added." + + def test_remove_route(self, openai_encoder, routes): + route_layer = RouteLayer(encoder=openai_encoder, routes=routes) + # Remove a route by name + route_to_remove = routes[0].name + route_layer.remove(route_to_remove) + # Ensure the route is no longer in the route layer + assert ( + route_to_remove not in route_layer.list_route_names() + ), "The route should be removed from the route layer." + # Ensure the route is no longer in the index or categories + assert ( + route_to_remove not in route_layer.categories + ), "The route should be removed from the categories." + # Ensure the route's utterances are no longer in the index + for utterance in routes[0].utterances: + assert ( + utterance not in route_layer.index + ), "The route's utterances should be removed from the index." + + def test_remove_route_not_found(self, openai_encoder, routes): + route_layer = RouteLayer(encoder=openai_encoder, routes=routes) + # Attempt to remove a route that does not exist + non_existent_route = "non-existent-route" + with pytest.raises(ValueError) as excinfo: + route_layer.remove(non_existent_route) + assert ( + str(excinfo.value) == f"Route `{non_existent_route}` not found" + ), "Attempting to remove a non-existent route should raise a ValueError." + def test_add_multiple_routes(self, openai_encoder, routes): route_layer = RouteLayer(encoder=openai_encoder) route_layer._add_routes(routes=routes)