C3 AI Documentation Home

Create Tools from Code

Tools extend agent capabilities by allowing them to perform specific tasks and integrate with external resources. You can create tools from Python functions or existing C3 methods. The GenaiCore.Tool interface encapsulates all necessary information for easy integration with any tool using agentic framework.

Choose your implementation

Open Jupyter from your application to write and upsert the tool. The platform supports two approaches for creating tools: Native Python tools and C3 method tools.

Native Python tool

Use GenaiCore.Tool.NativePy to implement tools from Python functions. Native Python tools let you wrap custom logic as callable functions that agents can use.

Define your function with type hints and clear parameter descriptions:

Python
multiplier_src = '''
from typing_extensions import Annotated

def multiplier(
    a: Annotated[int, "First number"], 
    b: Annotated[int, "Second number"]
) -> int:
    """Return the product of two numbers."""
    return a * b
'''

Create and persist the tool instance:

Python
c3_multiplier_tool = c3.GenaiCore.Tool.NativePy.createFromPySrc(
    pySrc=multiplier_src,
    toolName="multiplier",
    actionRequirement="py-llm_312"
)

The actionRequirement parameter specifies the Python runtime environment needed to execute this tool. When you call createFromPySrc, the tool automatically becomes available in the agent gallery UI for immediate use within your current environment.

To make the tool available in your packaged application so that it persists when the application is deployed to other environments or clusters, see Publish the tool.

C3 method tool

Use GenaiCore.Tool.C3Method to expose an existing C3 Type static method as a tool. This lets you reuse logic already defined in the C3 AI Type System.

Static method tools

Define a static method in your C3 Type:

Type
entity type MyMathUtils {
    /**
     * Multiply two numbers.
     * @param a First number
     * @param b Second number
     * @return Product of a and b
     */
    multiply: function(a: !float, b: !float): !float py
}

Create the tool from the static method:

Python
my_type = c3.MyMathUtils
c3_multiply_tool = c3.GenaiCore.Tool.C3Method.createFromMethodName(
    type=my_type,
    methodName="multiply"
)

Instance method tools

Use createFromObjAndMethodName when the method requires a specific object instance.

Define an instance method in your C3 Type:

Type
entity type MyMathUtils {
    /**
     * Multiply two numbers with instance state.
     */
    multiply: member function(a: !float, b: !float): !float py
}

Create the tool from the instance method:

Python
my_math_utils_instance = c3.MyMathUtils()
c3_member_multiplier_tool = c3.GenaiCore.Tool.C3Method.createFromObjAndMethodName(
    obj=my_math_utils_instance,
    methodName="multiply"
)

The tool automatically extracts parameter information and documentation from the Type method definition. When you call createFromMethodName or createFromObjAndMethodName, the tool becomes available in the agent gallery UI within your current environment.

To make the tool available in your packaged application so that it persists when the application is deployed to other environments or clusters, see Publish the tool.

Hide Tool Arguments from LLMs

Non-LLM Arguments (also called injected arguments) are tool parameters that, during a tool call, are provided by the system or context but never by the LLM. The LLM does not see these arguments in the tool's schema and cannot modify them.

When to use Non-LLM Arguments

Use Non-LLM Arguments for:

  • API credentials that should not be visible to the LLM.
  • File paths that restrict the LLM to specific directories.
  • Database connections that require secure injection.
  • Rate limits or configuration values that control tool behavior.
  • Non-primitive types such as Python sets, C3 types, or pandas DataFrames.

Supported primitive types

The following primitive types are supported directly in the args schema and can be passed by the LLM:

  • string
  • int
  • number (float/decimal)
  • boolean
  • datetime
  • json

Non-primitive types

Anything outside of these primitives must be explicitly passed as a non-LLM kwarg using the GenaiCore.Tool.InjectedArg type. This allows you to inject richer objects such as:

  • Native Python types (for example, sets, lists, dicts not covered by JSON).
  • C3 types (for example, c3.File, custom entity types).
  • Pandas DataFrame (without a default value, using noDefaults=True).

Mark Arguments as Non-LLM Arguments for a Tool

Use the updateNonLlmKwargs method to mark specific tool arguments as non-LLM kwargs. Each injected argument is defined using GenaiCore.Tool.InjectedArg.

For Native Python tools:

Python
# Create a tool with multiple arguments
subtract_src = '''
def subtract(a: int, b: int) -> int:
    """Subtract b from a."""
    return a - b
'''

subtract_tool = c3.GenaiCore.Tool.NativePy.createFromPySrc(
    pySrc=subtract_src,
    toolName="subtract",
    actionRequirement="py-llm_312"
)

# Mark 'b' as a non-LLM argument with a default value of 10
subtract_tool = subtract_tool.updateNonLlmKwargs([
    c3.GenaiCore.Tool.InjectedArg(name="b", defaultValue=10)
])

# Now the LLM only sees 'a' in the args schema
# When calling with just 'a', 'b' defaults to 10
result = subtract_tool.call(a=5)  # Returns -5 (5 - 10)

# You can still override the non-LLM argument manually
result = subtract_tool.call(a=5, b=3)  # Returns 2 (5 - 3)

For C3 method tools:

Python
# Mark 'b' as a non-LLM argument in a C3 method tool
c3_multiply_tool = c3.GenaiCore.Tool.C3Method.createFromMethodName(
    type=c3.MyMathUtils,
    methodName="multiply"
)

c3_multiply_tool = c3_multiply_tool.updateNonLlmKwargs([
    c3.GenaiCore.Tool.InjectedArg(name="b", defaultValue=5.0)
])

# The LLM only provides 'a', and 'b' is automatically injected
result = c3_multiply_tool.call(a=3.0)  # Returns 15.0 (3.0 * 5.0)

Use Non-LLM Arguments with non-primitive types

Use GenaiCore.Tool.InjectedArg to inject non-primitive types:

Python
# Example: Tool that works with C3 types and native Python sets
word_set_arg = c3.GenaiCore.Tool.InjectedArg(
    name="wordSet",
    defaultValue={1, 2, 3, 4}  # Python set
)

test_file = c3.File(url="test_file")
test_file.writeString("hello")
file_arg = c3.GenaiCore.Tool.InjectedArg(
    name="file",
    defaultValue=test_file  # C3 File type
)

# Create spec with non-LLM kwargs
spec = c3.GenaiCore.Tool.C3Method.Spec(nonLlmKwargs=[word_set_arg, file_arg])

# Create tool with the spec
tool = c3.GenaiCore.Tool.C3Method.createFromMethodName(
    type=test_type,
    methodName="checkContentInSet",
    spec=spec
)

Configure arguments without default values

If an argument should be injected but you do not want to provide a default value, set noDefaults=True:

Python
# For a pandas DataFrame that doesn't have a default
data_frame_arg = c3.GenaiCore.Tool.InjectedArg(
    name="data_frame",
    noDefaults=True
)

spec = c3.GenaiCore.Tool.NativePy.Spec(nonLlmKwargs=[data_frame_arg])

Required non-LLM Arguments

If a non-LLM argument is marked as required in the tool's function signature, you must provide a default value. The system will raise an error if a required argument is marked as non-LLM without a default value:

Python
# Correct approach: provide a default value for required arguments
tool.updateNonLlmKwargs([
    c3.GenaiCore.Tool.InjectedArg(name="a", defaultValue=100)
])

How Non-LLM Arguments work with agents

When a tool with non-LLM arguments is used in an agent:

  1. The LLM only sees the filtered args schema (non-LLM arguments are excluded).
  2. The agent can override non-LLM argument values through nonLlmToolKwargs configuration.
  3. Default values are used if no override is provided.
  4. The tool receives both LLM-provided arguments and injected arguments during execution.

Publish the tool

When you create a tool using createFromPySrc, createFromMethodName, or createFromObjAndMethodName, it exists only in your current environment. To make the tool available after your application is packaged and deployed to other environments, call publish().

Python
<your_tool> = <your_tool>.publish()

After publishing, the tool appears under Tools. Navigate to Agents > Gallery > Tools to view and manage all available tools in your environment.

See also

Was this page helpful?