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)
}
}tessl i tessl/maven-com-embabel-agent--embabel-agent-starter@0.3.1docs