Skip to main content

Initialize the ToolSet

Start by creating a StackOneToolSet instance. The SDK automatically reads STACKONE_API_KEY, so you typically only provide fallback account IDs or custom HTTP settings:
from stackone_ai import StackOneToolSet

toolset = StackOneToolSet()
account_id = "your-customer-account-id"

Get Tools

Use glob patterns to retrieve specific tools:
# Get all HRIS tools
hris_tools = toolset.get_tools('hris_*', account_id=account_id)

# Get all ATS tools
ats_tools = toolset.get_tools('ats_*', account_id=account_id)

# Get specific list operations
list_tools = toolset.get_tools('hris_list_*', account_id=account_id)

Execute Tools

Basic Tool Execution

# Convert filtered tools to a tool collection
tools = toolset.get_tools('hris_*', account_id=account_id)
employee_tool = tools.get_tool('hris_list_employees')

# Execute with keyword arguments via call()
employees = employee_tool.call(limit=10, include_details=True)
print(employees.data)

Alternative Execution Methods

# Method 1: call() with keyword arguments (recommended)
result = employee_tool.call(id="employee-123", include_details=True)

# Method 2: execute() with dictionary payloads
result = employee_tool.execute({"id": "employee-123", "include_details": True})

# Method 3: execute() with OpenAI-style arguments
payload = {"arguments": {"id": "employee-123"}}
result = employee_tool.execute(payload)

# Convert back to native dataclasses or dicts as needed
print(result.data)

Attaching Session Context to Calls

Both execution styles accept an optional options keyword to pass metadata that is not forwarded to the StackOne API. The Python SDK uses this information to power telemetry features such as LangSmith implicit feedback streams:
employee_tool.call(
    id="employee-123",
    options={
        "feedback_session_id": "chat-42",
        "feedback_user_id": "user-123",
        "feedback_metadata": {"conversation_id": "abc"},
    },
)

Error Handling

from stackone_ai.exceptions import StackOneError, ToolExecutionError

try:
    result = employee_tool.call(id="employee-123")
    print("Success:", result)
except ToolExecutionError as e:
    print(f"Tool execution failed: {e.message}")
except StackOneError as e:
    print(f"StackOne API error: {e.message}")
except Exception as e:
    print(f"Unexpected error: {e}")

Tool Filtering

Advanced Filtering Patterns

# Get all tools for multiple categories
all_tools = toolset.get_tools(['hris_*', 'ats_*'], account_id=account_id)

# Exclude dangerous operations
safe_tools = toolset.get_tools(['hris_*', '!hris_delete_*'], account_id=account_id)

# Get only read operations
read_only_tools = toolset.get_tools(['*_list_*', '*_get_*'], account_id=account_id)

List Available Tools

# Get all available tools
tools = toolset.get_tools('*', account_id=account_id)

# List tool names
tool_names = tools.list_tools()
print('Available tools:', tool_names)

# Get specific tool information
tool_info = tools.get_tool_info('hris_list_employees')
print('Tool info:', tool_info)

Working with Results

Processing Tool Results

employees = employee_tool.call(limit=50)

# Process the results
for employee in employees.data:
    print(f"{employee.first_name} {employee.last_name} - {employee.email}")

# Check pagination
if employees.next:
    print('More results available')

Handling Different Data Types

# List operations return arrays
departments = dept_tool.call()
print(f"Found {len(departments.data)} departments")

# Get operations return single objects
employee = employee_tool.call(id='emp_123')
print(f"Employee: {employee.data.display_name}")

Environment Configuration

Using Environment Variables

import os
from stackone_ai import StackOneToolSet

# Set in your .env file
# STACKONE_API_KEY=your_api_key
# STACKONE_ACCOUNT_ID=your_account_id

toolset = StackOneToolSet(
    api_key=os.getenv('STACKONE_API_KEY')
)

# Use environment account ID as default
account_id = os.getenv('STACKONE_ACCOUNT_ID') or 'fallback-account-id'

Using python-dotenv

from dotenv import load_dotenv
import os

# Load environment variables from .env file
load_dotenv()

from stackone_ai import StackOneToolSet

toolset = StackOneToolSet(
    api_key=os.getenv('STACKONE_API_KEY')
)

Dynamic Account Handling

# Handle multiple customer accounts
customer_accounts = ['account-1', 'account-2', 'account-3']

for account_id in customer_accounts:
    tools = toolset.get_tools('hris_list_employees', account_id=account_id)
    employees = tools.get_tool('hris_list_employees').call()

    print(f"Account {account_id}: {len(employees.data)} employees")

Meta Tools

Use meta tools to discover and execute StackOne tools dynamically via natural language search:
tools = toolset.get_tools('*', account_id=account_id)
meta_tools = tools.meta_tools()

search = meta_tools.get_tool('meta_search_tools')
results = search.call(query='manage employees create update list', limit=5, minScore=0.3)

if results.get('tools'):
    execute = meta_tools.get_tool('meta_execute_tool')
    output = execute.call(
        tool_name=results['tools'][0]['name'],
        params={'limit': 10}
    )
    print(output)
Meta tools work with LangChain, CrewAI, and OpenAI out of the box—see /agents/python/meta-tools for adapters and best practices.

Implicit Feedback

The SDK can emit implicit behavioural signals to LangSmith whenever a tool is executed. Provide a LangSmith API key and optional overrides via environment variables:
LANGSMITH_API_KEY=your_langsmith_key
STACKONE_IMPLICIT_FEEDBACK_ENABLED=true  # defaults to true when an API key exists
STACKONE_IMPLICIT_FEEDBACK_PROJECT=stackone-agents
STACKONE_IMPLICIT_FEEDBACK_TAGS=python-sdk,stackone
For full control, configure the feedback manager in code:
from stackone_ai import configure_implicit_feedback

configure_implicit_feedback(
    project_name='stackone-agents',
    default_tags=['python-sdk'],
    session_resolver=lambda: 'chat-42',
    user_resolver=lambda: 'user-123',
)
The callbacks give you a chance to derive identifiers from your chat state before telemetry is sent. When the same session triggers two tool calls in quick succession, the SDK emits a refinement_needed event so you can diagnose loops or poor results inside LangSmith.

Next Steps