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:
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
'''Add an initialization function if the tool requires one-time setup, such as loading models or establishing connections.
Create and persist the tool instance:
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:
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:
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:
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:
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:
stringintnumber(float/decimal)booleandatetimejson
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:
# 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:
# 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:
# 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:
# 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:
# 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:
- The LLM only sees the filtered args schema (non-LLM arguments are excluded).
- The agent can override non-LLM argument values through
nonLlmToolKwargsconfiguration. - Default values are used if no override is provided.
- 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().
<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.