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 defining and achieving goals with @AchievesGoal annotation.
import com.embabel.agent.api.annotation.AchievesGoal;
import com.embabel.agent.api.annotation.Export;
import com.embabel.agent.api.annotation.Action;
@Agent(description = "Report generator")
public class ReportAgent {
@AchievesGoal(
description = "Generate a summary report from analyzed data",
value = 1.0,
tags = {"reporting", "summarization"}
)
@Action(description = "Generate summary report")
public Report generateSummaryReport(AnalyzedData data) {
return reportGenerator.generate(data);
}
}import com.embabel.agent.api.annotation.AchievesGoal
import com.embabel.agent.api.annotation.Export
import com.embabel.agent.api.annotation.Action
@Agent(description = "Request processor")
class RequestProcessorAgent {
@AchievesGoal(
description = "Process user request and generate response",
tags = ["processing", "generation"],
value = 1.0
)
@Action(description = "Process request")
fun processRequest(input: UserInput): Result {
return processor.process(input)
}
}Provide examples to help LLMs understand goal scenarios.
@Agent(description = "Data analyzer")
public class AnalyzerAgent {
@AchievesGoal(
description = "Analyze dataset and provide insights",
value = 1.0,
tags = {"analysis", "insights", "data-science"},
examples = {
"Analyze sales data for Q4",
"Provide insights from customer feedback data",
"Analyze website traffic patterns"
}
)
@Action(description = "Perform data analysis")
public AnalysisReport analyzeData(Dataset dataset, @Provided Ai ai) {
return ai.withLlm(OpenAiModels.GPT_4_TURBO)
.createObject("Analyze this dataset: " + dataset);
}
}@Agent(description = "Content generator")
class ContentGeneratorAgent {
@AchievesGoal(
description = "Generate marketing content from brief",
tags = ["content", "marketing", "copywriting"],
examples = [
"Create blog post about product features",
"Generate social media campaign content",
"Write email newsletter about new release"
],
value = 1.0
)
@Action(description = "Generate content")
fun generateContent(
brief: ContentBrief,
@Provided ai: Ai
): MarketingContent {
return ai.withLlm(GeminiModels.GEMINI_2_5_PRO)
.createObject("Generate content for: $brief")
}
}Control how goals are exposed locally and remotely.
@Agent(description = "Internal processor")
public class InternalProcessorAgent {
@AchievesGoal(
description = "Internal processing step",
export = @Export(local = true, remote = false)
)
@Action(description = "Process internally")
public InternalResult processInternal(Data data) {
return internalProcessor.process(data);
}
}@Agent(description = "API agent")
public class ApiAgent {
@AchievesGoal(
description = "Publicly accessible API endpoint",
export = @Export(
name = "processUserQuery",
remote = true,
local = true,
startingInputTypes = {String.class, UserQuery.class}
),
tags = {"api", "public"},
value = 1.0
)
@Action(description = "Process user query")
public Response processQuery(UserQuery query) {
return queryProcessor.process(query);
}
}@Agent(description = "Public service agent")
class PublicServiceAgent {
@AchievesGoal(
description = "Transform data format for external clients",
export = Export(
name = "data-transformer",
remote = true,
local = true,
startingInputTypes = [RawData::class, String::class]
),
tags = ["transformation", "api"],
value = 1.0
)
@Action(description = "Transform data")
fun transform(raw: RawData): TransformedData {
return transformer.transform(raw)
}
}Complete workflow demonstrating how goals guide GOAP planning.
@Agent(
description = "Order fulfillment agent",
planner = PlannerType.GOAP
)
public class OrderFulfillmentAgent {
// Step 1: Load order
@Action(
description = "Load order from database",
post = {"orderLoaded"},
outputBinding = "order",
cost = 5.0,
value = 10.0
)
public Order loadOrder(String orderId) {
return orderRepository.findById(orderId);
}
// Step 2: Validate order
@Action(
description = "Validate order details",
pre = {"orderLoaded"},
post = {"orderValidated"},
cost = 3.0,
value = 15.0
)
public ValidationResult validateOrder(Order order) {
return validator.validate(order);
}
// Step 3: Check inventory
@Action(
description = "Check inventory availability",
pre = {"orderValidated"},
post = {"inventoryChecked"},
outputBinding = "inventoryStatus",
cost = 5.0,
value = 20.0
)
public InventoryStatus checkInventory(Order order) {
return inventoryService.check(order);
}
// Step 4: Calculate shipping
@Action(
description = "Calculate shipping cost",
pre = {"inventoryChecked"},
post = {"shippingCalculated"},
outputBinding = "shippingCost",
cost = 4.0,
value = 15.0
)
public Double calculateShipping(Order order) {
return shippingCalculator.calculate(order);
}
// Goal: Fulfill order
@AchievesGoal(
description = "Complete order fulfillment with shipping",
tags = {"fulfillment", "orders", "shipping"},
examples = {
"Fulfill order #12345",
"Process and ship customer order",
"Complete order delivery"
},
export = @Export(
remote = true,
local = true,
startingInputTypes = {String.class, Order.class}
),
value = 100.0
)
@Action(
description = "Fulfill order",
pre = {"orderValidated", "inventoryChecked", "shippingCalculated"},
post = {"orderFulfilled"},
canRerun = false
)
public FulfilledOrder fulfillOrder(
Order order,
InventoryStatus inventoryStatus,
Double shippingCost,
@Provided ActionContext context
) {
context.updateProgress("Fulfilling order " + order.getId());
if (!inventoryStatus.isAvailable()) {
throw new InsufficientInventoryException(order.getId());
}
FulfilledOrder fulfilled = fulfillmentService.fulfill(
order,
shippingCost
);
context.sendMessage(Message.info(
"Order " + order.getId() + " fulfilled successfully"
));
return fulfilled;
}
}@Agent(
description = "Document processing agent",
planner = PlannerType.GOAP
)
class DocumentProcessingAgent {
// Step 1: Upload document
@Action(
description = "Upload document to storage",
post = ["documentUploaded"],
outputBinding = "documentId",
cost = 10.0,
value = 20.0
)
fun uploadDocument(file: File): String {
return storageService.upload(file)
}
// Step 2: Extract text
@Action(
description = "Extract text from document",
pre = ["documentUploaded"],
post = ["textExtracted"],
outputBinding = "extractedText",
cost = 15.0,
value = 30.0
)
fun extractText(documentId: String): String {
return ocrService.extract(documentId)
}
// Step 3: Analyze content
@Action(
description = "Analyze document content with AI",
pre = ["textExtracted"],
post = ["contentAnalyzed"],
outputBinding = "analysis",
cost = 25.0,
value = 50.0
)
fun analyzeContent(
extractedText: String,
@Provided ai: Ai
): ContentAnalysis {
return ai.withLlm(GeminiModels.GEMINI_2_5_PRO)
.createObject("Analyze: $extractedText")
}
// Goal: Generate structured document data
@AchievesGoal(
description = "Process document and extract structured data",
tags = ["document-processing", "ocr", "analysis"],
examples = [
"Extract data from invoice",
"Process receipt and get line items",
"Analyze contract and extract key terms"
],
export = Export(
name = "process-document",
remote = true,
local = true,
startingInputTypes = [File::class, String::class]
),
value = 100.0
)
@Action(
description = "Generate structured document data",
pre = ["contentAnalyzed"],
post = ["documentProcessed"],
canRerun = false
)
fun processDocument(
analysis: ContentAnalysis,
@Provided context: ActionContext
): StructuredDocument {
context.updateProgress("Generating structured data")
val structured = documentStructurer.structure(analysis)
context.sendMessage(Message.info(
"Extracted ${structured.fields.size} fields"
))
return structured
}
}Agents can have multiple goal-achieving actions.
@Agent(description = "Customer service agent")
public class CustomerServiceAgent {
@AchievesGoal(
description = "Answer customer question",
tags = {"support", "qa"},
export = @Export(remote = true, local = true)
)
@Action(description = "Answer question")
public Answer answerQuestion(Question question, @Provided Ai ai) {
return ai.withLlm(OpenAiModels.GPT_4_TURBO)
.createObject("Answer: " + question);
}
@AchievesGoal(
description = "Resolve customer complaint",
tags = {"support", "complaints"},
export = @Export(remote = true, local = true)
)
@Action(description = "Resolve complaint")
public Resolution resolveComplaint(Complaint complaint, @Provided Ai ai) {
return ai.withLlm(OpenAiModels.GPT_4_TURBO)
.createObject("Resolve: " + complaint);
}
@AchievesGoal(
description = "Process refund request",
tags = {"support", "refunds"},
export = @Export(remote = true, local = true)
)
@Action(description = "Process refund")
public RefundResult processRefund(RefundRequest request) {
return refundService.process(request);
}
}@Agent(description = "Content moderation agent")
class ModerationAgent {
@AchievesGoal(
description = "Moderate user-generated content",
tags = ["moderation", "content-safety"],
export = Export(remote = true)
)
@Action(description = "Moderate content")
fun moderateContent(content: Content, @Provided ai: Ai): ModerationResult {
return ai.withLlm(GeminiModels.GEMINI_2_5_PRO)
.createObject("Moderate: $content")
}
@AchievesGoal(
description = "Classify content category",
tags = ["classification", "categorization"],
export = Export(remote = true)
)
@Action(description = "Classify content")
fun classifyContent(content: Content, @Provided ai: Ai): Classification {
return ai.withLlm(GeminiModels.GEMINI_2_5_PRO)
.createObject("Classify: $content")
}
@AchievesGoal(
description = "Detect spam or malicious content",
tags = ["spam-detection", "security"],
export = Export(remote = true)
)
@Action(description = "Detect spam")
fun detectSpam(content: Content): SpamDetectionResult {
return spamDetector.detect(content)
}
}Use the value attribute to prioritize goal achievement.
@Agent(description = "Task prioritization agent")
public class TaskAgent {
@AchievesGoal(
description = "Process high-priority task",
tags = {"tasks", "high-priority"},
value = 100.0 // High value
)
@Action(description = "Process high-priority")
public Result processHighPriority(Task task) {
return taskProcessor.process(task, Priority.HIGH);
}
@AchievesGoal(
description = "Process medium-priority task",
tags = {"tasks", "medium-priority"},
value = 50.0 // Medium value
)
@Action(description = "Process medium-priority")
public Result processMediumPriority(Task task) {
return taskProcessor.process(task, Priority.MEDIUM);
}
@AchievesGoal(
description = "Process low-priority task",
tags = {"tasks", "low-priority"},
value = 10.0 // Low value
)
@Action(description = "Process low-priority")
public Result processLowPriority(Task task) {
return taskProcessor.process(task, Priority.LOW);
}
}@Agent(description = "Alert handler")
class AlertAgent {
@AchievesGoal(
description = "Handle critical system alert",
tags = ["alerts", "critical"],
value = 100.0 // Highest priority
)
@Action(description = "Handle critical alert")
fun handleCritical(alert: Alert): Response {
return alertHandler.handleCritical(alert)
}
@AchievesGoal(
description = "Handle warning alert",
tags = ["alerts", "warning"],
value = 50.0 // Medium priority
)
@Action(description = "Handle warning")
fun handleWarning(alert: Alert): Response {
return alertHandler.handleWarning(alert)
}
@AchievesGoal(
description = "Handle informational alert",
tags = ["alerts", "info"],
value = 10.0 // Low priority
)
@Action(description = "Handle info")
fun handleInfo(alert: Alert): Response {
return alertHandler.handleInfo(alert)
}
}import com.embabel.agent.api.AgentInvocation;
import com.embabel.agent.api.AgentPlatform;
@Service
public class OrderService {
private final AgentPlatform platform;
public OrderService(AgentPlatform platform) {
this.platform = platform;
}
public FulfilledOrder fulfillOrder(String orderId) {
// Create invocation for goal-achieving agent
AgentInvocation<FulfilledOrder> invocation =
AgentInvocation.create(platform, FulfilledOrder.class);
// Invoke with order ID - agent will plan path to goal
return invocation.invoke(orderId);
}
public CompletableFuture<FulfilledOrder> fulfillOrderAsync(String orderId) {
AgentInvocation<FulfilledOrder> invocation =
AgentInvocation.create(platform, FulfilledOrder.class);
// Asynchronous goal achievement
return invocation.invokeAsync(orderId);
}
}import com.embabel.agent.api.AgentInvocation
import com.embabel.agent.api.AgentPlatform
@Service
class DocumentService(private val platform: AgentPlatform) {
fun processDocument(file: File): StructuredDocument {
// Create invocation for goal
val invocation = AgentInvocation.create<StructuredDocument>(platform)
// Invoke - agent plans and executes to achieve goal
return invocation.invoke(file)
}
suspend fun processDocumentAsync(file: File): StructuredDocument {
val invocation = AgentInvocation.create<StructuredDocument>(platform)
// Async goal achievement
return invocation.invokeAsync(file).await()
}
}import com.embabel.agent.api.annotation.*;
@Agent(
description = "E-commerce order processing agent",
planner = PlannerType.GOAP
)
public class EcommerceOrderAgent {
private final OrderRepository orderRepo;
private final InventoryService inventory;
private final PaymentService payment;
private final ShippingService shipping;
public EcommerceOrderAgent(
OrderRepository orderRepo,
InventoryService inventory,
PaymentService payment,
ShippingService shipping
) {
this.orderRepo = orderRepo;
this.inventory = inventory;
this.payment = payment;
this.shipping = shipping;
}
// Supporting actions
@Action(
description = "Load order details",
post = {"orderLoaded"},
outputBinding = "order",
cost = 5.0
)
public Order loadOrder(String orderId) {
return orderRepo.findById(orderId)
.orElseThrow(() -> new OrderNotFoundException(orderId));
}
@Action(
description = "Verify inventory",
pre = {"orderLoaded"},
post = {"inventoryVerified"},
outputBinding = "inventoryStatus",
cost = 5.0
)
public InventoryStatus verifyInventory(Order order) {
return inventory.verify(order.getItems());
}
@Action(
description = "Process payment",
pre = {"orderLoaded", "inventoryVerified"},
post = {"paymentProcessed"},
outputBinding = "paymentResult",
cost = 10.0
)
public PaymentResult processPayment(Order order) {
return payment.process(order.getPaymentInfo(), order.getTotal());
}
// Goal 1: Create shipment
@AchievesGoal(
description = "Create shipment for order",
tags = {"shipping", "fulfillment"},
examples = {
"Ship order #12345",
"Create shipping label for order",
"Prepare order for delivery"
},
export = @Export(
name = "create-shipment",
remote = true,
local = true,
startingInputTypes = {String.class, Order.class}
),
value = 50.0
)
@Action(
description = "Create shipment",
pre = {"paymentProcessed", "inventoryVerified"},
post = {"shipmentCreated"}
)
public Shipment createShipment(
Order order,
InventoryStatus inventoryStatus,
PaymentResult paymentResult,
@Provided ActionContext context
) {
context.updateProgress("Creating shipment for order " + order.getId());
if (!paymentResult.isSuccessful()) {
throw new PaymentFailedException(order.getId());
}
Shipment shipment = shipping.createShipment(order);
context.sendMessage(Message.info(
"Shipment created with tracking: " + shipment.getTrackingNumber()
));
return shipment;
}
// Goal 2: Complete order fulfillment
@AchievesGoal(
description = "Complete full order fulfillment process",
tags = {"fulfillment", "complete", "orders"},
examples = {
"Fulfill order #12345 completely",
"Process and ship order end-to-end",
"Complete order from payment to delivery"
},
export = @Export(
name = "fulfill-order",
remote = true,
local = true,
startingInputTypes = {String.class, Order.class}
),
value = 100.0
)
@Action(
description = "Complete order fulfillment",
pre = {"shipmentCreated"},
canRerun = false
)
public FulfilledOrder fulfillOrder(
Order order,
Shipment shipment,
@Provided ActionContext context
) {
context.updateProgress("Finalizing order " + order.getId());
FulfilledOrder fulfilled = new FulfilledOrder(
order,
shipment,
Instant.now()
);
orderRepo.markFulfilled(fulfilled);
context.sendMessage(Message.info(
"Order " + order.getId() + " fulfilled successfully"
));
return fulfilled;
}
}import com.embabel.agent.api.annotation.*
@Agent(
description = "Machine learning model training agent",
planner = PlannerType.GOAP
)
class ModelTrainingAgent(
private val dataLoader: DataLoader,
private val preprocessor: Preprocessor,
private val trainer: ModelTrainer,
private val evaluator: ModelEvaluator,
private val registry: ModelRegistry
) {
// Supporting actions
@Action(
description = "Load training dataset",
post = ["dataLoaded"],
outputBinding = "dataset",
cost = 10.0
)
fun loadDataset(dataPath: String): Dataset {
return dataLoader.load(dataPath)
}
@Action(
description = "Preprocess data",
pre = ["dataLoaded"],
post = ["dataPreprocessed"],
outputBinding = "preprocessedData",
cost = 20.0
)
fun preprocessData(dataset: Dataset): PreprocessedData {
return preprocessor.preprocess(dataset)
}
@Action(
description = "Train model",
pre = ["dataPreprocessed"],
post = ["modelTrained"],
outputBinding = "model",
cost = 50.0
)
fun trainModel(
preprocessedData: PreprocessedData,
@Provided context: ActionContext
): TrainedModel {
context.updateProgress("Training model...")
return trainer.train(preprocessedData)
}
@Action(
description = "Evaluate model",
pre = ["modelTrained"],
post = ["modelEvaluated"],
outputBinding = "evaluation",
cost = 15.0
)
fun evaluateModel(model: TrainedModel): Evaluation {
return evaluator.evaluate(model)
}
// Goal 1: Train and evaluate model
@AchievesGoal(
description = "Train model and provide evaluation metrics",
tags = ["ml", "training", "evaluation"],
examples = [
"Train classification model on dataset",
"Train and evaluate regression model",
"Build ML model with metrics"
],
export = Export(
name = "train-model",
remote = true,
local = true,
startingInputTypes = [String::class, TrainingSpec::class]
),
value = 75.0
)
@Action(
description = "Complete training with evaluation",
pre = ["modelEvaluated"]
)
fun completeTraining(
model: TrainedModel,
evaluation: Evaluation,
@Provided context: ActionContext
): TrainingResult {
context.sendMessage(Message.info(
"Model accuracy: ${evaluation.accuracy}"
))
return TrainingResult(model, evaluation)
}
// Goal 2: Deploy production-ready model
@AchievesGoal(
description = "Train, evaluate, and deploy model to production",
tags = ["ml", "deployment", "production"],
examples = [
"Deploy trained model to production",
"Train and register production model",
"Complete ML pipeline with deployment"
],
export = Export(
name = "deploy-model",
remote = true,
local = true,
startingInputTypes = [String::class, DeploymentSpec::class]
),
value = 100.0
)
@Action(
description = "Deploy model to production",
pre = ["modelEvaluated"],
canRerun = false
)
fun deployModel(
model: TrainedModel,
evaluation: Evaluation,
@Provided context: ActionContext
): DeployedModel {
if (evaluation.accuracy < 0.85) {
throw ModelQualityException(
"Model accuracy ${evaluation.accuracy} below threshold"
)
}
context.updateProgress("Deploying model to production")
val deployed = registry.register(model, evaluation)
context.sendMessage(Message.info(
"Model deployed with ID: ${deployed.id}"
))
return deployed
}
}tessl i tessl/maven-com-embabel-agent--embabel-agent-starter@0.3.1docs