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:

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 CodedTool from neuro_san.interfaces.coded_tool and implementing the async_invoke method.
  • Place tool implementations in coded_tools/tools/<your_tool>.py and expose them via coded_tools/tools/__init__.py to enable dynamic loading.
  • Reference tools in your HOCON network configuration using fully-qualified class names (e.g., coded_tools.tools.WeatherLookup).
  • Use sly_data for secure credential passing (API keys, tokens) that must remain hidden from the LLM, while args contains user-visible parameters.
  • Leverage CodedToolAgentCaller to orchestrate sub-agents from within tools, and extend OpenAITool for 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →