Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 12 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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(
Expand All @@ -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})
```

Expand All @@ -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

Expand Down
2 changes: 1 addition & 1 deletion examples/test_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"],
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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.
"""

Expand All @@ -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
Expand All @@ -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)
Expand All @@ -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")

Expand All @@ -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
Expand All @@ -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
Expand All @@ -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?"},
],
Expand Down Expand Up @@ -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:
Expand All @@ -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}"),
Expand All @@ -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"):
Expand Down
2 changes: 1 addition & 1 deletion stackone_ai/feedback/tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -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?" '
Expand Down
20 changes: 10 additions & 10 deletions stackone_ai/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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])
Loading