Base starter module for the Embabel Agent Framework providing core dependencies for building agentic flows on the JVM with Spring Boot integration and GOAP-based intelligent path finding.
—
Complete API reference for creating, managing, and using tools in agent execution.
Base interface for all tools with factory methods for programmatic creation.
package com.embabel.agent.api
interface Tool {
companion object {
fun create(name: String, function: Function<*, *>): Tool
fun create(name: String, description: String, function: Function<*, *>): Tool
fun fromMethod(method: Method): Tool
fun fromMethod(instance: Any, method: Method): Tool
}
fun getName(): String
fun getDescription(): String
fun getParameters(): List<ToolParameter>
fun execute(arguments: Map<String, Any>): Any
}Factory Methods:
create(name: String, function: Function<*, *>): Tool - Create tool with name and functioncreate(name: String, description: String, function: Function<*, *>): Tool - Create tool with name, description, and functionfromMethod(method: Method): Tool - Create tool from methodfromMethod(instance: Any, method: Method): Tool - Create tool from instance methodMethods:
getName(): String - Get tool namegetDescription(): String - Get tool descriptiongetParameters(): List<ToolParameter> - Get parameter definitionsexecute(arguments: Map<String, Any>): Any - Execute tool with argumentsUsage:
@EmbabelComponent
public class CalculatorTools {
public List<Tool> createCalculatorTools() {
return List.of(
Tool.create("add", "Add two numbers", (args) -> {
double a = (Double) args.get("a");
double b = (Double) args.get("b");
return a + b;
}),
Tool.create("multiply", "Multiply two numbers", (args) -> {
double a = (Double) args.get("a");
double b = (Double) args.get("b");
return a * b;
}),
Tool.create("divide", "Divide two numbers", (args) -> {
double a = (Double) args.get("a");
double b = (Double) args.get("b");
if (b == 0) throw new IllegalArgumentException("Division by zero");
return a / b;
})
);
}
}@EmbabelComponent
class StringTools {
fun createStringTools(): List<Tool> {
return listOf(
Tool.create("uppercase", "Convert string to uppercase") { args ->
(args["text"] as String).uppercase()
},
Tool.create("lowercase", "Convert string to lowercase") { args ->
(args["text"] as String).lowercase()
},
Tool.create("reverse", "Reverse a string") { args ->
(args["text"] as String).reversed()
},
Tool.create("length", "Get string length") { args ->
(args["text"] as String).length
}
)
}
}Creating from Methods:
import com.embabel.agent.api.Tool;
import java.lang.reflect.Method;
public class ReflectiveToolFactory {
public Tool createToolFromMethod() throws NoSuchMethodException {
Method method = this.getClass().getMethod("processData", String.class);
return Tool.fromMethod(this, method);
}
public String processData(String input) {
return "Processed: " + input;
}
}Progressive disclosure tool facade that reveals specific tools based on category selection.
package com.embabel.agent.api
class MatryoshkaTool : Tool {
companion object {
fun fromInstance(instance: Any): MatryoshkaTool
}
fun selectCategory(category: String): List<Tool>
fun getCategories(): List<String>
}Factory Methods:
fromInstance(instance: Any): MatryoshkaTool - Create from annotated class instanceMethods:
selectCategory(category: String): List<Tool> - Select tools by categorygetCategories(): List<String> - Get available categoriesUsage:
import com.embabel.agent.api.MatryoshkaTool;
import com.embabel.agent.api.annotation.MatryoshkaTools;
import com.embabel.agent.api.annotation.LlmTool;
@EmbabelComponent
@MatryoshkaTools(
name = "database_operations",
description = "Database tools - select category: query, insert, update, or delete"
)
public class DatabaseTools {
public static MatryoshkaTool createDatabaseTool() {
return MatryoshkaTool.fromInstance(new DatabaseTools());
}
@LlmTool(description = "Execute SELECT query", category = "query")
public List<Map<String, Object>> select(
@LlmTool.Param(description = "SQL SELECT statement") String sql
) {
return database.executeQuery(sql);
}
@LlmTool(description = "Insert new record", category = "insert")
public int insert(
@LlmTool.Param(description = "Table name") String table,
@LlmTool.Param(description = "Record data") Map<String, Object> data
) {
return database.insert(table, data);
}
@LlmTool(description = "Update existing record", category = "update")
public int update(
@LlmTool.Param(description = "Table name") String table,
@LlmTool.Param(description = "WHERE clause") String where,
@LlmTool.Param(description = "Updated data") Map<String, Object> data
) {
return database.update(table, where, data);
}
@LlmTool(description = "Delete record", category = "delete")
public int delete(
@LlmTool.Param(description = "Table name") String table,
@LlmTool.Param(description = "WHERE clause") String where
) {
return database.delete(table, where);
}
}import com.embabel.agent.api.MatryoshkaTool
import com.embabel.agent.api.annotation.MatryoshkaTools
import com.embabel.agent.api.annotation.LlmTool
@EmbabelComponent
@MatryoshkaTools(
name = "file_system",
description = "File system tools - choose: read, write, or manage"
)
class FileSystemTools {
companion object {
fun createFileSystemTool(): MatryoshkaTool {
return MatryoshkaTool.fromInstance(FileSystemTools())
}
}
@LlmTool(description = "Read file contents", category = "read")
fun readFile(@LlmTool.Param(description = "File path") path: String): String {
return fileService.read(path)
}
@LlmTool(description = "List directory contents", category = "read")
fun listDirectory(@LlmTool.Param(description = "Directory path") path: String): List<String> {
return fileService.list(path)
}
@LlmTool(description = "Write file", category = "write")
fun writeFile(
@LlmTool.Param(description = "File path") path: String,
@LlmTool.Param(description = "Content") content: String
) {
fileService.write(path, content)
}
@LlmTool(description = "Delete file", category = "manage")
fun deleteFile(@LlmTool.Param(description = "File path") path: String) {
fileService.delete(path)
}
@LlmTool(description = "Move file", category = "manage")
fun moveFile(
@LlmTool.Param(description = "Source path") source: String,
@LlmTool.Param(description = "Destination path") dest: String
) {
fileService.move(source, dest)
}
}Tools that wrap agent invocations and expose them as callable functions.
package com.embabel.agent.api
class AgenticTool : Tool {
companion object {
fun fromAgent(agent: Agent): AgenticTool
fun fromAgent(agentClass: Class<*>): AgenticTool
fun fromAgent(agentName: String): AgenticTool
}
fun invokeAgent(arguments: Map<String, Any>): Any
}Factory Methods:
fromAgent(agent: Agent): AgenticTool - Create from agent instancefromAgent(agentClass: Class<*>): AgenticTool - Create from agent classfromAgent(agentName: String): AgenticTool - Create from agent nameMethods:
invokeAgent(arguments: Map<String, Any>): Any - Invoke wrapped agent with argumentsUsage:
import com.embabel.agent.api.AgenticTool;
@EmbabelComponent
public class AgentToolProvider {
public List<Tool> createAgenticTools() {
return List.of(
AgenticTool.fromAgent(DataAnalyzerAgent.class),
AgenticTool.fromAgent("ReportGeneratorAgent"),
AgenticTool.fromAgent(summarizerAgentInstance)
);
}
@Action(description = "Use agentic tools for complex processing")
public Result processWithAgenticTools(
Input input,
@Provided Ai ai
) {
List<Tool> tools = createAgenticTools();
return ai.withLlm(OpenAiModels.GPT_4_TURBO)
.withTools(tools)
.createObject("Process this input: " + input);
}
}import com.embabel.agent.api.AgenticTool
@EmbabelComponent
class AgentToolProvider {
fun createAgenticTools(): List<Tool> {
return listOf(
AgenticTool.fromAgent(DataAnalyzerAgent::class.java),
AgenticTool.fromAgent("ReportGeneratorAgent"),
AgenticTool.fromAgent(summarizerAgentInstance)
)
}
@Action(description = "Complex processing with agent tools")
fun processWithAgenticTools(
input: Input,
@Provided ai: Ai
): Result {
val tools = createAgenticTools()
return ai.withLlm(OpenAiModels.GPT_4_TURBO)
.withTools(tools)
.createObject("Process: $input")
}
}Organize related tools into groups for modular management and dependency declaration.
Usage:
import com.embabel.agent.api.annotation.ToolGroup;
import com.embabel.agent.api.Tool;
@EmbabelComponent
public class AnalysisToolGroups {
@ToolGroup(role = "statistical-analysis")
public List<Tool> getStatisticalTools() {
return List.of(
Tool.create("mean", "Calculate mean", this::calculateMean),
Tool.create("median", "Calculate median", this::calculateMedian),
Tool.create("std_dev", "Calculate standard deviation", this::calculateStdDev),
Tool.create("correlation", "Calculate correlation", this::calculateCorrelation)
);
}
@ToolGroup(role = "data-visualization")
public List<Tool> getVisualizationTools() {
return List.of(
Tool.create("scatter_plot", "Create scatter plot", this::createScatterPlot),
Tool.create("bar_chart", "Create bar chart", this::createBarChart),
Tool.create("line_chart", "Create line chart", this::createLineChart)
);
}
private double calculateMean(Map<String, Object> args) { /* ... */ }
private double calculateMedian(Map<String, Object> args) { /* ... */ }
private double calculateStdDev(Map<String, Object> args) { /* ... */ }
private double calculateCorrelation(Map<String, Object> args) { /* ... */ }
private String createScatterPlot(Map<String, Object> args) { /* ... */ }
private String createBarChart(Map<String, Object> args) { /* ... */ }
private String createLineChart(Map<String, Object> args) { /* ... */ }
}Actions can require and provide tool groups:
@Agent(description = "Data analyst")
public class DataAnalystAgent {
@Action(
description = "Perform statistical analysis",
toolGroupRequirements = {"statistical-analysis"}
)
public StatisticalReport analyzeData(Dataset data, @Provided Ai ai) {
return ai.createObject("Analyze this dataset: " + data);
}
@Action(
description = "Create visualization",
toolGroupRequirements = {"data-visualization"}
)
public Visualization visualizeData(Dataset data, @Provided Ai ai) {
return ai.createObject("Create a visualization for: " + data);
}
@Action(
description = "Full analysis with charts",
toolGroupRequirements = {"statistical-analysis", "data-visualization"}
)
public FullReport fullAnalysis(Dataset data, @Provided Ai ai) {
return ai.createObject("Perform full analysis with charts: " + data);
}
}Define parameters with types, descriptions, and validation.
package com.embabel.agent.api
data class ToolParameter(
val name: String,
val type: Class<*>,
val description: String,
val required: Boolean = true,
val defaultValue: Any? = null
)Constructor Parameters:
name: String - Parameter nametype: Class<*> - Parameter typedescription: String - Parameter descriptionrequired: Boolean - Required flag (default: true)defaultValue: Any? - Default value (default: null)Usage:
import com.embabel.agent.api.Tool;
import com.embabel.agent.api.ToolParameter;
public class ParameterizedToolFactory {
public Tool createSearchTool() {
List<ToolParameter> parameters = List.of(
new ToolParameter("query", String.class, "Search query", true, null),
new ToolParameter("maxResults", Integer.class, "Maximum results", false, 10),
new ToolParameter("sortBy", String.class, "Sort field", false, "relevance")
);
return Tool.builder()
.name("search")
.description("Search for documents")
.parameters(parameters)
.function(this::performSearch)
.build();
}
private List<Document> performSearch(Map<String, Object> args) {
String query = (String) args.get("query");
int maxResults = (Integer) args.getOrDefault("maxResults", 10);
String sortBy = (String) args.getOrDefault("sortBy", "relevance");
return searchService.search(query, maxResults, sortBy);
}
}import com.embabel.agent.api.*;
import com.embabel.agent.api.annotation.*;
@Agent(description = "Data processing agent with custom tools")
public class DataProcessingAgent {
@Action(
description = "Process data with custom tools",
toolGroups = {"data-tools"}
)
public ProcessedData processData(
RawData data,
@Provided Ai ai,
@Provided ActionContext context
) {
List<Tool> tools = createDataTools();
context.updateProgress("Processing data with " + tools.size() + " tools");
return ai.withLlm(OpenAiModels.GPT_4_TURBO)
.withTools(tools)
.createObject("Process and transform: " + data);
}
@ToolGroup(role = "data-tools")
private List<Tool> createDataTools() {
return List.of(
Tool.create("validate", "Validate data format", this::validateData),
Tool.create("normalize", "Normalize data values", this::normalizeData),
Tool.create("aggregate", "Aggregate data points", this::aggregateData),
MatryoshkaTool.fromInstance(new DataTransformTools()),
AgenticTool.fromAgent(ValidationAgent.class),
AgenticTool.fromAgent("EnrichmentAgent")
);
}
private ValidationResult validateData(Map<String, Object> args) {
RawData data = (RawData) args.get("data");
return validator.validate(data);
}
private NormalizedData normalizeData(Map<String, Object> args) {
RawData data = (RawData) args.get("data");
return normalizer.normalize(data);
}
private AggregatedData aggregateData(Map<String, Object> args) {
RawData data = (RawData) args.get("data");
String method = (String) args.get("method");
return aggregator.aggregate(data, method);
}
}
@MatryoshkaTools(
name = "data_transforms",
description = "Data transformation operations - select: convert, reshape, or filter"
)
class DataTransformTools {
@LlmTool(description = "Convert data format", category = "convert")
public ConvertedData convert(
@LlmTool.Param(description = "Source data") RawData data,
@LlmTool.Param(description = "Target format") String format
) {
return converter.convert(data, format);
}
@LlmTool(description = "Reshape data structure", category = "reshape")
public ReshapedData reshape(
@LlmTool.Param(description = "Source data") RawData data,
@LlmTool.Param(description = "Target shape") String shape
) {
return reshaper.reshape(data, shape);
}
@LlmTool(description = "Filter data by criteria", category = "filter")
public FilteredData filter(
@LlmTool.Param(description = "Source data") RawData data,
@LlmTool.Param(description = "Filter expression") String expression
) {
return filterer.filter(data, expression);
}
}import com.embabel.agent.api.*
import com.embabel.agent.api.annotation.*
@Agent(description = "Analysis agent with tool suite")
class AnalysisAgent {
@Action(
description = "Analyze data with specialized tools",
toolGroups = ["analysis-tools"]
)
fun analyzeData(
data: Dataset,
@Provided ai: Ai,
@Provided context: ActionContext
): AnalysisReport {
val tools = createAnalysisTools()
context.updateProgress("Analyzing with ${tools.size} specialized tools")
return ai.withLlm(GeminiModels.GEMINI_2_5_PRO)
.withTools(tools)
.createObject("Analyze: $data")
}
@ToolGroup(role = "analysis-tools")
fun createAnalysisTools(): List<Tool> {
return listOf(
Tool.create("summarize", "Summarize data", ::summarizeData),
Tool.create("findOutliers", "Find outliers", ::findOutliers),
Tool.create("detectTrends", "Detect trends", ::detectTrends),
MatryoshkaTool.fromInstance(StatisticalTools()),
AgenticTool.fromAgent(DeepAnalysisAgent::class.java)
)
}
private fun summarizeData(args: Map<String, Any>): Summary {
val data = args["data"] as Dataset
return summarizer.summarize(data)
}
private fun findOutliers(args: Map<String, Any>): List<Outlier> {
val data = args["data"] as Dataset
return outlierDetector.detect(data)
}
private fun detectTrends(args: Map<String, Any>): List<Trend> {
val data = args["data"] as Dataset
return trendDetector.detect(data)
}
}Install with Tessl CLI
npx tessl i tessl/maven-com-embabel-agent--embabel-agent-starter@0.3.0docs