How to Debug Coded Tools Using pytest.set_trace() in Neuro-SAN Studio

Use from pytest import set_trace in your test file, insert set_trace() at the desired breakpoint, and run python -m pytest <test_file> -s to drop into an interactive debugger that lets you inspect the internal state of any coded tool.

Neuro-SAN Studio, maintained by cognizant-ai-lab, provides a framework for building agent networks using coded tools—Python classes like Accountant, CalculatorTool, and TimeTool that expose custom logic to agents. When these tools misbehave or return unexpected results, you need a way to inspect their execution flow without modifying the core framework. The pytest.set_trace() helper offers a lightweight, zero-dependency method to pause test execution and examine variables directly inside the tool's runtime context.

Why Use pytest.set_trace() for Coded Tools?

While Python’s built-in pdb.set_trace() works, pytest.set_trace() offers tighter integration with the test runner used throughout Neuro-SAN Studio. Because the debugger runs in the same process as the test, you can inspect arguments passed to the tool, step through the invoke method line-by-line, and modify state on-the-fly to test edge cases.

Key advantages over standard PDB:

  • Automatic pytest integration – Respects pytest’s capture settings and output handling.
  • Works seamlessly with -s – No manual disabling of output capture required.
  • Consistent with pytest idioms – Aligns with other helpers like pytest.raises.

Step-by-Step Debugging Workflow

Locate the Target Test

Identify the unit test that exercises the coded tool you need to debug. For example, tests/coded_tools/basic/test_accountant.py validates the Accountant tool defined in coded_tools/basic/accountant.py.

Insert the Breakpoint

Import the helper at the top of your test file and place set_trace() immediately after instantiating the tool or before calling its invoke method:


# tests/coded_tools/basic/test_accountant.py

from pytest import set_trace
from coded_tools.basic.accountant import Accountant

def test_accountant_balance():
    # Arrange – instantiate the tool

    tool = Accountant()
    # Drop into debugger right after construction

    set_trace()

    # Act – invoke the tool with a sample prompt

    result = tool.invoke("What is the balance of account 12345?")

    # Assert – verify expected output

    assert "balance" in result.lower()

Run with Interactive Output

Execute pytest with the -s flag to prevent the runner from capturing stdin/stdout, ensuring the debugger interface remains interactive:

python -m pytest tests/coded_tools/basic/test_accountant.py -s

When execution hits set_trace(), you’ll see a (Pdb) prompt. Use standard pdb commands to inspect the coded tool:

  • p tool – Display the tool instance.
  • p tool.some_internal_state – Inspect specific attributes.
  • n – Execute the next line (step over).
  • s – Step into a function call.
  • c – Continue execution until the next breakpoint or test completion.

Practical Example: Debugging the Accountant Tool

Consider a scenario where the Accountant tool returns malformed JSON. By placing set_trace() after instantiation in tests/coded_tools/basic/test_accountant.py, you can inspect the tool’s configuration before the invoke method processes the LLM call:

def test_accountant_json_output():
    tool = Accountant()
    set_trace()  # Inspect tool's internal config here

    
    result = tool.invoke("Get account 12345 details")
    assert isinstance(result, dict)

Running with -s allows you to verify that tool is properly initialized and that any internal dictionaries or API clients contain the expected credentials before the network request is made.

Advanced Debugging Techniques

Using ipdb for Enhanced UX

For a richer debugging experience with tab-completion and syntax highlighting, configure pytest to use ipdb:

pip install ipdb
export PYTHONBREAKPOINT=ipdb.set_trace

Now set_trace() will drop into ipdb instead of standard pdb, providing colored output and auto-completion for coded tool attributes.

Debugging Parameterized Tests

When a coded tool fails only on specific input combinations, insert set_trace() inside a parameterized test to inspect each iteration:

import pytest
from pytest import set_trace
from coded_tools.basic.calculator_tool import CalculatorTool

@pytest.mark.parametrize(
    "expression,expected",
    [
        ("2+2", 4),
        ("5*3", 15),
        ("invalid", None),   # <- this case fails

    ],
)
def test_calculator(expression, expected):
    tool = CalculatorTool()
    set_trace()                # Inspect each iteration

    result = tool.invoke(expression)
    assert result == expected

Run with python -m pytest <file> -s to pause on each parameter set and identify which input triggers the failure.

Key Files for Debugging Coded Tools

File Role
coded_tools/basic/accountant.py Example coded tool implementation showing how tools expose logic to agents.
tests/coded_tools/basic/test_accountant.py Unit test for Accountant—the ideal location to insert set_trace() for debugging tool behavior.
coded_tools/basic/advanced_calculator/calculator_tool.py Numeric logic demonstration tool useful for testing parameterized debugging scenarios.
tests/coded_tools/basic/advanced_calculator/test_calculator.py Corresponding test file for calculator logic.
pytest.ini Pytest configuration file defining markers and coverage settings for the test suite.
run.py Entry point for launching the Neuro-SAN Studio, useful when reproducing runtime failures in the full agent network context.

Summary

  • Import set_trace from pytest, not pdb, to ensure seamless integration with the Neuro-SAN Studio test runner.
  • Place breakpoints after tool instantiation in unit tests (e.g., tests/coded_tools/basic/test_accountant.py) to inspect coded tools like Accountant or CalculatorTool before they process inputs.
  • Always run with -s to prevent pytest from capturing stdin/stdout, ensuring the interactive debugger remains accessible.
  • Consider ipdb via PYTHONBREAKPOINT for enhanced debugging features like tab-completion when working with complex tool hierarchies.

Frequently Asked Questions

What is the difference between pytest.set_trace() and pdb.set_trace()?

pytest.set_trace() is specifically designed to work with the pytest test runner used in Neuro-SAN Studio. It automatically handles pytest’s output capture mechanisms, meaning you don’t need to manually disable capture to see the debugger prompt. In contrast, pdb.set_trace() may hang or behave unexpectedly when pytest is capturing stdout/stderr, requiring additional flags to function properly.

How do I debug a coded tool that fails only in the full agent network?

When a tool works in isolation but fails during full network execution, first reproduce the failure using the studio’s entry point in run.py. Then, create a targeted unit test in the tests/coded_tools/ directory that simulates the specific input triggering the failure. Insert set_trace() in this isolated test to inspect the tool’s state without the complexity of the full agent network running.

Can I use pytest.set_trace() with VS Code or PyCharm?

Yes, though IDE debuggers typically require additional configuration. When running tests inside VS Code or PyCharm, you can either use the IDE’s built-in "Debug Test" functionality instead of set_trace(), or configure the IDE to recognize the PDB prompt when running with -s. For the smoothest experience with set_trace(), run tests from the terminal with python -m pytest -s and use the command-line PDB interface.

Why does my debugger hang when running tests without the -s flag?

Pytest captures stdout and stderr by default to provide clean test output reports. When set_trace() triggers a PDB session, it attempts to read from stdin and write to stdout. If pytest is capturing these streams, the debugger cannot interact with your terminal, causing it to appear hung or frozen. The -s (or --capture=no) flag disables this capture, allowing the debugger direct access to the terminal I/O streams.

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 →