How to Create Custom Coded Tools in Neuro SAN: A Complete Developer Guide
Create custom coded tools in Neuro SAN by subclassing the CodedTool interface, implementing the asynchronous async_invoke method, and registering the class in your agent network's HOCON configuration.
Neuro SAN, the open-source agent orchestration framework from the cognizant-ai-lab/neuro-san-studio repository, allows developers to extend agent capabilities beyond LLM reasoning by implementing custom coded tools. These Python components execute inside the Neuro SAN runtime, enabling agents to query external APIs, access databases, or perform complex computations while maintaining seamless integration with the conversational flow.
What Are Coded Tools in Neuro SAN?
Coded tools are specialized Python classes that inherit from the CodedTool interface located at neuro_san.interfaces.coded_tool.CodedTool. Unlike declarative tool definitions that rely solely on LLM function calling, coded tools provide deterministic, code-driven execution environments where developers control the exact logic, error handling, and external integrations.
When an agent invokes a coded tool, Neuro SAN automatically instantiates the tool class (once per agent network load), passes the user-provided arguments and private session data, executes the asynchronous async_invoke method, and returns the result back to the calling agent as a standard message.
Implementing the CodedTool Interface
The async_invoke Method Contract
Every custom tool must implement the async_invoke method with the following signature:
async def async_invoke(self, args: Dict[str, Any], sly_data: Dict[str, Any]) -> Any:
The method receives two dictionaries:
args: Contains the arguments supplied by the agent prompt (e.g.,{"city": "Paris"}). These are visible to the LLM and extracted from the natural language request.sly_data: Contains private "sly data" such as API keys, user session tokens, or internal metadata. This data is never exposed to the LLM and is used for secure credential passing or context management.
The method can return strings, dictionaries, lists, or any JSON-serializable object that the agent can incorporate into its reasoning.
Tool Lifecycle and Instantiation
Neuro SAN instantiates coded tool classes once per agent network load, not per invocation. This design pattern allows tools to maintain persistent connections, cache data, or initialize expensive resources (like database pools) efficiently. The __init__ method receives no special arguments from the framework, though some advanced patterns (like CodedToolAgentCaller) may inject dependencies during instantiation.
Step-by-Step: Building Your First Custom Tool
1. Create the Tool Class
Create a new Python file under coded_tools/tools/ and subclass CodedTool. Here is a minimal "Hello" tool implementation:
# coded_tools/tools/hello_tool.py
import logging
from typing import Any, Dict
from neuro_san.interfaces.coded_tool import CodedTool
class HelloTool(CodedTool):
"""
Simple example: returns a greeting.
"""
def __init__(self):
self.logger = logging.getLogger(__name__)
async def async_invoke(self, args: Dict[str, Any], sly_data: Dict[str, Any]) -> str:
name = args.get("name", "world")
self.logger.info("HelloTool invoked with name=%s", name)
return f"👋 Hello, {name}!"
2. Expose the Tool in the Package
Import the class in coded_tools/tools/__init__.py to make it available for dynamic loading:
# coded_tools/tools/__init__.py
from .hello_tool import HelloTool
# other tool imports...
3. Register in HOCON Network Configuration
Reference the fully-qualified class name in your agent network definition (e.g., network.hocon):
agents {
greeter {
class = "myagents.Greeter"
tools = [ "coded_tools.tools.HelloTool" ]
}
}
Start Neuro SAN (python -m run). When the greeter agent issues a tool call like {{tool: HelloTool name="Alice"}}, Neuro SAN executes your custom logic and returns the formatted greeting.
Advanced Patterns for Coded Tools
Calling External APIs with Async HTTP
For real-world integrations, implement asynchronous HTTP calls using aiohttp or httpx. This example demonstrates a weather lookup tool that securely accesses API keys through sly_data:
# coded_tools/tools/weather_lookup.py
import logging
import aiohttp
from typing import Any, Dict
from neuro_san.interfaces.coded_tool import CodedTool
class WeatherLookup(CodedTool):
"""
Calls the OpenWeatherMap API and returns the current temperature.
"""
def __init__(self):
self.logger = logging.getLogger(__name__)
async def async_invoke(self, args: Dict[str, Any], sly_data: Dict[str, Any]) -> str:
city = args.get("city")
if not city:
return "Error: `city` argument is required."
api_key = sly_data.get("openweather_api_key")
if not api_key:
return "Error: OpenWeatherMap API key not provided in sly_data."
endpoint = (
f"https://api.openweathermap.org/data/2.5/weather"
f"?q={city}&units=metric&appid={api_key}"
)
async with aiohttp.ClientSession() as session:
async with session.get(endpoint) as resp:
if resp.status != 200:
return f"Error: Weather service returned {resp.status}"
data = await resp.json()
temp = data["main"]["temp"]
description = data["weather"][0]["description"]
return f"The current temperature in {city} is {temp} °C with {description}."
Orchestrating Sub-Agents with CodedToolAgentCaller
Complex workflows may require a tool to delegate tasks to other agents in the network. Use CodedToolAgentCaller to invoke agents from within async_invoke:
# coded_tools/tools/agent_bridge.py
import logging
from typing import Any, Dict
from neuro_san.interfaces.coded_tool import CodedTool
from coded_tools.tools.coded_tool_agent_caller import CodedToolAgentCaller
class AgentBridge(CodedTool):
"""
Calls a secondary agent and returns its reply.
"""
def __init__(self, branch_activation):
# branch_activation is injected by Neuro SAN during instantiation
self.caller = CodedToolAgentCaller(branch_activation)
self.logger = logging.getLogger(__name__)
async def async_invoke(self, args: Dict[str, Any], sly_data: Dict[str, Any]) -> str:
target = args.get("target_agent")
query = args.get("query")
if not target or not query:
return "Error: `target_agent` and `query` are required."
response = await self.caller.call_agent(target, {"query": query}, sly_data)
return f"Response from {target}: {response}"
Wrapping OpenAI Built-in Tools
For integrations with OpenAI's native capabilities (image generation, code interpreter, web search), extend the OpenAITool wrapper class located at coded_tools/tools/openai_tool.py. This base class handles authentication and provides the arun method for executing OpenAI tool calls asynchronously.
Reference implementations include:
openai_image_generation.py– Generates images using DALL-Ewikipedia_rag.py– Implements retrieval-augmented generation using LangChain retrievers
Key Reference Files in the Repository
| File | Purpose | Location |
|---|---|---|
coded_tools/tools/openai_image_generation.py |
Wraps OpenAI image generation capabilities | View source |
coded_tools/tools/wikipedia_rag.py |
RAG implementation using LangChain Wikipedia retriever | View source |
coded_tools/tools/coded_tool_agent_caller.py |
Helper for invoking other agents from within tools | View source |
coded_tools/tools/openai_tool.py |
Base wrapper for OpenAI built-in tools | View source |
run.py |
Entry point that loads HOCON networks and registers tools | View source |
Summary
- Create custom coded tools in Neuro SAN by subclassing
CodedToolfromneuro_san.interfaces.coded_tooland implementing theasync_invokemethod. - Place tool implementations in
coded_tools/tools/<your_tool>.pyand expose them viacoded_tools/tools/__init__.pyto enable dynamic loading. - Reference tools in your HOCON network configuration using fully-qualified class names (e.g.,
coded_tools.tools.WeatherLookup). - Use
sly_datafor secure credential passing (API keys, tokens) that must remain hidden from the LLM, whileargscontains user-visible parameters. - Leverage
CodedToolAgentCallerto orchestrate sub-agents from within tools, and extendOpenAIToolfor wrapping OpenAI native capabilities.
Frequently Asked Questions
What is the difference between args and sly_data in async_invoke?
The args dictionary contains parameters extracted from the agent's natural language request (e.g., {"city": "Paris"}), which are visible to the LLM during tool selection. The sly_data dictionary contains private session data such as API keys, authentication tokens, or internal metadata that is never exposed to the LLM. This separation ensures sensitive credentials remain secure while allowing the agent to reason about tool parameters.
Can I use synchronous libraries inside a coded tool?
While you can technically use synchronous code, the async_invoke method is designed for asynchronous execution. For I/O-bound operations like HTTP requests or database queries, use async libraries such as aiohttp or asyncpg to avoid blocking the Neuro SAN event loop. If you must use synchronous code, wrap it in asyncio.to_thread() or similar executors to maintain runtime performance.
How do I debug a coded tool during development?
Since coded tools are instantiated once per network load and executed within the Neuro SAN runtime, use standard Python logging via logging.getLogger(__name__) within your tool class. Start the server with python -m run and monitor stdout for log output. For deeper debugging, you can add breakpoints in async_invoke and attach a debugger, or temporarily add print statements (though logging is preferred for production code).
Can coded tools call other agents in the network?
Yes. Use the CodedToolAgentCaller helper class (located at coded_tools/tools/coded_tool_agent_caller.py) to invoke other agents from within async_invoke. When Neuro SAN instantiates your tool, it injects the current BranchActivation context, which you pass to CodedToolAgentCaller to enable agent-to-agent communication. This pattern is essential for complex orchestration workflows where a tool needs to delegate sub-tasks to specialized agents.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →