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 all agent framework annotations.
Primary annotation for defining an agent.
package com.embabel.agent.api.annotation
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
@Component
annotation class Agent(
val name: String = "",
val provider: String = "",
val description: String,
val version: String = DEFAULT_VERSION,
val planner: PlannerType = PlannerType.GOAP,
val scan: Boolean = true,
val beanName: String = "",
val opaque: Boolean = false,
val actionRetryPolicy: ActionRetryPolicy = ActionRetryPolicy.DEFAULT,
val actionRetryPolicyExpression: String = ""
)Attributes:
name: String - Agent name (default: class simple name)provider: String - Provider namespace (default: empty)description: String - Required agent purpose descriptionversion: String - Agent version (default: DEFAULT_VERSION)planner: PlannerType - Planning algorithm (default: PlannerType.GOAP)scan: Boolean - Enable classpath scanning (default: true)beanName: String - Override Spring bean name (default: auto-generated)opaque: Boolean - Hide internal actions/conditions (default: false)actionRetryPolicy: ActionRetryPolicy - Default retry strategy (default: ActionRetryPolicy.DEFAULT)actionRetryPolicyExpression: String - Property expression for retry config (default: empty)Usage:
@Agent(
description = "Customer support agent",
provider = "customer-service",
version = "1.0.0",
planner = PlannerType.GOAP,
scan = true
)
public class CustomerSupportAgent { }@Agent(
description = "Data processing agent",
provider = "data-platform",
version = "2.1.0",
planner = PlannerType.GOAP,
opaque = false
)
class DataProcessingAgent { }Marks a class that exposes agent capabilities without being an agent itself.
package com.embabel.agent.api.annotation
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
@Component
annotation class EmbabelComponent(
val scan: Boolean = true
)Attributes:
scan: Boolean - Enable method scanning (default: true)Usage:
@EmbabelComponent(scan = true)
public class FileOperations {
@Action(description = "Read file contents")
public String readFile(String path) {
return Files.readString(Path.of(path));
}
}@EmbabelComponent(scan = true)
class DatabaseOperations {
@Action(description = "Query database records")
fun query(sql: String): List<Record> {
return executeQuery(sql)
}
}Defines an action that an agent can perform.
package com.embabel.agent.api.annotation
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
annotation class Action(
val description: String,
val pre: Array<String> = [],
val post: Array<String> = [],
val canRerun: Boolean = true,
val clearBlackboard: Boolean = false,
val outputBinding: String = "",
val cost: Double = 0.0,
val value: Double = 0.0,
val costMethod: String = "",
val valueMethod: String = "",
val toolGroups: Array<String> = [],
val toolGroupRequirements: Array<String> = [],
val trigger: KClass<*> = Nothing::class,
val actionRetryPolicy: ActionRetryPolicy = ActionRetryPolicy.DEFAULT,
val actionRetryPolicyExpression: String = ""
)Attributes:
description: String - Required action descriptionpre: Array<String> - Preconditions (default: empty)post: Array<String> - Postconditions (default: empty)canRerun: Boolean - Allow multiple executions (default: true)clearBlackboard: Boolean - Clear blackboard after execution (default: false)outputBinding: String - Blackboard variable binding (default: empty)cost: Double - Static execution cost (default: 0.0)value: Double - Static execution value (default: 0.0)costMethod: String - Dynamic cost method name (default: empty)valueMethod: String - Dynamic value method name (default: empty)toolGroups: Array<String> - Tool groups provided (default: empty)toolGroupRequirements: Array<String> - Tool groups required (default: empty)trigger: KClass<*> - Triggering type (default: Nothing)actionRetryPolicy: ActionRetryPolicy - Retry strategy (default: DEFAULT)actionRetryPolicyExpression: String - Retry config expression (default: empty)Usage:
@Action(
description = "Fetch task from database",
post = {"taskLoaded"},
outputBinding = "task",
cost = 5.0,
value = 10.0
)
public Task fetchTask(String taskId) {
return taskRepository.findById(taskId);
}
@Action(
description = "Process task using LLM",
pre = {"taskLoaded"},
post = {"taskProcessed"},
outputBinding = "result",
cost = 20.0,
value = 50.0,
toolGroups = {"llm-tools"}
)
public ProcessedResult processTask(Task task, Ai ai) {
return ai.process(task);
}@Action(
description = "Validate order data",
post = ["orderValidated"],
cost = 2.0,
value = 15.0
)
fun validateOrder(order: Order): ValidationResult {
return validator.validate(order)
}
@Action(
description = "Calculate shipping cost",
pre = ["orderValidated"],
post = ["shippingCalculated"],
outputBinding = "shippingCost",
costMethod = "calculateCostDynamic"
)
fun calculateShipping(order: Order): Double {
return shippingCalculator.calculate(order)
}Marks a method as a condition check for GOAP planning.
package com.embabel.agent.api.annotation
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
annotation class Condition(
val name: String,
val cost: ZeroToOne = ZeroToOne.ZERO
)Attributes:
name: String - Required unique condition namecost: ZeroToOne - Evaluation cost 0.0-1.0 (default: 0.0)Usage:
@Condition(name = "hasStock", cost = ZeroToOne.of(0.1))
public boolean hasStock(String productId) {
return inventory.getStock(productId) > 0;
}
@Condition(name = "lowStock", cost = ZeroToOne.of(0.1))
public boolean isLowStock(String productId) {
return inventory.getStock(productId) < THRESHOLD;
}
@Action(description = "Reorder product", pre = {"lowStock"})
public void reorderProduct(String productId) {
supplier.placeOrder(productId);
}@Condition(name = "userAuthenticated", cost = ZeroToOne.of(0.05))
fun isAuthenticated(userId: String): Boolean {
return authService.isAuthenticated(userId)
}
@Condition(name = "hasPermission", cost = ZeroToOne.of(0.15))
fun hasPermission(userId: String, resource: String): Boolean {
return authService.checkPermission(userId, resource)
}Marks a method as cost/value computation for dynamic planning.
package com.embabel.agent.api.annotation
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
annotation class Cost(
val name: String
)Attributes:
name: String - Required unique computation method nameUsage:
@Action(
description = "Allocate compute resources",
costMethod = "computeAllocationCost",
valueMethod = "computeAllocationValue"
)
public Allocation allocateResources(Request request) {
return allocator.allocate(request);
}
@Cost(name = "computeAllocationCost")
public double computeAllocationCost(Request request) {
double systemLoad = monitor.getCurrentLoad();
return request.getResourceCount() * systemLoad * 10.0;
}
@Cost(name = "computeAllocationValue")
public double computeAllocationValue(Request request) {
return request.getPriority() * 100.0;
}@Action(
description = "Cache data item",
costMethod = "cachingCost"
)
fun cacheItem(key: String, value: Any): Unit {
cache.put(key, value)
}
@Cost(name = "cachingCost")
fun cachingCost(key: String, value: Any): Double {
val size = estimateSize(value)
val availableMemory = cache.getAvailableMemory()
return if (size > availableMemory) 100.0 else 1.0
}Marks a parameter as platform-provided (not from blackboard).
package com.embabel.agent.api.annotation
@Target(AnnotationTarget.VALUE_PARAMETER)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
annotation class ProvidedUsage:
@Action(description = "Generate article content")
public Article generateContent(
String topic,
@Provided Ai ai,
@Provided ActionContext context
) {
context.updateProgress("Generating content for: " + topic);
return ai.withLlm(OpenAiModels.GPT_4_TURBO)
.createObject("Write an article about: " + topic);
}@Action(description = "Analyze data with LLM")
fun analyzeData(
data: Dataset,
@Provided ai: Ai,
@Provided context: ActionContext
): Analysis {
context.sendMessage("Analyzing dataset: ${data.name}")
return ai.createObject("Analyze this data: ${data.summary}")
}Exposes a method as an LLM-callable tool.
package com.embabel.agent.api.annotation
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
annotation class LlmTool(
val description: String,
val name: String = "",
val returnDirect: Boolean = false,
val category: String = ""
)Attributes:
description: String - Required tool description (shown to LLM)name: String - Override tool name (default: method name)returnDirect: Boolean - Skip LLM processing (default: false)category: String - Category for MatryoshkaTools (default: empty)Usage:
@LlmTool(
description = "Read the contents of a file from the filesystem",
name = "read_file"
)
public String readFile(
@LlmTool.Param(description = "Path to the file to read", required = true)
String filePath
) {
return Files.readString(Path.of(filePath));
}
@LlmTool(
description = "Write content to a file on the filesystem",
name = "write_file"
)
public void writeFile(
@LlmTool.Param(description = "Path to the file to write", required = true)
String filePath,
@LlmTool.Param(description = "Content to write to the file", required = true)
String content
) {
Files.writeString(Path.of(filePath), content);
}@LlmTool(
description = "Execute a SQL query and return results",
name = "sql_query"
)
fun executeQuery(
@LlmTool.Param(description = "SQL query to execute", required = true)
query: String
): List<Map<String, Any>> {
return database.execute(query)
}
@LlmTool(
description = "Get database schema information",
name = "get_schema",
returnDirect = true
)
fun getSchema(): String {
return database.describeSchema()
}Nested annotation for documenting LLM tool parameters.
package com.embabel.agent.api.annotation
@Target(AnnotationTarget.VALUE_PARAMETER)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
annotation class Param(
val description: String,
val required: Boolean = true
)Attributes:
description: String - Required parameter description (shown to LLM)required: Boolean - Parameter required flag (default: true)Marks a method as providing a tool group.
package com.embabel.agent.api.annotation
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
annotation class ToolGroup(
val role: String
)Attributes:
role: String - Required tool group role/nameUsage:
@ToolGroup(role = "data-analysis")
public List<Tool> getAnalysisTools() {
return List.of(
Tool.create("calculate_statistics", this::calculateStats),
Tool.create("generate_chart", this::generateChart),
Tool.create("find_correlations", this::findCorrelations)
);
}@ToolGroup(role = "web-scraping")
fun getWebTools(): List<Tool> {
return listOf(
Tool.create("fetch_url", ::fetchUrl),
Tool.create("parse_html", ::parseHtml),
Tool.create("extract_links", ::extractLinks)
)
}Creates a progressive disclosure tool facade.
package com.embabel.agent.api.annotation
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
annotation class MatryoshkaTools(
val name: String,
val description: String,
val removeOnInvoke: Boolean = true,
val categoryParameter: String = "category"
)Attributes:
name: String - Required facade tool namedescription: String - Required facade tool description (shown to LLM)removeOnInvoke: Boolean - Remove facade after first invocation (default: true)categoryParameter: String - Category selection parameter name (default: "category")Usage:
@EmbabelComponent
@MatryoshkaTools(
name = "data_operations",
description = "Choose a category of data operations: read, write, or analyze",
removeOnInvoke = true
)
public class DataOperationsTools {
@LlmTool(description = "Read data from a source", category = "read")
public String readData(@LlmTool.Param(description = "Source path") String path) {
return dataService.read(path);
}
@LlmTool(description = "Write data to a destination", category = "write")
public void writeData(
@LlmTool.Param(description = "Destination path") String path,
@LlmTool.Param(description = "Data to write") String data
) {
dataService.write(path, data);
}
@LlmTool(description = "Analyze data and generate report", category = "analyze")
public Report analyzeData(@LlmTool.Param(description = "Data source") String path) {
return dataService.analyze(path);
}
}@EmbabelComponent
@MatryoshkaTools(
name = "file_operations",
description = "Select file operation type: basic, advanced, or search",
removeOnInvoke = true
)
class FileOperationsTools {
@LlmTool(description = "List files in directory", category = "basic")
fun listFiles(@LlmTool.Param(description = "Directory path") path: String): List<String> {
return fileService.list(path)
}
@LlmTool(description = "Copy file with options", category = "advanced")
fun copyFile(
@LlmTool.Param(description = "Source path") source: String,
@LlmTool.Param(description = "Destination path") dest: String
) {
fileService.copy(source, dest)
}
@LlmTool(description = "Search files by pattern", category = "search")
fun searchFiles(@LlmTool.Param(description = "Search pattern") pattern: String): List<String> {
return fileService.search(pattern)
}
}Marks an action as achieving a specific goal.
package com.embabel.agent.api.annotation;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AchievesGoal {
String description();
double value() default 0.0;
String[] tags() default {};
String[] examples() default {};
Export export() default @Export;
}Attributes:
description(): String - Required goal descriptionvalue(): double - Numeric goal value (default: 0.0)tags(): String[] - Capability tags (default: empty)examples(): String[] - Example scenarios (default: empty)export(): @Export - Export configuration (default: @Export defaults)Usage:
@AchievesGoal(
description = "Generate a summary report from analyzed data",
value = 1.0,
tags = {"reporting", "summarization"},
examples = {
"Summarize sales data for Q4",
"Generate monthly performance report"
},
export = @Export(remote = true, local = true)
)
public Report generateSummaryReport(AnalyzedData data) {
return new Report();
}@AchievesGoal(
description = "Process user request and generate response",
tags = ["processing", "generation"],
export = Export(remote = true, local = true)
)
fun processRequest(input: UserInput): Result {
return Result()
}Nested annotation for configuring goal export.
package com.embabel.agent.api.annotation;
public @interface Export {
String name() default "";
boolean remote() default false;
boolean local() default true;
Class<?>[] startingInputTypes() default {};
}Attributes:
name(): String - Override export name (default: empty, uses method name)remote(): boolean - Expose remotely (e.g., MCP, A2A) (default: false)local(): boolean - Expose locally within platform (default: true)startingInputTypes(): Class<?>[] - Starting input types (default: empty)Usage:
@AchievesGoal(
description = "Internal processing step",
export = @Export(local = true, remote = false)
)
public InternalResult processInternal(Data data) { }
@AchievesGoal(
description = "Publicly accessible API endpoint",
export = @Export(
name = "processUserQuery",
remote = true,
local = true,
startingInputTypes = {String.class, UserQuery.class}
)
)
public Response processQuery(UserQuery query) { }Utility class for simplified HITL operations (Java syntax sugar).
package com.embabel.agent.api.annotation;
public class WaitFor {
public static <T> FormBindingRequest<T> formSubmission(String title, Class<T> clazz);
public static <P> ConfirmationRequest<P> confirmation(P what, String description);
public static <P> Awaitable<P, ?> awaitable(Awaitable<P, ?> awaitable);
}Methods:
public static <T> FormBindingRequest<T> formSubmission(String title, Class<T> clazz)Parameters:
title: String - Form title shown to userclazz: Class<T> - Class type for form data bindingReturns: FormBindingRequest<T> - Request object that can be awaited
Usage:
public class UserDetails {
private String name;
private String email;
private int age;
}
FormBindingRequest<UserDetails> request =
WaitFor.formSubmission("Enter Your Details", UserDetails.class);
UserDetails details = request.await();public static <P> ConfirmationRequest<P> confirmation(P what, String description)Parameters:
what: P - Object requiring confirmationdescription: String - Description shown to userReturns: ConfirmationRequest<P> - Request object that can be awaited
Usage:
DeleteAction action = new DeleteAction(resource);
ConfirmationRequest<DeleteAction> request =
WaitFor.confirmation(action, "Delete this resource permanently?");
boolean confirmed = request.await();
if (confirmed) {
action.execute();
}public static <P> Awaitable<P, ?> awaitable(Awaitable<P, ?> awaitable)Parameters:
awaitable: Awaitable<P, ?> - Custom awaitable implementationReturns: Awaitable<P, ?> - Wrapped awaitable
Usage:
Awaitable<CustomResult, ?> customAwaitable = createCustomAwaitable();
Awaitable<CustomResult, ?> wrapped = WaitFor.awaitable(customAwaitable);
CustomResult result = wrapped.await();Deprecated since 0.3.1 - Use application.properties or application.yml instead.
package com.embabel.agent.config.annotation
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface EnableAgents {
String loggingTheme() default "";
String[] mcpServers() default {};
}Attributes:
loggingTheme: String - Logging personality theme (default: empty)
mcpServers: String[] - Deprecated MCP servers to enable (default: empty)Alternative (application.yml):
embabel:
agent:
logging:
personality: starwarstessl i tessl/maven-com-embabel-agent--embabel-agent-starter@0.3.1docs