Skip to main content

Custom Tools

Tools are packaged as Plugins. A Plugin acts as a container that can include multiple individual tools, their logic, and their external dependencies. In the portal interface, an uploaded plugin is referred to as a Tool Group.

For system tools and how to add them, see System Tools List


Prerequisites

  • Basic understanding of AI agents
  • Familiarity with YAML configuration
  • Python programming knowledge for custom tool implementation
  • Access to the Flametree portal for plugin management

How to Create Custom Tool

To create custom tool, follow these steps:

  1. Create tool configuration and implementation – Define the tool in YAML (describe its purpose and required inputs) and implement the business logic in Python that executes the function and returns the result.
  2. Upload Plugin to the portal
  3. Add tools to workflow in appropriate states
  4. Test in Playground before production

Tip: Pay attention to the examples of ready-made custom tools

Create Tool Configuration and Implementation

Before you begin, review the recommended file structure for a custom tool:

my_crm_plugin/
├── crm_integration.yaml # Tool configuration
├── requirements.txt # External Python dependencies
└── submodules/ # Folder for your Python code
└── crm_logic.py # Implementation logic

Tool Configuration (YAML)

The YAML file defines the interface for the AI agent. It tells the agent what the tool does and what parameters it needs.

Example crm_integration.yaml:

kind: Plugin
name: CRM Integration Plugin
description: Tools for posting leads to external CRM
dependencies:
- submodules/crm_logic.py
- requirements.txt # If you have a requirements.txt, the system installs packages automatically
tools:
- kind: Tool
object_name: PostLeadToCRM
name: post_lead
description: Sends client contact details to the corporate CRM system. Use this when the user confirms their contact info.
implementation: crm_logic.post_lead
parameters:
- name: client_name
type: string
description: Name of the client
- name: client_email
type: string
description: Email of the client

See the Reference: Tool Configuration Fields section below for a complete description of all required and optional YAML fields.

External Dependencies

If your tool uses external libraries such as pytz, pandas, and others, list them in the requirements.txt file and specify their versions.

pytz==2024.1
aiohttp==3.9.3

Tool Implementation (Python)

A tool implementation is an async Python function. The system maps the YAML parameters directly to the function arguments.

from loguru import logger

async def create_ticket(issue_summary: str, issue_details: str, **kwargs):
"""
Implementation logic for CreateSupportTicket.
YAML parameters (issue_summary, issue_details) are passed as direct arguments.
System state is passed via **kwargs.
"""
# 1. Log the action
logger.info(f"Processing ticket: {issue_summary}")

# 2. Execute business logic (e.g., API call)
ticket_id = "TICKET-123"

# 3. Return a string to the Agent
return f"Support ticket created successfully with ID: {ticket_id}"

The function must:

  • Use async def
  • Accept parameters that match the YAML definition.
  • Include **kwargs to receive system-provided arguments
  • Return a string that describes the result. The agent uses this value to continue the conversation.

⚠️ Note: A tool can also return a structured object. This allows you to send a system message directly to the user instead of continuing the agent flow.

The system automatically injects standard arguments into **kwargs at runtime. These provide access to the session state, conversation history, and more. See the Reference: Standard Arguments section below for the complete list.

Troubleshooting

If the agent calls the tool but it fails or does not behave as expected:

  1. Check the Python implementation for syntax or runtime errors.
  2. Verify that all required parameters are defined in the YAML configuration.
  3. Ensure the implementation function is declared using async def.
  4. Review agent logs for detailed error messages.

Best Practices

Writing Tool Descriptions

Do’s ✅Don’ts ❌
- Describe what the tool does, not when to use it
- Be specific about the tool's action
- Use clear, simple language
- Include usage instructions in the description
- Make descriptions too long or complex

💡 Tip: Tool parameters are strictly validated based on their YAML definition. Clear and accurate parameter descriptions help the agent call tools correctly.

Good Example:

description: Creates a support ticket in Jira with the provided issue details

Not So Good Example:

description: Use this when customer has a problem and needs help. This tool will create a ticket but only if the issue is serious enough.

When to Use Tools Instructions

Put instructions about when to use tools in the workflow state description, not in the tool description:

description: |
## Tool Usage Guidelines
- Use CreateTicket only after confirming the issue with the customer
- Always get customer contact information before creating a ticket

Naming Conventions

  • object_name: PascalCase, no spaces. For example, SendEmailTemplate
  • name: Same as object_name for consistency
  • Parameters: lowercase with underscores. For example, customer_email

Design Principles

  1. Separate logic and actions — use skills for logic, tools for concrete actions
  2. Describe only what the tool does — usage conditions go in the workflow
  3. Design tools and skills as reusable components
  4. Avoid duplicate object_name values — they will cause conflicts

Handling Similar Tools

When you have similar tools, for example, Get Active Cards vs Get Inactive Cards:

  • Keep descriptions similar in structure
  • Clearly highlight the key difference
  • Maintain consistent parameter naming

Reference: Tool Configuration Fields

Each tool definition in the YAML file requires the following fields:

Required Fields

FieldDescription
kindMust be set to Tool
object_nameUnique identifier for the tool. Use PascalCase and no spaces
nameName the agent uses to invoke the tool
descriptionClear description of what the tool does
parametersList of input parameters. Use an empty list ([]) if the tool takes no input
implementationFully qualified reference to the Python function that implements the tool

Parameter Fields

FieldDescription
nameParameter identifier
typeData type (string, integer, boolean, and others.)
descriptionClear description of the expected value
optionalIndicates whether the parameter is optional. Defaults to false

How to define and receive tool parameters:

If a tool requires input ,for example, an email address, ID, or date, define each parameter in the parameters list.

parameters:  
- name: email
type: string
description: "Email address to send the notification to"
- name: customer_name
type: string
description: "Customer name"

💡 Tip: All YAML parameters are automatically passed to the Python function as named arguments (**kwargs).

Reference: Standard Arguments

These standard keyword arguments are injected at runtime into every tool's kwargs. They allow you to control the session, access memory, and read configuration.

ArgumentPurposeType
agent_nameIdentifies which agent triggered the toolstr
raw_agent_answerOriginal JSON string of tool arguments before parsingstr
stackAgent's local stack — used to push result containers that control flow (send message, finish, interrupt)Stack
heapSession-scoped shared dictionary for storing and reading arbitrary datadict
scratchpadAgent's working memory — records of thoughts, observations, and messagesScratchpadBridge or ScratchpadMemory
conversation_memoryFull chat history between the user and the systemRecordsMemory
system_parametersRuntime session parameters (e.g. client_id)dict
environment_jsonJSON-encoded string of environment configurationstr
flags_configSession lifecycle flags (first run, ended, interrupt behavior)FlagsConfig
flow_configComplete flow configuration object — the most powerful entry point, contains references to all session-level objectsFlowConfig
agent_configConfiguration of the calling agent (prompt template, available tools, speech settings)AgentConfig
available_skills_dictDictionary of all loaded skills keyed by namedict[str, Skill]
knowledge_vdbFAISS-backed knowledge base for document searchKnowledgeVDB
tools_vdbFAISS-backed tool index for semantic tool search (non-None only for search_tool)ToolsVDB | None
automatic_operationWhether the agent is running in automatic mode (no human in the loop)bool
tool_call_idLLM-assigned identifier for this tool call (tool-calling agents only)str
tool_call_typeType field from the LLM tool call (tool-calling agents only)str

Note on tool-calling vs traditional agents: The arguments tool_call_id and tool_call_type are available only when the tool is invoked by a BaseAgentToolCalling subclass. They are not passed by BaseAgent subclasses.

Argument Details

agent_name

Identifies which agent triggered the tool.

Example: StatefulToolCallingAgent, SingleStatefulOutboundAgent

In tool-calling mode the calling agent is typically StatefulToolCallingAgent. In traditional mode it is SingleStatefulOutboundAgent. Form-related tools may also be called from FormToolCallingAgent or SingleFormAgent.

raw_agent_answer

The original JSON string of tool arguments exactly as generated by the LLM, before parsing.

Example: '{"message": "Hello!", "currency": "EUR"}'

By the time implementation() runs, the system has already parsed this JSON into individual keyword arguments. In most cases, you do not need to use this value directly.

Use it for:

  • Debugging
  • Logging raw LLM output
  • Inspecting malformed arguments

stack

The agent’s execution stack. This is a list-like asynchronous data structure used to push containers that control conversation flow.

Use stack to:

  • Send a message to the user
  • End the agent loop
  • Interrupt processing
  • Trigger state transitions

This is the primary mechanism for a tool to influence flow behavior.

Example:

from src.utils.containers import AskUserContainer

await stack.push(AskUserContainer("CasualAnswer", "Here is your balance: 1500 EUR"))

Common container types to push:

ContainerEffect
AskUserContainer("CasualAnswer", text)Send a message to the user and wait for response
FinalAnswerContainer(...)Send a final answer and stop the execution
InterruptProcessContainer(...)Interrupt the current process
ProceedContainer(...)Delegate the task downstream
StateContainer(...)Trigger a state transition

heap

A session-scoped shared dictionary that persists for the lifetime of the session.

Any tool can read from or write to heap. Use it for inter-tool or inter-agent communication within the same session.

Use heap for:

  • Temporary shared state
  • Cross-tool coordination
  • Passing values between workflow steps

Example:

# Store data for later use by another tool or agent
heap["last_transfer_id"] = "TXN-12345"

# Read the state machine
statemachine = heap.get("statemachine")

scratchpad

The agent's working memory that stores the sequence of messages (AI messages, tool results, human messages) forming the agent's reasoning context.

In most cases tools do not need to touch the scratchpad directly. Returning a string from implementation() automatically creates an Observation. Use scratchpad only when you need custom multi-record updates or direct message manipulation.

Access the scratchpad only if you need:

  • Custom multi-record updates
  • Direct manipulation of reasoning messages
  • Advanced control over agent memory behavior

conversation_memory

The complete chat history between the user and the system, stored as a RecordsMemory instance.

While the scratchpad contains reasoning records, conversation_memory stores the actual user–system dialogue.

Use it when you need access to:

  • Full message history
  • Prior user inputs
  • Context outside the current reasoning step

Example:

records = conversation_memory.get_records()             # list[str] of recent messages
formatted = conversation_memory.get_formatted_memory() # single formatted string

system_parameters

Runtime parameters for the current session. Typically includes client identifiers and session metadata.

Use this argument to access:

  • Client identifiers
  • Session identifiers
  • Other runtime metadata

Example:

client_id = system_parameters.get("client_id")
session_id = system_parameters.get("session_id")

environment_json

A JSON-encoded string that contains environment configuration parameters.

These values correspond to flow_config.environment_parameters, but are pre-serialized.

Use this argument if you need raw JSON instead of the parsed dictionary.

flags_config

Session lifecycle flags that indicate the current state of the session.

Fields:

FieldTypeDefaultDescription
interrupt_at_final_answerboolTrueWhether the agent loop should stop when a FinalAnswerContainer is pushed
first_runboolTrueTrue during the first run of the session (before the first user message is processed)
is_session_endedboolFalseTrue if the session has been explicitly ended

Example:

if flags_config.first_run:
return "Welcome! This is your first interaction."

Use flags_config to implement conditional logic based on session lifecycle state.

flow_config

The complete flow configuration object. This is the most powerful argument available to tools.

It provides access to nearly all session-level components.

Key Fields:

FieldTypeDescription
global_heapdictSession-scoped shared data (same object as the heap argument)
global_continuous_heapdictPersistent across session resets; contains "_session_id"
conversation_memoryRecordsMemoryChat history (same object as the conversation_memory argument)
environment_parametersdictEnvironment config (parsed version of environment_json)
system_parametersdictRuntime params (same object as the system_parameters argument)
flags_configFlagsConfigSame object as the flags_config argument
global_event_managerBaseEventManagerPub/sub event system
current_stateStateConfig | NoneCurrent state machine state
form_infolist[FormInfoField] | NoneForm field definitions

Example — accessing session ID:

session_id = flow_config.global_continuous_heap.get("_session_id")

Use flow_config only when you need cross-cutting access to multiple session-level objects.

agent_config

Configuration of the calling agent. The values are potentially overridden by the current state machine state.

Includes:

  • name
  • available_tools
  • prompt_template
  • Speech or output settings

available_skills_dict

A dictionary of loaded skill instances, keyed by skill name.

Primarily used by internal tools such as SearchTool.

knowledge_vdb

Vector database for searching knowledge connected to your agent.

Example:

docs = knowledge_vdb.get_relevant_documents(query="What are the transfer fees?", k=5)
for doc in docs:
print(doc.page_content, doc.metadata)

Use this argument to perform semantic document retrieval.

tools_vdb

Vector database indexing tool descriptions for semantic tool search. This is set to a non-None value only when the tool being called is search_tool.

automatic_operation

Indicates whether the agent runs in automatic mode.

  • True — no human is in the loop
  • False — human interaction is expected

Use this flag when tool behavior must differ between automated and interactive execution.

tool_call_id and tool_call_type

Identifier and type fields from the LLM’s structured tool call response.

These arguments are available only in tool-calling mode.

They are primarily used internally to associate tool responses with the corresponding LLM call.