Skip to main content
Python tools are one of the most flexible and powerful ways to extend agent functionality in watsonx Orchestrate, especially when combined with agentic workflows. A Python tool consists of one or more Python files. Within these files, you define one or more functions and annotate them with the @tool decorator to expose them to Orchestrate. Each Python tool runs inside an isolated container with its own virtual environment. This ensures that the tool and its dependencies remain sandboxed from the host operating system, providing a secure and consistent runtime. Python tool example
Python
#test_tool.py
from ibm_watsonx_orchestrate.agent_builder.tools import tool


@tool()
def my_tool(input: str) -> str:
    """Executes the tool's action based on the provided input.

    Args:
        input (str): The input of the tool.

    Returns:
        str: The action of the tool.
    """

    #functionality of the tool

    return f"Hello, {input}"
Note:
Python tools must use Google-style docstrings to apply descriptions and document the tool.

Importing Python-based tools

To import a Python tool use the orchestrate tools import command using the -f flag to specify which python file contains your tool definitions. Each @tool annotated in the given file will be exposed as a tool within your active watsonx Orchestrate environment. It is recommended to include only a single @tool annotated function per file so that tools can be imported independently.
BASH
orchestrate tools import -k python -f my-tool.py -r requirements.txt -a app1 -a app2

Additional features of Python tools

If your Python function relies on external libraries or packages, you can ensure your tool works correctly by specifying these dependencies in the requirements.txt file.Python tool example
Python
import requests
from ibm_watsonx_orchestrate.agent_builder.tools import tool


@tool
def fetch_url(endpoint: str) -> str:
    """Executes a GET request against a given endpoint to fetch its contents.

    Args:
        endpoint (str): the url to fetch

    Returns:
        str: the contents of the page
    """

    #functionality of the tool

    return requests.get(endpoint).text
requirements.txt example
TEXT
requests==2.32.4
For more information on the format of a requests file, please see the official pip documentation.
When importing your tool, specify the requirements.txt file by using the -r flag.
BASH
orchestrate tools import -k python -f my-tool.py -r requirements.txt
Python tools support input and output arguments based on any native Python type from the typings package and classes which extend BaseModel from the popular library Pydantic.Example
PYTHON
import requests
from ibm_watsonx_orchestrate.agent_builder.tools import tool
from pydantic import BaseModel

class InputExample(BaseModel):
    sample: Optional[str] = Field(None, description="description of my field")

class OutputExample(BaseModel):
    result: Optional[str] = Field(None, description="description of my result field")

@tool
def fetch_url(example: InputExample, endpoint: str) -> OutputExample:
    """Executes a GET request against a given endpoint to fetch its contents.

    Args:
        example: An example input object that takes a sample
        endpoint: an example endpoint

    Returns:
        OutputExample: the example output
    """

    #functionality of the tool

    return OutputExample(result=requests.get(endpoint).text)
Python tools are compatible with the watsonx Orchestrate Connections framework. A connection represents a dependency on an external service and are a way to associate credentials to a tool such as those for Basic, Bearer, API Key, OAuth, or IDP SSO based authentication flows. Python tools also support key_value connections which as the name implies are arbitrary dictionaries of keys and values which can be used to pass in credentials for any authorization scheme which does not match one of the existing native schemes.Connections are referenced by something known as an application id (or app_id). This app_id is the unique identifier of a connection. OpenAPI connections can have at most one Connection’s app_id associated to them.For more information please see, Connections, and the expected_credentials input to the @tool annotation.
In addition to importing a single tool file, it is possible to import an entire folder (package) along with your tool file. This is useful when you wish to centralize logic into shared utility libraries, for example, shared authentication, data processing, or including static files such as CSVs or sqlite databases.Assuming a folder structure as follows:
─── my_agentic_project/
    └── tools/
        └── multi_file_tool/
            └── utils/
               └── csv_utils.py
               └── __init__.py
            └── my_tool.py
            └── my_data.csv
            └── requirements.txt
my_tool.py:
PYTHON
from ibm_watsonx_orchestrate.agent_builder.tools import tool
from os import path
import pandas as pd
from .utils.csv_utils import parse_csv # this is a relative import of my csv_utils.py file I included in this package

@tool
def return_file_contents() -> str:
    """
    Gets the contents of my super important csv file as a table.

    Returns:
        str: the contents of the csv
    """
    base_path = os.path.dirname(os.path.abspath(__file__))
    file_path = path.join(base_path, 'my_data.csv')
    dataframe: pd.DataFrame = parse_csv(file_path)

    return dataframe.to_markdown() # note dataframe output is unsupported, but dataframe.to_markdown will render a table in a format which the ui knows how to render
Importing your multifile Python tool:
Assuming your CLI was currently in the my_agentic_project folder, this tool could be imported using the following:
BASH
orchestrate tools import -k python \
    -p tools/multi_file_tool \
    -f tools/multi_file_tool/my_tool.py \
    -r tools/multi_file_tool/requirements.txt
Notes:
  • Only tools defined in my_tool.py will be imported. Other Python files in the package will not be scanned for tools.
  • The system will only accept strings composed of alphanumeric characters and underscores (_) in the name attribute of the @tool decorator in my_tool.py.
  • The system will only accept tool file names composed of alphanumeric characters and underscores (_).
  • The package root folder and the tool file path CLI arguments MUST share a common base path.
  • The path of the tool file folder relative to the package root folder, must be composed of folder names which are only composed of alphanumeric characters and underscores (_).
  • Any whitespace like characters which prefix or suffix provided package root path will be stripped by the system.
  • A package root folder path that resolves to an empty string will make the system assume that no package root was specified. Then, the system falls back to single Python file tool import.
Limitations:
  • The max compressed tool size: 50Mb
  • File resolution for non-python packages must be done relative to the current file, as seen above
  • Imports to packages within your code must be resolved relatively
You can create Python tools that accept files or return files to download.To do that, you must comply with the following requirements:
  • To accept files as input, the tool must accept a sequence of bytes as arguments.
  • To return a file for download, the tool must return a sequence of bytes as output.
The following example accepts a file as input and returns the processed file for download:
from typing import Union
from io import BytesIO
from typing import Any
from ibm_watsonx_orchestrate.agent_builder.tools import tool
import base64

@tool
def create_image_with_filter(name: str, age: int, image_bytes: bytes) -> bytes:
    """Gets user information, applies a filter to the image, and returns the processed image.

    Args:
        name (str): The user's name.
        age (int): The user's age.
        image_bytes (bytes): The original image in bytes format.

    Returns:
        bytes: The processed image in bytes format.
    """

    import cv2
    import numpy as np
    from typing import Union
    from io import BytesIO
    # Convert bytes to numpy array
    image_array = np.frombuffer(image_bytes, np.uint8)
    image = cv2.imdecode(image_array, cv2.IMREAD_COLOR)

    if image is None:
        raise ValueError("Invalid image bytes provided")

    # Apply bilateral filter for smoothing while preserving edges
    smooth = cv2.bilateralFilter(image, d=9, sigmaColor=75, sigmaSpace=75)

    # Convert to grayscale and detect edges
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    edges = cv2.medianBlur(gray, 7)
    edges = cv2.adaptiveThreshold(
        edges, 255, cv2.ADAPTIVE_THRESH_MEAN_C,
        cv2.THRESH_BINARY, blockSize=9, C=2
    )

    # Convert edges to color image
    edges_colored = cv2.cvtColor(edges, cv2.COLOR_GRAY2BGR)

    # Combine smoothed image with edges
    cartoon = cv2.bitwise_and(smooth, edges_colored)

    # Enhance color saturation
    hsv = cv2.cvtColor(cartoon, cv2.COLOR_BGR2HSV)
    hsv[..., 1] = cv2.multiply(hsv[..., 1], 1.4)  # increase saturation
    cartoon_enhanced = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)

    # Convert back to bytes
    success, buffer = cv2.imencode('.jpg', cartoon_enhanced)
    if not success:
        raise RuntimeError("Failed to encode image")

    return buffer.tobytes()
Use the WXOFile parameter type when a tool must reference a file without processing its full content.
The WXOFile class provides methods to retrieve file properties or content as needed.
You can call the following methods:
MethodDescription
WXOFile.get_file_name(wxo_file)Returns the file name.
WXOFile.get_file_size(wxo_file)Returns the file size in bytes.
WXOFile.get_file_type(wxo_file)Returns the file MIME type, such as image/jpeg or text/plain.
WXOFile.get_content(wxo_file)Returns the file content in bytes.
Use this approach when a tool only needs file metadata or to read the content on demand.
It helps reduce processing overhead and improves performance.
from ibm_watsonx_orchestrate.agent_builder.tools import tool, ToolPermission, WXOFile


@tool(permission=ToolPermission.READ_ONLY)
def get_file_metadata(wxo_file: WXOFile, session_id: str) -> str:
    """This tool receives a file reference and a session id and outputs the file's metadata with the session id.

    Args:
        wxo_file (WXOFile): a file input URL reference
        session_id (str): a session ID

    Returns:
        str: A string containing the file name, size and type with the session ID
    """

    filename = WXOFile.get_file_name(wxo_file)
    file_size = WXOFile.get_file_size(wxo_file)
    file_type = WXOFile.get_file_type(wxo_file)
    file_content = WXOFile.get_content(wxo_file) # content in bytes

    return f"File name: {filename}, File size: {file_size}, File type: {file_type} for session ID: {session_id}"

Runtime and migration strategy

Python tools execute within a UV virtual environment inside a component called the tools runtime. This runtime includes a predefined set of supported Python versions. Currently, the only supported version is Python 3.12.

Version Management

  • When a tool is imported into the runtime, it uses the Python version it was originally imported with.
  • If that version becomes deprecated by watsonx Orchestrate, the system will:
    • Display a deprecation warning in the UI.
    • Show the same warning when running the command:
      orchestrate tools list
      
    • Inform the user that the tool must be reimported to remain compatible.

Deprecation Timeline

  • After 24 months of deprecation:
    • The runtime will remove support for the deprecated Python version.
    • If the tool has not been reimported, the runtime will attempt to reimport it using the closest supported Python version.

Limitations of Python tools

Host networking

  • watsonx Orchestrate Developer Edition: Python tools run inside a container. In this environment, localhost refers to the container itself, not the host machine. To call an endpoint on the host machine, use docker.host.internal or the host machine’s IP address.
  • SaaS: The SaaS version of watsonx Orchestrate cannot access your company’s internal network. If internal access is required, prototype with the Developer Edition and then deploy watsonx Orchestrate on-premises or consult IBM for alternative solutions.
  • On-premises: To allow a tool to access external internet resources, ensure that firewall rules do not block outbound traffic from the node pool responsible for tool execution.

Read only filesystem

For security and stability, tools execute in a read-only filesystem. Each tool can access only its own filesystem and cannot modify files during execution.