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.
Step-by-step guide for creating agents with GOAP planning.
import com.embabel.agent.api.annotation.Agent;
import com.embabel.agent.api.annotation.PlannerType;
import org.springframework.stereotype.Component;
@Agent(
description = "Customer support agent for handling inquiries",
provider = "customer-service",
version = "1.0.0",
planner = PlannerType.GOAP,
scan = true
)
public class CustomerSupportAgent {
// Agent actions and conditions defined here
}import com.embabel.agent.api.annotation.Agent
import com.embabel.agent.api.annotation.PlannerType
import org.springframework.stereotype.Component
@Agent(
description = "Data processing agent for ETL operations",
provider = "data-platform",
version = "2.1.0",
planner = PlannerType.GOAP,
scan = true,
opaque = false
)
class DataProcessingAgent {
// Agent actions and conditions defined here
}Agents support configurable retry policies for resilient action execution.
import com.embabel.agent.api.ActionRetryPolicy;
import com.embabel.agent.api.annotation.Agent;
import com.embabel.agent.api.annotation.PlannerType;
@Agent(
description = "Resilient agent with exponential backoff",
planner = PlannerType.GOAP,
actionRetryPolicy = ActionRetryPolicy.exponential(3, 1000)
)
public class ResilientAgent {
@Action(description = "Fetch data with retries")
public Data fetchData(String source) {
return dataService.fetch(source);
}
@Action(
description = "Critical operation - no retries",
actionRetryPolicy = ActionRetryPolicy.NO_RETRY
)
public void criticalOperation() {
// Must succeed first time
}
}import com.embabel.agent.api.ActionRetryPolicy
import com.embabel.agent.api.annotation.Agent
import com.embabel.agent.api.annotation.Action
@Agent(
description = "Data processor with fixed retry",
actionRetryPolicy = ActionRetryPolicy.fixed(3, 2000)
)
class DataProcessor {
@Action(
description = "Process with exponential backoff",
actionRetryPolicy = ActionRetryPolicy.exponential(10, 100)
)
fun processData(data: Input): Output {
return processor.process(data)
}
}Retry Policy Options:
ActionRetryPolicy.DEFAULT - Sensible defaults for most scenariosActionRetryPolicy.exponential(attempts, initialBackoffMs) - Exponential backoff between retriesActionRetryPolicy.fixed(attempts, backoffMs) - Constant wait time between retriesActionRetryPolicy.NO_RETRY - Disable retries completelyUse @EmbabelComponent to create reusable capability providers that aren't full agents.
import com.embabel.agent.api.annotation.EmbabelComponent;
import com.embabel.agent.api.annotation.Action;
@EmbabelComponent(scan = true)
public class FileOperations {
@Action(description = "Read file contents")
public String readFile(String path) {
return Files.readString(Path.of(path));
}
@Action(description = "Write file contents")
public void writeFile(String path, String content) {
Files.writeString(Path.of(path), content);
}
@Action(description = "List directory contents")
public List<String> listDirectory(String path) {
return Arrays.asList(new File(path).list());
}
}import com.embabel.agent.api.annotation.EmbabelComponent
import com.embabel.agent.api.annotation.Action
import java.nio.file.Files
import java.nio.file.Paths
@EmbabelComponent(scan = true)
class DatabaseOperations {
@Action(description = "Query database records")
fun query(sql: String): List<Record> {
return executeQuery(sql)
}
@Action(description = "Insert database record")
fun insert(record: Record) {
executeInsert(record)
}
@Action(description = "Update database record")
fun update(id: String, record: Record) {
executeUpdate(id, record)
}
}Use opaque = true to hide internal implementation details when the agent is used as a subagent.
@Agent(
description = "Internal processing agent",
opaque = true,
scan = true
)
public class InternalProcessorAgent {
// These actions are hidden from parent agents
@Action(description = "Internal validation step")
private ValidationResult validate(Input input) {
return validator.validate(input);
}
// Public interface for parent agents
@AchievesGoal(
description = "Process input and return result",
export = @Export(local = true, remote = false)
)
@Action(description = "Process input")
public ProcessedOutput process(Input input) {
ValidationResult validated = validate(input);
return transform(validated);
}
}@Agent(
description = "Background worker agent",
opaque = true
)
class BackgroundWorkerAgent {
// Internal implementation details
@Action(description = "Prepare data")
private fun prepare(raw: RawData): PreparedData {
return preparer.prepare(raw)
}
@Action(description = "Transform data")
private fun transform(prepared: PreparedData): TransformedData {
return transformer.transform(prepared)
}
// Public goal for external callers
@AchievesGoal(
description = "Complete background processing",
export = Export(local = true)
)
@Action(description = "Execute background job")
fun execute(raw: RawData): TransformedData {
val prepared = prepare(raw)
return transform(prepared)
}
}Override the default Spring bean name for an agent.
@Agent(
description = "Custom named agent",
beanName = "myCustomAgentBean",
scan = true
)
public class CustomNamedAgent {
// Implementation
}
// Usage in other components
@Service
public class AgentService {
@Autowired
@Qualifier("myCustomAgentBean")
private Agent customAgent;
public void useAgent() {
// Use the custom-named agent
}
}@Agent(
description = "Custom bean agent",
beanName = "specialAgentBean"
)
class CustomBeanAgent {
// Implementation
}
// Usage with qualifier
@Service
class AgentService(
@Qualifier("specialAgentBean")
private val customAgent: Agent
) {
fun useAgent() {
// Use the custom-named agent
}
}For performance or control, disable automatic scanning and manually register capabilities.
@Agent(
description = "Manually configured agent",
scan = false
)
public class ManualAgent {
// Capabilities must be registered programmatically
// or explicitly invoked
public void explicitMethod() {
// This won't be auto-discovered as an action
}
}@Agent(
description = "Manual configuration agent",
scan = false
)
class ManualConfigAgent {
// Manual registration required for actions
fun customOperation() {
// Not automatically discovered
}
}import com.embabel.agent.api.annotation.*;
import com.embabel.agent.api.ActionRetryPolicy;
import org.springframework.stereotype.Component;
@Agent(
description = "Task processing agent with full configuration",
provider = "task-management",
version = "1.0.0",
planner = PlannerType.GOAP,
scan = true,
opaque = false,
actionRetryPolicy = ActionRetryPolicy.exponential(3, 1000)
)
public class TaskProcessingAgent {
private final TaskRepository taskRepository;
private final TaskProcessor processor;
public TaskProcessingAgent(
TaskRepository taskRepository,
TaskProcessor processor
) {
this.taskRepository = taskRepository;
this.processor = processor;
}
@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)
.orElseThrow(() -> new TaskNotFoundException(taskId));
}
@Action(
description = "Validate task data",
pre = {"taskLoaded"},
post = {"taskValidated"},
cost = 2.0,
value = 15.0
)
public ValidationResult validateTask(Task task) {
return processor.validate(task);
}
@Action(
description = "Process validated task",
pre = {"taskValidated"},
post = {"taskProcessed"},
outputBinding = "result",
cost = 20.0,
value = 50.0,
actionRetryPolicy = ActionRetryPolicy.exponential(5, 500)
)
public ProcessedResult processTask(
Task task,
@Provided Ai ai,
@Provided ActionContext context
) {
context.updateProgress("Processing task: " + task.getId());
return ai.withLlm(OpenAiModels.GPT_4_TURBO)
.createObject("Process this task: " + task.getDescription());
}
@Action(
description = "Save processed result",
pre = {"taskProcessed"},
post = {"taskSaved"},
canRerun = false,
cost = 5.0,
value = 30.0
)
public void saveResult(ProcessedResult result) {
taskRepository.saveResult(result);
}
}import com.embabel.agent.api.annotation.*
import com.embabel.agent.api.ActionRetryPolicy
import org.springframework.stereotype.Component
@Agent(
description = "Data analysis agent with GOAP planning",
provider = "analytics",
version = "2.0.0",
planner = PlannerType.GOAP,
scan = true,
actionRetryPolicy = ActionRetryPolicy.fixed(3, 2000)
)
class DataAnalysisAgent(
private val dataSource: DataSource,
private val analyzer: DataAnalyzer,
private val reportGenerator: ReportGenerator
) {
@Action(
description = "Load dataset from source",
post = ["dataLoaded"],
outputBinding = "dataset",
cost = 10.0,
value = 20.0
)
fun loadData(query: String): Dataset {
return dataSource.load(query)
}
@Action(
description = "Clean and prepare data",
pre = ["dataLoaded"],
post = ["dataCleaned"],
outputBinding = "cleanedData",
cost = 5.0,
value = 25.0
)
fun cleanData(dataset: Dataset): CleanedData {
return analyzer.clean(dataset)
}
@Action(
description = "Perform statistical analysis",
pre = ["dataCleaned"],
post = ["dataAnalyzed"],
outputBinding = "analysis",
cost = 15.0,
value = 50.0,
actionRetryPolicy = ActionRetryPolicy.exponential(5, 1000)
)
fun analyzeData(
cleanedData: CleanedData,
@Provided ai: Ai,
@Provided context: ActionContext
): Analysis {
context.updateProgress("Analyzing ${cleanedData.size} records")
return analyzer.analyze(cleanedData)
}
@Action(
description = "Generate final report",
pre = ["dataAnalyzed"],
post = ["reportGenerated"],
canRerun = false,
cost = 8.0,
value = 40.0
)
fun generateReport(
analysis: Analysis,
@Provided context: ActionContext
): Report {
context.updateProgress("Generating report")
return reportGenerator.generate(analysis)
}
}@Agent(description = "Simple file processor")
public class FileProcessorAgent {
@Action(description = "Process file")
public Result processFile(String path) {
// Implementation
}
}@Agent(
description = "Complex workflow orchestrator",
planner = PlannerType.GOAP
)
public class WorkflowAgent {
@Action(pre = {}, post = {"initialized"})
public void initialize() { }
@Action(pre = {"initialized"}, post = {"processed"})
public void process() { }
@Action(pre = {"processed"}, post = {"completed"})
public void finalize() { }
}@Agent(
description = "Remote API client",
actionRetryPolicy = ActionRetryPolicy.exponential(5, 1000)
)
public class RemoteApiAgent {
@Action(description = "Call remote service")
public ApiResponse callService(Request request) {
return apiClient.call(request);
}
}tessl i tessl/maven-com-embabel-agent--embabel-agent-starter@0.3.1docs