Callable Tools Factory
Pass a function as `tools` instead of a list.
Pass a function as tools instead of a list. The function is called at the start of each run, so the toolset can vary per user or session.
1"""2Callable Tools Factory3======================4Pass a function as `tools` instead of a list. The function is called5at the start of each run, so the toolset can vary per user or session.67The factory receives parameters by name via signature inspection:8- agent: the Agent instance9- run_context: the current RunContext (has user_id, session_id, etc.)10- session_state: the current session state dict1112Results are cached per user_id (or session_id) by default.13"""1415from kern.agent import Agent16from kern.models.openai import OpenAIResponses17from kern.run import RunContext1819# ---------------------------------------------------------------------------20# Tools21# ---------------------------------------------------------------------------222324def search_web(query: str) -> str:25 """Search the web for information."""26 return f"Search results for: {query}"272829def search_internal_docs(query: str) -> str:30 """Search internal documentation (admin only)."""31 return f"Internal doc results for: {query}"323334def get_account_balance(account_id: str) -> str:35 """Get account balance (finance only)."""36 return f"Balance for {account_id}: $42,000"373839# ---------------------------------------------------------------------------40# Callable Factory41# ---------------------------------------------------------------------------424344def tools_for_user(run_context: RunContext):45 """Return different tools based on the user's role stored in session_state."""46 role = (run_context.session_state or {}).get("role", "viewer")47 print(f"--> Resolving tools for role: {role}")4849 base_tools = [search_web]50 if role == "admin":51 base_tools.append(search_internal_docs)52 if role in ("admin", "finance"):53 base_tools.append(get_account_balance)5455 return base_tools565758# ---------------------------------------------------------------------------59# Create Agent60# ---------------------------------------------------------------------------61agent = Agent(62 model=OpenAIResponses(id="gpt-5-mini"),63 tools=tools_for_user,64 instructions=[65 "You are a helpful assistant.",66 "Use the tools available to you to answer the user's question.",67 ],68)697071# ---------------------------------------------------------------------------72# Run Agent73# ---------------------------------------------------------------------------74if __name__ == "__main__":75 # Run 1: viewer role - only search_web available76 # Each user_id gets its own cached toolset77 print("=== Run as viewer ===")78 agent.print_response(79 "Search for recent news about AI agents",80 user_id="viewer_user",81 session_state={"role": "viewer"},82 stream=True,83 )8485 # Run 2: admin role - all tools available86 # Different user_id means the factory is called again with new context87 print("\n=== Run as admin ===")88 agent.print_response(89 "Search internal docs for the deployment guide and check account balance for ACC-001",90 user_id="admin_user",91 session_state={"role": "admin"},92 stream=True,93 )Run the Example
1# Clone and setup repo2git clone https://github.com/kern-ai/kern.git3cd kern/cookbook/02_agents/04_tools45# Create and activate virtual environment6./scripts/demo_setup.sh7source .venvs/demo/bin/activate89python 01_callable_tools.py