Skip to content

Commit 90d8aa3

Browse files
Update SDK as per PR suggestions
1 parent 8137538 commit 90d8aa3

8 files changed

Lines changed: 53 additions & 48 deletions

File tree

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -318,10 +318,10 @@ tools = toolset.fetch_tools(actions=["hris_*"])
318318
utility_tools = tools.utility_tools()
319319

320320
# Search for relevant tools using natural language
321-
results = utility_tools.search_tool.call(query="manage employees", limit=5)
321+
results = utility_tools.get_search_tool()(query="manage employees", top_k=5)
322322

323323
# Execute discovered tools dynamically
324-
result = utility_tools.execute_tool.call(toolName="hris_list_employees", params={"limit": 10})
324+
result = utility_tools.get_execute_tool()(toolName="hris_list_employees", params={"limit": 10})
325325
```
326326

327327
## Semantic Search

examples/semantic_search_example.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ def example_utility_tools_semantic():
244244
print(f'Step 3: Calling tool_search with query="{query}"...')
245245
print(" (Searches are scoped to your linked connectors)")
246246
print()
247-
result = utility.search_tool.call(query=query, limit=5)
247+
result = utility.get_search_tool()(query=query, top_k=5)
248248
tools_data = result.get("tools", [])
249249
print(f"tool_search returned {len(tools_data)} results:")
250250
for tool_info in tools_data:

examples/utility_tools_example.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ def example_utility_tools_basic():
5050
utility_tools = all_tools.utility_tools()
5151

5252
# Search for employee management tools
53-
result = utility_tools.search_tool.call(query="manage employees create update list", limit=5)
53+
result = utility_tools.get_search_tool()(query="manage employees create update list", top_k=5)
5454

5555
print("Found relevant tools:")
5656
for tool in result.get("tools", []):
@@ -76,7 +76,7 @@ def example_utility_tools_with_execution():
7676
utility_tools = all_tools.utility_tools()
7777

7878
# Step 1: Search for relevant tools
79-
search_result = utility_tools.search_tool.call(query="list all employees", limit=1)
79+
search_result = utility_tools.get_search_tool()(query="list all employees", top_k=1)
8080

8181
tools_found = search_result.get("tools", [])
8282
if tools_found:
@@ -88,7 +88,7 @@ def example_utility_tools_with_execution():
8888
# Step 2: Execute the found tool
8989
try:
9090
print(f"\nExecuting {best_tool['name']}...")
91-
result = utility_tools.execute_tool.call(toolName=best_tool["name"], params={"limit": 5})
91+
result = utility_tools.get_execute_tool()(toolName=best_tool["name"], params={"limit": 5})
9292
print(f"Execution result: {result}")
9393
except Exception as e:
9494
print(f"Execution failed (expected in example): {e}")

stackone_ai/models.py

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,13 @@ def call(self, *args: Any, options: JsonDict | None = None, **kwargs: Any) -> Js
332332

333333
return self.execute(kwargs if kwargs else None)
334334

335+
def __call__(self, *args: Any, options: JsonDict | None = None, **kwargs: Any) -> JsonDict:
336+
"""Make the tool directly callable.
337+
338+
Alias for :meth:`call` so that ``tool(query="…")`` works.
339+
"""
340+
return self.call(*args, options=options, **kwargs)
341+
335342
def to_openai_function(self) -> JsonDict:
336343
"""Convert this tool to OpenAI's function format
337344
@@ -598,11 +605,11 @@ def utility_tools(
598605
toolset = StackOneToolSet()
599606
tools = toolset.fetch_tools()
600607
utility = tools.utility_tools(search_method="semantic")
601-
result = utility.search_tool.call(query="onboard new hire")
608+
result = utility.get_search_tool()(query="onboard new hire")
602609
603610
# Local BM25+TF-IDF search (default)
604611
utility = tools.utility_tools()
605-
result = utility.search_tool.call(query="onboard new hire")
612+
result = utility.get_search_tool()(query="onboard new hire")
606613
"""
607614
from stackone_ai.utility_tools import create_tool_execute
608615

@@ -632,8 +639,7 @@ def utility_tools(
632639
class UtilityTools(Tools):
633640
"""Utility tools collection with typed accessors for search and execute tools."""
634641

635-
@property
636-
def search_tool(self) -> StackOneTool:
642+
def get_search_tool(self) -> StackOneTool:
637643
"""Get the tool_search utility tool.
638644
639645
Returns:
@@ -642,13 +648,12 @@ def search_tool(self) -> StackOneTool:
642648
Raises:
643649
StackOneError: If tool_search is not found in the collection
644650
"""
645-
tool = self.get_tool("tool_search")
646-
if tool is None:
647-
raise StackOneError("tool_search not found in this UtilityTools collection")
648-
return tool
651+
for tool in self.tools:
652+
if tool.name == "tool_search":
653+
return tool
654+
raise StackOneError("tool_search not found in this UtilityTools collection")
649655

650-
@property
651-
def execute_tool(self) -> StackOneTool:
656+
def get_execute_tool(self) -> StackOneTool:
652657
"""Get the tool_execute utility tool.
653658
654659
Returns:
@@ -657,7 +662,7 @@ def execute_tool(self) -> StackOneTool:
657662
Raises:
658663
StackOneError: If tool_execute is not found in the collection
659664
"""
660-
tool = self.get_tool("tool_execute")
661-
if tool is None:
662-
raise StackOneError("tool_execute not found in this UtilityTools collection")
663-
return tool
665+
for tool in self.tools:
666+
if tool.name == "tool_execute":
667+
return tool
668+
raise StackOneError("tool_execute not found in this UtilityTools collection")

stackone_ai/toolset.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -406,10 +406,10 @@ def _search_one(c: str) -> list[SemanticSearchResult]:
406406
if search_tool:
407407
fallback_params: dict[str, Any] = {
408408
"query": query,
409-
"limit": top_k,
409+
"top_k": top_k,
410410
}
411411
if min_similarity is not None:
412-
fallback_params["minScore"] = min_similarity
412+
fallback_params["min_score"] = min_similarity
413413
result = search_tool.execute(fallback_params)
414414
matched_names = [t["name"] for t in result.get("tools", [])]
415415
# Filter by available connectors and preserve relevance order

stackone_ai/utility_tools.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -201,13 +201,13 @@ def create_tool_search(index: ToolIndex) -> StackOneTool:
201201
'(e.g., "tools for managing employees", "create time off request")'
202202
),
203203
},
204-
"limit": {
204+
"top_k": {
205205
"type": "number",
206206
"description": "Maximum number of tools to return (default: 5)",
207207
"default": 5,
208208
"nullable": True,
209209
},
210-
"minScore": {
210+
"min_score": {
211211
"type": "number",
212212
"description": "Minimum relevance score (0-1) to filter results (default: 0.0)",
213213
"default": 0.0,
@@ -225,11 +225,11 @@ def execute_filter(arguments: str | JsonDict | None = None) -> JsonDict:
225225
kwargs = arguments or {}
226226

227227
query = kwargs.get("query", "")
228-
limit = int(kwargs["limit"]) if kwargs.get("limit") is not None else 5
229-
min_score = float(kwargs["minScore"]) if kwargs.get("minScore") is not None else 0.0
228+
top_k = int(kwargs["top_k"]) if kwargs.get("top_k") is not None else 5
229+
min_score = float(kwargs["min_score"]) if kwargs.get("min_score") is not None else 0.0
230230

231231
# Search for tools
232-
results = index.search(query, limit, min_score)
232+
results = index.search(query, top_k, min_score)
233233

234234
# Format results
235235
tools_data = [
@@ -310,13 +310,13 @@ def create_semantic_tool_search(
310310
'(e.g., "onboard a new team member", "request vacation days")'
311311
),
312312
},
313-
"limit": {
313+
"top_k": {
314314
"type": "number",
315315
"description": "Maximum number of tools to return (default: 5)",
316316
"default": 5,
317317
"nullable": True,
318318
},
319-
"minSimilarity": {
319+
"min_similarity": {
320320
"type": "number",
321321
"description": (
322322
"Minimum similarity score (0-1) to filter results. "
@@ -340,8 +340,8 @@ def execute_search(arguments: str | JsonDict | None = None) -> JsonDict:
340340
kwargs = arguments or {}
341341

342342
query = kwargs.get("query", "")
343-
limit = int(kwargs["limit"]) if kwargs.get("limit") is not None else 5
344-
min_similarity = float(kwargs["minSimilarity"]) if kwargs.get("minSimilarity") is not None else None
343+
top_k = int(kwargs["top_k"]) if kwargs.get("top_k") is not None else 5
344+
min_similarity = float(kwargs["min_similarity"]) if kwargs.get("min_similarity") is not None else None
345345
connector = kwargs.get("connector")
346346

347347
all_results: list[SemanticSearchResult] = []
@@ -361,7 +361,7 @@ def execute_search(arguments: str | JsonDict | None = None) -> JsonDict:
361361
semantic_client.search,
362362
query=query,
363363
connector=c,
364-
top_k=limit,
364+
top_k=top_k,
365365
min_similarity=min_similarity,
366366
): c
367367
for c in connectors_to_search
@@ -377,12 +377,12 @@ def execute_search(arguments: str | JsonDict | None = None) -> JsonDict:
377377
response = semantic_client.search(
378378
query=query,
379379
connector=connector,
380-
top_k=limit,
380+
top_k=top_k,
381381
min_similarity=min_similarity,
382382
)
383383
all_results = list(response.results)
384384

385-
# Sort by score, deduplicate, apply limit
385+
# Sort by score, deduplicate, apply top_k
386386
all_results.sort(key=lambda r: r.similarity_score, reverse=True)
387387
seen: set[str] = set()
388388
tools_data: list[dict[str, object]] = []
@@ -399,7 +399,7 @@ def execute_search(arguments: str | JsonDict | None = None) -> JsonDict:
399399
}
400400
)
401401

402-
return {"tools": tools_data[:limit]}
402+
return {"tools": tools_data[:top_k]}
403403

404404
execute_config = ExecuteConfig(
405405
name=name,

tests/test_semantic_search.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -550,7 +550,7 @@ def test_semantic_tool_search_execute(self, mock_search: MagicMock) -> None:
550550
client = SemanticSearchClient(api_key="test-key")
551551
tool = create_semantic_tool_search(client)
552552

553-
result = tool.execute({"query": "create employee", "limit": 5})
553+
result = tool.execute({"query": "create employee", "top_k": 5})
554554

555555
assert "tools" in result
556556
assert len(result["tools"]) == 1
@@ -581,7 +581,7 @@ def test_semantic_tool_search_with_min_similarity(self, mock_search: MagicMock)
581581
client = SemanticSearchClient(api_key="test-key")
582582
tool = create_semantic_tool_search(client)
583583

584-
result = tool.execute({"query": "test", "limit": 10, "minSimilarity": 0.5})
584+
result = tool.execute({"query": "test", "top_k": 10, "min_similarity": 0.5})
585585

586586
assert len(result["tools"]) == 1
587587
assert result["tools"][0]["name"] == "high_score_action"
@@ -623,8 +623,8 @@ def test_semantic_tool_search_has_correct_parameters(self) -> None:
623623

624624
props = tool.parameters.properties
625625
assert "query" in props
626-
assert "limit" in props
627-
assert "minSimilarity" in props
626+
assert "top_k" in props
627+
assert "min_similarity" in props
628628
assert "connector" in props
629629

630630

@@ -677,7 +677,7 @@ def _search_side_effect(
677677
client = SemanticSearchClient(api_key="test-key")
678678
tool = create_semantic_tool_search(client, available_connectors={"bamboohr", "hibob"})
679679

680-
result = tool.execute({"query": "create employee", "limit": 10})
680+
result = tool.execute({"query": "create employee", "top_k": 10})
681681

682682
# Should have searched each connector separately
683683
assert mock_search.call_count == 2
@@ -755,7 +755,7 @@ def test_no_connectors_queries_full_catalog(self, mock_search: MagicMock) -> Non
755755
client = SemanticSearchClient(api_key="test-key")
756756
tool = create_semantic_tool_search(client) # No available_connectors
757757

758-
result = tool.execute({"query": "create employee", "limit": 5})
758+
result = tool.execute({"query": "create employee", "top_k": 5})
759759

760760
# Should make a single call without connector scoping
761761
mock_search.assert_called_once_with(
@@ -1216,7 +1216,7 @@ def test_semantic_tool_search_deduplicates_versions(self, mock_search: MagicMock
12161216

12171217
client = SemanticSearchClient(api_key="test-key")
12181218
tool = create_semantic_tool_search(client)
1219-
result = tool.execute({"query": "list employees", "limit": 10})
1219+
result = tool.execute({"query": "list employees", "top_k": 10})
12201220

12211221
# Should deduplicate: only one result
12221222
assert len(result["tools"]) == 1

tests/test_utility_tools.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ def test_search_tool_execute_with_json_string(self, sample_tools):
255255
search_tool = create_tool_search(index)
256256

257257
# Execute with JSON string
258-
json_input = json.dumps({"query": "employee", "limit": 2, "minScore": 0.0})
258+
json_input = json.dumps({"query": "employee", "top_k": 2, "min_score": 0.0})
259259
result = search_tool.execute(json_input)
260260

261261
assert "tools" in result
@@ -271,8 +271,8 @@ def test_search_tool_execute(self, sample_tools):
271271
result = search_tool.execute(
272272
{
273273
"query": "manage employees",
274-
"limit": 3,
275-
"minScore": 0.0,
274+
"top_k": 3,
275+
"min_score": 0.0,
276276
}
277277
)
278278

@@ -293,7 +293,7 @@ def test_search_tool_call(self, sample_tools):
293293
search_tool = create_tool_search(index)
294294

295295
# Call with kwargs
296-
result = search_tool.call(query="candidate", limit=2)
296+
result = search_tool.call(query="candidate", top_k=2)
297297

298298
assert "tools" in result
299299
assert len(result["tools"]) <= 2
@@ -384,7 +384,7 @@ def test_utility_tools_functionality(self, tools_collection):
384384
result = search_tool.execute(
385385
{
386386
"query": "create employee",
387-
"limit": 1,
387+
"top_k": 1,
388388
}
389389
)
390390

@@ -489,6 +489,6 @@ def test_utility_tools_with_custom_alpha(self, sample_tools):
489489
assert "alpha=0.3" in search_tool.description
490490

491491
# Test it works
492-
result = search_tool.execute({"query": "list employees", "limit": 3})
492+
result = search_tool.execute({"query": "list employees", "top_k": 3})
493493
assert "tools" in result
494494
assert len(result["tools"]) > 0

0 commit comments

Comments
 (0)