Skip to content

Commit aa448aa

Browse files
committed
Update dependencies
1 parent afe4e07 commit aa448aa

File tree

7 files changed

+230
-121
lines changed

7 files changed

+230
-121
lines changed

plugins/tool_search/embedding/README.md

Lines changed: 0 additions & 19 deletions
This file was deleted.

plugins/tool_search/in_mem_embeddings/pyproject.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ description = "UTCP plugin providing in-memory embedding-based semantic tool sea
1212
readme = "README.md"
1313
requires-python = ">=3.10"
1414
dependencies = [
15+
"pydantic>=2.0",
1516
"utcp>=1.0",
17+
"numpy>=2.3",
1618
]
1719
classifiers = [
1820
"Development Status :: 4 - Beta",
@@ -27,6 +29,10 @@ embedding = [
2729
"sentence-transformers>=2.2.0",
2830
"torch>=1.9.0",
2931
]
32+
test = [
33+
"pytest>=7.0.0",
34+
"pytest-asyncio>=0.21.0",
35+
]
3036

3137

3238
[project.urls]

plugins/tool_search/in_mem_embeddings/src/utcp_in_mem_embeddings/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,7 @@
55
def register():
66
"""Entry point function to register the in-memory embeddings search strategy."""
77
register_tool_search_strategy("in_mem_embeddings", InMemEmbeddingsSearchStrategyConfigSerializer())
8+
9+
__all__ = [
10+
"InMemEmbeddingsSearchStrategyConfigSerializer",
11+
]

plugins/tool_search/in_mem_embeddings/test_integration.py

Lines changed: 0 additions & 96 deletions
This file was deleted.
Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
#!/usr/bin/env python3
2+
"""Integration tests to verify the plugin works with the core UTCP system."""
3+
4+
import sys
5+
from pathlib import Path
6+
import pytest
7+
import pytest_asyncio
8+
9+
# Add paths
10+
plugin_src = (Path(__file__).parent / "src").resolve()
11+
core_src = (Path(__file__).parent.parent.parent.parent / "core" / "src").resolve()
12+
sys.path.insert(0, str(plugin_src))
13+
sys.path.insert(0, str(core_src))
14+
15+
16+
@pytest.fixture(scope="session")
17+
def register_plugin():
18+
"""Register the plugin once for all tests."""
19+
from utcp_in_mem_embeddings import register
20+
register()
21+
return True
22+
23+
24+
@pytest_asyncio.fixture
25+
async def sample_tools():
26+
"""Create sample tools for testing."""
27+
from utcp.data.tool import Tool, JsonSchema
28+
from utcp.data.call_template import CallTemplate
29+
30+
return [
31+
Tool(
32+
name="test.tool1",
33+
description="A test tool for cooking",
34+
inputs=JsonSchema(),
35+
outputs=JsonSchema(),
36+
tags=["cooking", "test"],
37+
tool_call_template=CallTemplate(
38+
name="test.tool1",
39+
call_template_type="default"
40+
)
41+
),
42+
Tool(
43+
name="test.tool2",
44+
description="A test tool for programming",
45+
inputs=JsonSchema(),
46+
outputs=JsonSchema(),
47+
tags=["programming", "development"],
48+
tool_call_template=CallTemplate(
49+
name="test.tool2",
50+
call_template_type="default"
51+
)
52+
)
53+
]
54+
55+
56+
@pytest_asyncio.fixture
57+
async def tool_repository(sample_tools):
58+
"""Create a tool repository with sample tools."""
59+
from utcp.implementations.in_mem_tool_repository import InMemToolRepository
60+
from utcp.data.utcp_manual import UtcpManual
61+
from utcp.data.call_template import CallTemplate
62+
63+
repo = InMemToolRepository()
64+
manual = UtcpManual(tools=sample_tools)
65+
manual_call_template = CallTemplate(name="test_manual", call_template_type="default")
66+
await repo.save_manual(manual_call_template, manual)
67+
68+
return repo
69+
70+
71+
@pytest.mark.asyncio
72+
async def test_plugin_registration(register_plugin):
73+
"""Test that the plugin can be registered successfully."""
74+
# The fixture already registers the plugin, so we just verify it worked
75+
assert register_plugin is True
76+
77+
78+
@pytest.mark.asyncio
79+
async def test_plugin_discovery(register_plugin):
80+
"""Test that the core system can discover the registered plugin."""
81+
from utcp.interfaces.tool_search_strategy import ToolSearchStrategyConfigSerializer
82+
83+
strategies = ToolSearchStrategyConfigSerializer.tool_search_strategy_implementations
84+
assert "in_mem_embeddings" in strategies, "Plugin should be discoverable by core system"
85+
86+
87+
@pytest.mark.asyncio
88+
async def test_strategy_creation_through_core(register_plugin):
89+
"""Test creating strategy instance through the core serialization system."""
90+
from utcp.interfaces.tool_search_strategy import ToolSearchStrategyConfigSerializer
91+
92+
serializer = ToolSearchStrategyConfigSerializer()
93+
94+
strategy_config = {
95+
"tool_search_strategy_type": "in_mem_embeddings",
96+
"model_name": "all-MiniLM-L6-v2",
97+
"similarity_threshold": 0.3
98+
}
99+
100+
strategy = serializer.validate_dict(strategy_config)
101+
assert strategy.tool_search_strategy_type == "in_mem_embeddings"
102+
assert strategy.model_name == "all-MiniLM-L6-v2"
103+
assert strategy.similarity_threshold == 0.3
104+
105+
106+
@pytest.mark.asyncio
107+
async def test_basic_search_functionality(register_plugin, tool_repository):
108+
"""Test basic search functionality with the plugin."""
109+
from utcp.interfaces.tool_search_strategy import ToolSearchStrategyConfigSerializer
110+
111+
# Create strategy through core system
112+
serializer = ToolSearchStrategyConfigSerializer()
113+
strategy_config = {
114+
"tool_search_strategy_type": "in_mem_embeddings",
115+
"model_name": "all-MiniLM-L6-v2",
116+
"similarity_threshold": 0.3
117+
}
118+
strategy = serializer.validate_dict(strategy_config)
119+
120+
# Test search for cooking-related tools
121+
results = await strategy.search_tools(tool_repository, "cooking", limit=1)
122+
assert len(results) > 0, "Search should return at least one result for 'cooking' query"
123+
124+
# Verify the result is relevant
125+
cooking_tool = results[0]
126+
assert "cooking" in cooking_tool.description.lower() or "cooking" in cooking_tool.tags
127+
128+
129+
@pytest.mark.asyncio
130+
async def test_search_with_different_queries(register_plugin, tool_repository):
131+
"""Test search functionality with different query types."""
132+
from utcp.interfaces.tool_search_strategy import ToolSearchStrategyConfigSerializer
133+
134+
serializer = ToolSearchStrategyConfigSerializer()
135+
strategy_config = {
136+
"tool_search_strategy_type": "in_mem_embeddings",
137+
"model_name": "all-MiniLM-L6-v2",
138+
"similarity_threshold": 0.3
139+
}
140+
strategy = serializer.validate_dict(strategy_config)
141+
142+
# Test different queries
143+
test_cases = [
144+
("cooking", "cooking"),
145+
("programming", "programming"),
146+
("development", "programming") # Should match programming tool
147+
]
148+
149+
for query, expected_tag in test_cases:
150+
results = await strategy.search_tools(tool_repository, query, limit=2)
151+
assert len(results) > 0, f"Search should return results for '{query}' query"
152+
153+
# Check if any result contains the expected tag
154+
found_relevant = any(
155+
expected_tag in tool.tags or expected_tag in tool.description.lower()
156+
for tool in results
157+
)
158+
assert found_relevant, f"Results should be relevant to '{query}' query"
159+
160+
161+
@pytest.mark.asyncio
162+
async def test_search_limit_parameter(register_plugin, tool_repository):
163+
"""Test that the limit parameter works correctly."""
164+
from utcp.interfaces.tool_search_strategy import ToolSearchStrategyConfigSerializer
165+
166+
serializer = ToolSearchStrategyConfigSerializer()
167+
strategy_config = {
168+
"tool_search_strategy_type": "in_mem_embeddings",
169+
"model_name": "all-MiniLM-L6-v2",
170+
"similarity_threshold": 0.1 # Lower threshold to get more results
171+
}
172+
strategy = serializer.validate_dict(strategy_config)
173+
174+
# Test with limit=1
175+
results_1 = await strategy.search_tools(tool_repository, "test", limit=1)
176+
assert len(results_1) <= 1, "Should respect limit=1"
177+
178+
# Test with limit=2
179+
results_2 = await strategy.search_tools(tool_repository, "test", limit=2)
180+
assert len(results_2) <= 2, "Should respect limit=2"
181+
182+
183+
@pytest.mark.asyncio
184+
async def test_similarity_threshold(register_plugin, tool_repository):
185+
"""Test that similarity threshold affects results."""
186+
from utcp.interfaces.tool_search_strategy import ToolSearchStrategyConfigSerializer
187+
188+
serializer = ToolSearchStrategyConfigSerializer()
189+
190+
# Test with high threshold (should return fewer results)
191+
high_threshold_config = {
192+
"tool_search_strategy_type": "in_mem_embeddings",
193+
"model_name": "all-MiniLM-L6-v2",
194+
"similarity_threshold": 0.9
195+
}
196+
high_threshold_strategy = serializer.validate_dict(high_threshold_config)
197+
198+
# Test with low threshold (should return more results)
199+
low_threshold_config = {
200+
"tool_search_strategy_type": "in_mem_embeddings",
201+
"model_name": "all-MiniLM-L6-v2",
202+
"similarity_threshold": 0.1
203+
}
204+
low_threshold_strategy = serializer.validate_dict(low_threshold_config)
205+
206+
# Search with both strategies
207+
high_results = await high_threshold_strategy.search_tools(tool_repository, "random_query", limit=10)
208+
low_results = await low_threshold_strategy.search_tools(tool_repository, "random_query", limit=10)
209+
210+
# Low threshold should return same or more results than high threshold
211+
assert len(low_results) >= len(high_results), "Lower threshold should return more results"

0 commit comments

Comments
 (0)