Overview
- Stateful workflows with persistent memory
- Graph-based execution with conditional branching
- Multi-step processes with human-in-the-loop
- Dynamic tool loading based on connected accounts
Copy
Ask AI
from stackone_ai import StackOneToolSet
from langgraph.prebuilt import create_react_agent
from langchain_openai import ChatOpenAI
def create_agent_for_account(account_id: str):
"""
Create LangGraph agent with tools for a specific account.
In production, account_id comes from:
- User/tenant context
- Authentication middleware
- Request parameters
"""
# Initialize toolset
toolset = StackOneToolSet()
# Fetch tools dynamically for this account
tools = toolset.fetch_tools(account_ids=[account_id])
# Convert to LangChain format (LangGraph uses LangChain tools)
langchain_tools = tools.to_langchain()
# Create LangGraph agent
model = ChatOpenAI(model="gpt-5")
agent = create_react_agent(model, langchain_tools)
return agent
# Use the agent
account_id = get_current_user_account() # Your function
agent = create_agent_for_account(account_id)
# Run stateful workflow
config = {"configurable": {"thread_id": "user-123-session"}}
result = agent.invoke(
{"messages": [("user", "Find all employees hired this year")]},
config=config
)
Dynamic Tool Loading
Load tools based on available integrations:Copy
Ask AI
from stackone_ai import StackOneToolSet
toolset = StackOneToolSet()
# Load all tools for specific accounts (most common)
tools = toolset.fetch_tools(
account_ids=["account-123"]
)
# Optional: Filter by operation type for security
tools = toolset.fetch_tools(
account_ids=["account-123"],
actions=["*_list_*", "*_get_*"] # Only list and get operations (read-only)
)
# Convert to LangChain format for LangGraph
langchain_tools = tools.to_langchain()
Stateful Workflows
Build complex, multi-step workflows with state:Copy
Ask AI
from langgraph.graph import StateGraph, MessagesState
from langgraph.prebuilt import ToolNode
from langchain_core.messages import SystemMessage
# Define workflow state
class AgentState(MessagesState):
employee_data: dict
analysis_complete: bool
# Create graph
def create_hr_workflow(account_id: str):
toolset = StackOneToolSet()
tools = toolset.fetch_tools(account_ids=[account_id])
langchain_tools = tools.to_langchain()
# Create nodes
tool_node = ToolNode(langchain_tools)
def agent_node(state: AgentState):
model = ChatOpenAI(model="gpt-5")
model_with_tools = model.bind_tools(langchain_tools)
messages = [
SystemMessage(content="You are an HR data analyst."),
*state["messages"]
]
response = model_with_tools.invoke(messages)
return {"messages": [response]}
# Build graph
workflow = StateGraph(AgentState)
workflow.add_node("agent", agent_node)
workflow.add_node("tools", tool_node)
workflow.set_entry_point("agent")
workflow.add_conditional_edges("agent", should_continue)
workflow.add_edge("tools", "agent")
return workflow.compile()
def should_continue(state: AgentState):
"""Decide whether to continue or finish"""
last_message = state["messages"][-1]
if not last_message.tool_calls:
return "end"
return "tools"
Human-in-the-Loop
Add human approval for sensitive operations:Copy
Ask AI
from langgraph.prebuilt import create_react_agent
from langgraph.checkpoint.memory import MemorySaver
def create_hr_agent_with_approval(account_id: str):
toolset = StackOneToolSet()
# Only expose read operations initially (optional filtering)
read_tools = toolset.fetch_tools(
account_ids=[account_id],
actions=["*_list_*", "*_get_*"] # Only list and get operations
)
agent = create_react_agent(
model=ChatOpenAI(model="gpt-5"),
tools=read_tools.to_langchain(),
checkpointer=MemorySaver()
)
return agent
# Usage: Approve before executing sensitive actions
agent = create_hr_agent_with_approval(account_id)
result = agent.invoke({"messages": [("user", "Review termination candidates")]})
# Human reviews, then loads write tools for approved actions
if user_approves(result):
write_tools = toolset.fetch_tools(
account_ids=[account_id],
actions=["*_update_*", "*_create_*"] # Only update and create operations
)
# Continue with write operations...
Best Practices
Account ID from Context
Copy
Ask AI
# Get from request context
account_id = get_account_from_auth_token(request)
account_id = tenant.stackone_account_id
Tool Security
Copy
Ask AI
# Optional: Only expose read operations for security
safe_tools = toolset.fetch_tools(
account_ids=[account_id],
actions=["*_list_*", "*_get_*"] # Only list and get operations
)
# Or exclude dangerous operations
safe_tools = toolset.fetch_tools(
account_ids=[account_id],
actions=["!*_delete_*"] # Everything except deletes
)
Next Steps
- Dynamic Tool Loading with
fetch_tools() - Tool Filtering for security
- LangChain Integration for simpler workflows