From c28436d17eac0574cb81132cd0c4c3df88ed5baa Mon Sep 17 00:00:00 2001 From: ryoppippi <1560508+ryoppippi@users.noreply.github.com> Date: Wed, 28 Jan 2026 16:29:10 +0000 Subject: [PATCH 1/2] refactor(tools): rename meta tools to utility tools with tool_* prefix Rename tool naming convention to avoid confusion with Facebook's Meta brand. The "meta_*" prefix was ambiguous and could be misinterpreted. File renames: - stackone_ai/meta_tools.py -> stackone_ai/utility_tools.py - tests/test_meta_tools.py -> tests/test_utility_tools.py - examples/meta_tools_example.py -> examples/utility_tools_example.py Tool name changes: - meta_search_tools -> tool_search - meta_execute_tool -> tool_execute - meta_collect_tool_feedback -> tool_feedback API changes: - Tools.meta_tools() -> Tools.utility_tools() Internal class renames: - MetaToolSearchResult -> ToolSearchResult - create_meta_search_tools() -> create_tool_search() - create_meta_execute_tool() -> create_tool_execute() - MetaSearchTool -> ToolSearchTool - MetaExecuteTool -> ToolExecuteTool All tests pass and documentation has been updated accordingly. --- README.md | 22 ++--- examples/test_examples.py | 2 +- ...ls_example.py => utility_tools_example.py} | 52 ++++++------ stackone_ai/feedback/tool.py | 2 +- stackone_ai/models.py | 20 ++--- .../{meta_tools.py => utility_tools.py} | 48 +++++------ tests/test_feedback.py | 6 +- ...st_meta_tools.py => test_utility_tools.py} | 80 +++++++++---------- 8 files changed, 116 insertions(+), 116 deletions(-) rename examples/{meta_tools_example.py => utility_tools_example.py} (78%) rename stackone_ai/{meta_tools.py => utility_tools.py} (90%) rename tests/{test_meta_tools.py => test_utility_tools.py} (88%) diff --git a/README.md b/README.md index 27b19f9..1fa0ebf 100644 --- a/README.md +++ b/README.md @@ -281,16 +281,16 @@ result = crew.kickoff() ## Feedback Collection -The SDK includes a feedback collection tool (`meta_collect_tool_feedback`) that allows users to submit feedback about their experience with StackOne tools. This tool is automatically included in the toolset and is designed to be invoked by AI agents after user permission. +The SDK includes a feedback collection tool (`tool_feedback`) that allows users to submit feedback about their experience with StackOne tools. This tool is automatically included in the toolset and is designed to be invoked by AI agents after user permission. ```python from stackone_ai import StackOneToolSet toolset = StackOneToolSet() -# Get the feedback tool (included with "meta_*" pattern or all tools) -tools = toolset.fetch_tools(actions=["meta_*"]) -feedback_tool = tools.get_tool("meta_collect_tool_feedback") +# Get the feedback tool (included with "tool_*" pattern or all tools) +tools = toolset.fetch_tools(actions=["tool_*"]) +feedback_tool = tools.get_tool("tool_feedback") # Submit feedback (typically invoked by AI after user consent) result = feedback_tool.call( @@ -305,23 +305,23 @@ result = feedback_tool.call( - "Are you ok with sending feedback to StackOne? The LLM will take care of sending it." - Only call the tool after the user explicitly agrees. -## Meta Tools (Beta) +## Utility Tools (Beta) -Meta tools enable dynamic tool discovery and execution without hardcoding tool names. +Utility tools enable dynamic tool discovery and execution without hardcoding tool names. ### Basic Usage ```python -# Get meta tools for dynamic discovery +# Get utility tools for dynamic discovery tools = toolset.fetch_tools(actions=["hris_*"]) -meta_tools = tools.meta_tools() +utility_tools = tools.utility_tools() # Search for relevant tools using natural language -filter_tool = meta_tools.get_tool("meta_search_tools") +filter_tool = utility_tools.get_tool("tool_search") results = filter_tool.call(query="manage employees", limit=5) # Execute discovered tools dynamically -execute_tool = meta_tools.get_tool("meta_execute_tool") +execute_tool = utility_tools.get_tool("tool_execute") result = execute_tool.call(toolName="hris_list_employees", params={"limit": 10}) ``` @@ -334,7 +334,7 @@ For more examples, check out the [examples/](examples/) directory: - [OpenAI Integration](examples/openai_integration.py) - [LangChain Integration](examples/langchain_integration.py) - [CrewAI Integration](examples/crewai_integration.py) -- [Meta Tools](examples/meta_tools_example.py) +- [Utility Tools](examples/utility_tools_example.py) ## Development diff --git a/examples/test_examples.py b/examples/test_examples.py index 29e3cea..45d631e 100644 --- a/examples/test_examples.py +++ b/examples/test_examples.py @@ -30,7 +30,7 @@ def get_example_files() -> list[str]: "index.py": ["mcp"], "file_uploads.py": ["mcp"], "stackone_account_ids.py": ["mcp"], - "meta_tools_example.py": ["mcp"], + "utility_tools_example.py": ["mcp"], "mcp_server.py": ["mcp"], } diff --git a/examples/meta_tools_example.py b/examples/utility_tools_example.py similarity index 78% rename from examples/meta_tools_example.py rename to examples/utility_tools_example.py index ba97dbc..3291f7e 100644 --- a/examples/meta_tools_example.py +++ b/examples/utility_tools_example.py @@ -1,8 +1,8 @@ #!/usr/bin/env python """ -Example demonstrating meta tools for dynamic tool discovery and execution. +Example demonstrating utility tools for dynamic tool discovery and execution. -Meta tools allow AI agents to search for relevant tools based on natural language queries +Utility tools allow AI agents to search for relevant tools based on natural language queries and execute them dynamically without hardcoding tool names. """ @@ -16,8 +16,8 @@ load_dotenv() -def example_meta_tools_basic(): - """Basic example of using meta tools for tool discovery""" +def example_utility_tools_basic(): + """Basic example of using utility tools for tool discovery""" print("Example 1: Dynamic tool discovery\n") # Initialize StackOne toolset @@ -27,11 +27,11 @@ def example_meta_tools_basic(): all_tools = toolset.fetch_tools(actions=["bamboohr_*"]) print(f"Total BambooHR tools available: {len(all_tools)}") - # Get meta tools for dynamic discovery - meta_tools = all_tools.meta_tools() + # Get utility tools for dynamic discovery + utility_tools = all_tools.utility_tools() # Get the filter tool to search for relevant tools - filter_tool = meta_tools.get_tool("meta_search_tools") + filter_tool = utility_tools.get_tool("tool_search") if filter_tool: # Search for employee management tools result = filter_tool.call(query="manage employees create update list", limit=5, minScore=0.0) @@ -43,7 +43,7 @@ def example_meta_tools_basic(): print() -def example_meta_tools_with_execution(): +def example_utility_tools_with_execution(): """Example of discovering and executing tools dynamically""" print("Example 2: Dynamic tool execution\n") @@ -52,11 +52,11 @@ def example_meta_tools_with_execution(): # Get all tools using MCP-backed fetch_tools() all_tools = toolset.fetch_tools() - meta_tools = all_tools.meta_tools() + utility_tools = all_tools.utility_tools() # Step 1: Search for relevant tools - filter_tool = meta_tools.get_tool("meta_search_tools") - execute_tool = meta_tools.get_tool("meta_execute_tool") + filter_tool = utility_tools.get_tool("tool_search") + execute_tool = utility_tools.get_tool("tool_execute") if filter_tool and execute_tool: # Find tools for listing employees @@ -81,8 +81,8 @@ def example_meta_tools_with_execution(): def example_with_openai(): - """Example of using meta tools with OpenAI""" - print("Example 3: Using meta tools with OpenAI\n") + """Example of using utility tools with OpenAI""" + print("Example 3: Using utility tools with OpenAI\n") try: from openai import OpenAI @@ -93,20 +93,20 @@ def example_with_openai(): # Initialize StackOne toolset toolset = StackOneToolSet() - # Get BambooHR tools and their meta tools using MCP-backed fetch_tools() + # Get BambooHR tools and their utility tools using MCP-backed fetch_tools() bamboohr_tools = toolset.fetch_tools(actions=["bamboohr_*"]) - meta_tools = bamboohr_tools.meta_tools() + utility_tools = bamboohr_tools.utility_tools() # Convert to OpenAI format - openai_tools = meta_tools.to_openai() + openai_tools = utility_tools.to_openai() - # Create a chat completion with meta tools + # Create a chat completion with utility tools response = client.chat.completions.create( model="gpt-4", messages=[ { "role": "system", - "content": "You are an HR assistant. Use meta_search_tools to find appropriate tools, then meta_execute_tool to execute them.", + "content": "You are an HR assistant. Use tool_search to find appropriate tools, then tool_execute to execute them.", }, {"role": "user", "content": "Can you help me find tools for managing employee records?"}, ], @@ -145,12 +145,12 @@ def example_with_langchain(): tools = toolset.fetch_tools(actions=["bamboohr_list_*"]) langchain_tools = tools.to_langchain() - # Get meta tools as well - meta_tools = tools.meta_tools() - langchain_meta_tools = meta_tools.to_langchain() + # Get utility tools as well + utility_tools = tools.utility_tools() + langchain_utility_tools = utility_tools.to_langchain() # Combine all tools - all_langchain_tools = list(langchain_tools) + list(langchain_meta_tools) + all_langchain_tools = list(langchain_tools) + list(langchain_utility_tools) print(f"Available tools for LangChain: {len(all_langchain_tools)}") for tool in all_langchain_tools: @@ -163,7 +163,7 @@ def example_with_langchain(): [ ( "system", - "You are an HR assistant. Use the meta tools to discover and execute relevant tools.", + "You are an HR assistant. Use the utility tools to discover and execute relevant tools.", ), ("human", "{input}"), ("placeholder", "{agent_scratchpad}"), @@ -190,13 +190,13 @@ def example_with_langchain(): def main(): """Run all examples""" print("=" * 60) - print("StackOne AI SDK - Meta Tools Examples") + print("StackOne AI SDK - Utility Tools Examples") print("=" * 60) print() # Basic examples that work without external APIs - example_meta_tools_basic() - example_meta_tools_with_execution() + example_utility_tools_basic() + example_utility_tools_with_execution() # Examples that require OpenAI API if os.getenv("OPENAI_API_KEY"): diff --git a/stackone_ai/feedback/tool.py b/stackone_ai/feedback/tool.py index 2ce73fd..ae493e9 100644 --- a/stackone_ai/feedback/tool.py +++ b/stackone_ai/feedback/tool.py @@ -160,7 +160,7 @@ def create_feedback_tool( Returns: FeedbackTool configured for feedback collection """ - name = "meta_collect_tool_feedback" + name = "tool_feedback" description = ( "Collects user feedback on StackOne tool performance. " 'First ask the user, "Are you ok with sending feedback to StackOne?" ' diff --git a/stackone_ai/models.py b/stackone_ai/models.py index 336b413..fcd32d7 100644 --- a/stackone_ai/models.py +++ b/stackone_ai/models.py @@ -530,10 +530,10 @@ def to_langchain(self) -> Sequence[BaseTool]: """ return [tool.to_langchain() for tool in self.tools] - def meta_tools(self, hybrid_alpha: float | None = None) -> Tools: - """Return meta tools for tool discovery and execution + def utility_tools(self, hybrid_alpha: float | None = None) -> Tools: + """Return utility tools for tool discovery and execution - Meta tools enable dynamic tool discovery and execution based on natural language queries + Utility tools enable dynamic tool discovery and execution based on natural language queries using hybrid BM25 + TF-IDF search. Args: @@ -543,22 +543,22 @@ def meta_tools(self, hybrid_alpha: float | None = None) -> Tools: (10.8% improvement in validation testing). Returns: - Tools collection containing meta_search_tools and meta_execute_tool + Tools collection containing tool_search and tool_execute Note: This feature is in beta and may change in future versions """ - from stackone_ai.meta_tools import ( + from stackone_ai.utility_tools import ( ToolIndex, - create_meta_execute_tool, - create_meta_search_tools, + create_tool_execute, + create_tool_search, ) # Create search index with hybrid search index = ToolIndex(self.tools, hybrid_alpha=hybrid_alpha) - # Create meta tools - filter_tool = create_meta_search_tools(index) - execute_tool = create_meta_execute_tool(self) + # Create utility tools + filter_tool = create_tool_search(index) + execute_tool = create_tool_execute(self) return Tools([filter_tool, execute_tool]) diff --git a/stackone_ai/meta_tools.py b/stackone_ai/utility_tools.py similarity index 90% rename from stackone_ai/meta_tools.py rename to stackone_ai/utility_tools.py index 076a18f..0d9a209 100644 --- a/stackone_ai/meta_tools.py +++ b/stackone_ai/utility_tools.py @@ -1,4 +1,4 @@ -"""Meta tools for dynamic tool discovery and execution""" +"""Utility tools for dynamic tool discovery and execution""" from __future__ import annotations @@ -17,8 +17,8 @@ from stackone_ai.models import Tools -class MetaToolSearchResult(BaseModel): - """Result from meta_search_tools""" +class ToolSearchResult(BaseModel): + """Result from tool_search""" name: str description: str @@ -93,7 +93,7 @@ def __init__(self, tools: list[StackOneTool], hybrid_alpha: float | None = None) self.tfidf_index = TfidfIndex() self.tfidf_index.build(tfidf_docs) - def search(self, query: str, limit: int = 5, min_score: float = 0.0) -> list[MetaToolSearchResult]: + def search(self, query: str, limit: int = 5, min_score: float = 0.0) -> list[ToolSearchResult]: """Search for relevant tools using hybrid BM25 + TF-IDF Args: @@ -158,7 +158,7 @@ def search(self, query: str, limit: int = 5, min_score: float = 0.0) -> list[Met continue search_results.append( - MetaToolSearchResult( + ToolSearchResult( name=tool.name, description=tool.description, score=score, @@ -171,16 +171,16 @@ def search(self, query: str, limit: int = 5, min_score: float = 0.0) -> list[Met return search_results -def create_meta_search_tools(index: ToolIndex) -> StackOneTool: - """Create the meta_search_tools tool +def create_tool_search(index: ToolIndex) -> StackOneTool: + """Create the tool_search tool Args: index: Tool search index Returns: - Meta tool for searching relevant tools + Utility tool for searching relevant tools """ - name = "meta_search_tools" + name = "tool_search" description = ( f"Searches for relevant tools based on a natural language query using hybrid BM25 + TF-IDF search " f"(alpha={index.hybrid_alpha}). This tool should be called first to discover available tools " @@ -241,20 +241,20 @@ def execute_filter(arguments: str | JsonDict | None = None) -> JsonDict: execute_config = ExecuteConfig( name=name, method="POST", - url="", # Meta tools don't make HTTP requests + url="", # Utility tools don't make HTTP requests headers={}, ) # Create a wrapper class that delegates execute to our custom function - class MetaSearchTool(StackOneTool): - """Meta tool for searching relevant tools""" + class ToolSearchTool(StackOneTool): + """Utility tool for searching relevant tools""" def __init__(self) -> None: super().__init__( description=description, parameters=parameters, _execute_config=execute_config, - _api_key="", # Meta tools don't need API key + _api_key="", # Utility tools don't need API key _account_id=None, ) @@ -263,22 +263,22 @@ def execute( ) -> JsonDict: return execute_filter(arguments) - return MetaSearchTool() + return ToolSearchTool() -def create_meta_execute_tool(tools_collection: Tools) -> StackOneTool: - """Create the meta_execute_tool +def create_tool_execute(tools_collection: Tools) -> StackOneTool: + """Create the tool_execute tool Args: tools_collection: Collection of tools to execute from Returns: - Meta tool for executing discovered tools + Utility tool for executing discovered tools """ - name = "meta_execute_tool" + name = "tool_execute" description = ( "Executes a tool by name with the provided parameters. " - "Use this after discovering tools with meta_search_tools." + "Use this after discovering tools with tool_search." ) parameters = ToolParameters( @@ -322,20 +322,20 @@ def execute_tool(arguments: str | JsonDict | None = None) -> JsonDict: execute_config = ExecuteConfig( name=name, method="POST", - url="", # Meta tools don't make HTTP requests + url="", # Utility tools don't make HTTP requests headers={}, ) # Create a wrapper class that delegates execute to our custom function - class MetaExecuteTool(StackOneTool): - """Meta tool for executing discovered tools""" + class ToolExecuteTool(StackOneTool): + """Utility tool for executing discovered tools""" def __init__(self) -> None: super().__init__( description=description, parameters=parameters, _execute_config=execute_config, - _api_key="", # Meta tools don't need API key + _api_key="", # Utility tools don't need API key _account_id=None, ) @@ -344,4 +344,4 @@ def execute( ) -> JsonDict: return execute_tool(arguments) - return MetaExecuteTool() + return ToolExecuteTool() diff --git a/tests/test_feedback.py b/tests/test_feedback.py index 116e437..ab3132a 100644 --- a/tests/test_feedback.py +++ b/tests/test_feedback.py @@ -223,7 +223,7 @@ def test_call_method_interface(self) -> None: result = tool.call( feedback="Testing the .call() method interface.", account_id="acc_test004", - tool_names=["meta_collect_tool_feedback"], + tool_names=["tool_feedback"], ) assert result == api_response @@ -354,13 +354,13 @@ def test_tool_integration(self) -> None: feedback_tool = create_feedback_tool(api_key="test_key") assert feedback_tool is not None - assert feedback_tool.name == "meta_collect_tool_feedback" + assert feedback_tool.name == "tool_feedback" assert "feedback" in feedback_tool.description.lower() # Test OpenAI format openai_format = feedback_tool.to_openai_function() assert openai_format["type"] == "function" - assert openai_format["function"]["name"] == "meta_collect_tool_feedback" + assert openai_format["function"]["name"] == "tool_feedback" assert "feedback" in openai_format["function"]["parameters"]["properties"] assert "account_id" in openai_format["function"]["parameters"]["properties"] assert "tool_names" in openai_format["function"]["parameters"]["properties"] diff --git a/tests/test_meta_tools.py b/tests/test_utility_tools.py similarity index 88% rename from tests/test_meta_tools.py rename to tests/test_utility_tools.py index 8204a6b..c8b6c97 100644 --- a/tests/test_meta_tools.py +++ b/tests/test_utility_tools.py @@ -1,4 +1,4 @@ -"""Tests for meta tools functionality""" +"""Tests for utility tools functionality""" import httpx import pytest @@ -7,12 +7,12 @@ from hypothesis import strategies as st from stackone_ai import StackOneTool, Tools -from stackone_ai.meta_tools import ( +from stackone_ai.models import ExecuteConfig, ToolParameters +from stackone_ai.utility_tools import ( ToolIndex, - create_meta_execute_tool, - create_meta_search_tools, + create_tool_execute, + create_tool_search, ) -from stackone_ai.models import ExecuteConfig, ToolParameters # Hypothesis strategies for PBT # Score threshold strategy @@ -236,15 +236,15 @@ def test_search_limit_pbt(self, limit: int): assert len(results) <= len(tools) -class TestMetaSearchTool: - """Test the meta_search_tools functionality""" +class TestToolSearch: + """Test the tool_search functionality""" def test_filter_tool_creation(self, sample_tools): """Test creating the filter tool""" index = ToolIndex(sample_tools) - filter_tool = create_meta_search_tools(index) + filter_tool = create_tool_search(index) - assert filter_tool.name == "meta_search_tools" + assert filter_tool.name == "tool_search" assert "natural language query" in filter_tool.description.lower() def test_filter_tool_execute_with_json_string(self, sample_tools): @@ -252,7 +252,7 @@ def test_filter_tool_execute_with_json_string(self, sample_tools): import json index = ToolIndex(sample_tools) - filter_tool = create_meta_search_tools(index) + filter_tool = create_tool_search(index) # Execute with JSON string json_input = json.dumps({"query": "employee", "limit": 2, "minScore": 0.0}) @@ -265,7 +265,7 @@ def test_filter_tool_execute_with_json_string(self, sample_tools): def test_filter_tool_execute(self, sample_tools): """Test executing the filter tool""" index = ToolIndex(sample_tools) - filter_tool = create_meta_search_tools(index) + filter_tool = create_tool_search(index) # Execute with a query result = filter_tool.execute( @@ -290,7 +290,7 @@ def test_filter_tool_execute(self, sample_tools): def test_filter_tool_call(self, sample_tools): """Test calling the filter tool with call method""" index = ToolIndex(sample_tools) - filter_tool = create_meta_search_tools(index) + filter_tool = create_tool_search(index) # Call with kwargs result = filter_tool.call(query="candidate", limit=2) @@ -299,19 +299,19 @@ def test_filter_tool_call(self, sample_tools): assert len(result["tools"]) <= 2 -class TestMetaExecuteTool: - """Test the meta_execute_tool functionality""" +class TestToolExecute: + """Test the tool_execute functionality""" def test_execute_tool_creation(self, tools_collection): """Test creating the execute tool""" - execute_tool = create_meta_execute_tool(tools_collection) + execute_tool = create_tool_execute(tools_collection) - assert execute_tool.name == "meta_execute_tool" + assert execute_tool.name == "tool_execute" assert "executes a tool" in execute_tool.description.lower() def test_execute_tool_missing_name(self, tools_collection): """Test execute tool with missing tool name""" - execute_tool = create_meta_execute_tool(tools_collection) + execute_tool = create_tool_execute(tools_collection) with pytest.raises(ValueError, match="toolName is required"): execute_tool.execute({"params": {}}) @@ -320,7 +320,7 @@ def test_execute_tool_with_json_string(self, tools_collection): """Test execute tool with JSON string input.""" import json - execute_tool = create_meta_execute_tool(tools_collection) + execute_tool = create_tool_execute(tools_collection) # Execute with JSON string - should raise ValueError for invalid tool json_input = json.dumps({"toolName": "nonexistent_tool", "params": {}}) @@ -329,7 +329,7 @@ def test_execute_tool_with_json_string(self, tools_collection): def test_execute_tool_invalid_name(self, tools_collection): """Test execute tool with invalid tool name""" - execute_tool = create_meta_execute_tool(tools_collection) + execute_tool = create_tool_execute(tools_collection) with pytest.raises(ValueError, match="Tool 'invalid_tool' not found"): execute_tool.execute( @@ -342,14 +342,14 @@ def test_execute_tool_invalid_name(self, tools_collection): @respx.mock def test_execute_tool_call(self, tools_collection): """Test calling the execute tool with call method""" - execute_tool = create_meta_execute_tool(tools_collection) + execute_tool = create_tool_execute(tools_collection) # Mock the actual tool execution route = respx.get("https://api.example.com/hibob/employee").mock( return_value=httpx.Response(200, json={"success": True, "employees": []}) ) - # Call the meta execute tool + # Call the tool_execute tool result = execute_tool.call(toolName="hibob_list_employee", params={"limit": 10}) assert result == {"success": True, "employees": []} @@ -357,27 +357,27 @@ def test_execute_tool_call(self, tools_collection): assert route.calls[0].response.status_code == 200 -class TestToolsMetaTools: - """Test the meta_tools method on Tools collection""" +class TestToolsUtilityTools: + """Test the utility_tools method on Tools collection""" - def test_meta_tools_creation(self, tools_collection): - """Test creating meta tools from a Tools collection""" - meta_tools = tools_collection.meta_tools() + def test_utility_tools_creation(self, tools_collection): + """Test creating utility tools from a Tools collection""" + utility_tools = tools_collection.utility_tools() - assert isinstance(meta_tools, Tools) - assert len(meta_tools) == 2 + assert isinstance(utility_tools, Tools) + assert len(utility_tools) == 2 # Check tool names - tool_names = [tool.name for tool in meta_tools.tools] - assert "meta_search_tools" in tool_names - assert "meta_execute_tool" in tool_names + tool_names = [tool.name for tool in utility_tools.tools] + assert "tool_search" in tool_names + assert "tool_execute" in tool_names - def test_meta_tools_functionality(self, tools_collection): - """Test that meta tools work correctly""" - meta_tools = tools_collection.meta_tools() + def test_utility_tools_functionality(self, tools_collection): + """Test that utility tools work correctly""" + utility_tools = tools_collection.utility_tools() # Get the filter tool - filter_tool = meta_tools.get_tool("meta_search_tools") + filter_tool = utility_tools.get_tool("tool_search") assert filter_tool is not None # Search for tools @@ -475,14 +475,14 @@ def test_hybrid_search_with_different_alphas(self, sample_tools): f"Balanced results: {[r.name for r in results_balanced]}" ) - def test_meta_tools_with_custom_alpha(self, sample_tools): - """Test that meta_tools() accepts hybrid_alpha parameter""" + def test_utility_tools_with_custom_alpha(self, sample_tools): + """Test that utility_tools() accepts hybrid_alpha parameter""" tools_collection = Tools(sample_tools) - # Create meta tools with custom alpha - meta_tools = tools_collection.meta_tools(hybrid_alpha=0.3) + # Create utility tools with custom alpha + utility_tools = tools_collection.utility_tools(hybrid_alpha=0.3) - filter_tool = meta_tools.get_tool("meta_search_tools") + filter_tool = utility_tools.get_tool("tool_search") assert filter_tool is not None # Check that description mentions the alpha value From 0b99f722f46a3c459cabe61bb84c597dc4ef765c Mon Sep 17 00:00:00 2001 From: ryoppippi <1560508+ryoppippi@users.noreply.github.com> Date: Thu, 29 Jan 2026 16:38:07 +0000 Subject: [PATCH 2/2] docs(readme): update Features list to use Utility Tools naming Update the Features bullet point from "Meta Tools" to "Utility Tools" for consistency with the renamed section heading and tool names. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1fa0ebf..6ac0410 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ StackOne AI provides a unified interface for accessing various SaaS tools throug - Glob pattern filtering with patterns like `"hris_*"` and exclusions `"!hris_delete_*"` - Provider and action filtering - Multi-account support -- **Meta Tools** (Beta): Dynamic tool discovery and execution based on natural language queries +- **Utility Tools** (Beta): Dynamic tool discovery and execution based on natural language queries - Integration with popular AI frameworks: - OpenAI Functions - LangChain Tools