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 core domain types, enums, and concepts.
Enum defining the planning algorithm used by agents.
package com.embabel.agent.api
enum class PlannerType {
GOAP
}Values:
GOAP - Goal-Oriented Action Planning (default)Usage:
import com.embabel.agent.api.annotation.Agent;
import com.embabel.agent.api.annotation.PlannerType;
@Agent(
description = "Task planner agent",
planner = PlannerType.GOAP
)
public class TaskPlannerAgent { }import com.embabel.agent.api.annotation.Agent
import com.embabel.agent.api.annotation.PlannerType
@Agent(
description = "Workflow agent",
planner = PlannerType.GOAP
)
class WorkflowAgent { }Configures retry behavior for actions that fail during execution.
package com.embabel.agent.api
data class ActionRetryPolicy(
val maxAttempts: Int,
val backoffMillis: Long,
val backoffMultiplier: Double,
val backoffMaxInterval: Long
) {
companion object {
val DEFAULT: ActionRetryPolicy
val NO_RETRY: ActionRetryPolicy
fun exponential(maxAttempts: Int, initialBackoffMillis: Long): ActionRetryPolicy
fun fixed(maxAttempts: Int, backoffMillis: Long): ActionRetryPolicy
}
}Properties:
maxAttempts: Int - Maximum retry attemptsbackoffMillis: Long - Initial backoff millisecondsbackoffMultiplier: Double - Backoff multiplier for exponential retrybackoffMaxInterval: Long - Maximum backoff intervalFactory Methods:
DEFAULT: ActionRetryPolicy - Default retry policyNO_RETRY: ActionRetryPolicy - No retry policyexponential(maxAttempts: Int, initialBackoffMillis: Long): ActionRetryPolicy - Exponential backofffixed(maxAttempts: Int, backoffMillis: Long): ActionRetryPolicy - Fixed backoffUsage:
import com.embabel.agent.api.ActionRetryPolicy;
import com.embabel.agent.api.annotation.Agent;
import com.embabel.agent.api.annotation.Action;
@Agent(
description = "Resilient agent",
actionRetryPolicy = ActionRetryPolicy.exponential(3, 1000)
)
public class ResilientAgent {
@Action(
description = "Fetch data with retries",
actionRetryPolicy = ActionRetryPolicy.exponential(5, 500)
)
public Data fetchData(String source) {
return dataService.fetch(source);
}
@Action(
description = "Critical operation - no retries",
actionRetryPolicy = ActionRetryPolicy.NO_RETRY
)
public void criticalOperation() {
// No retries - 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",
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)
}
}Supports multi-modal agent inputs including text, images, audio, and video.
package com.embabel.agent.api
sealed class MultimodalContent {
data class Text(val content: String) : MultimodalContent()
data class Image(val url: String, val mimeType: String) : MultimodalContent()
data class Audio(val url: String, val mimeType: String) : MultimodalContent()
data class Video(val url: String, val mimeType: String) : MultimodalContent()
data class File(val path: String, val mimeType: String) : MultimodalContent()
companion object {
fun text(content: String): MultimodalContent.Text
fun image(url: String, mimeType: String = "image/jpeg"): MultimodalContent.Image
fun audio(url: String, mimeType: String = "audio/mpeg"): MultimodalContent.Audio
fun video(url: String, mimeType: String = "video/mp4"): MultimodalContent.Video
fun file(path: String, mimeType: String): MultimodalContent.File
}
}Types:
content: String - Text contenturl: String - Image URL or pathmimeType: String - MIME type (default: "image/jpeg")url: String - Audio URL or pathmimeType: String - MIME type (default: "audio/mpeg")url: String - Video URL or pathmimeType: String - MIME type (default: "video/mp4")path: String - File pathmimeType: String - MIME typeFactory Methods:
text(content: String): MultimodalContent.Text - Create text contentimage(url: String, mimeType: String = "image/jpeg"): MultimodalContent.Image - Create image contentaudio(url: String, mimeType: String = "audio/mpeg"): MultimodalContent.Audio - Create audio contentvideo(url: String, mimeType: String = "video/mp4"): MultimodalContent.Video - Create video contentfile(path: String, mimeType: String): MultimodalContent.File - Create file contentUsage:
import com.embabel.agent.api.MultimodalContent;
import com.embabel.agent.api.annotation.Action;
@Agent(description = "Multimodal agent")
public class MultimodalAgent {
@Action(description = "Process multimodal input")
public Result processMultimodal(List<MultimodalContent> inputs, @Provided Ai ai) {
return ai.withLlm(GeminiModels.GEMINI_2_5_PRO)
.createObject(inputs);
}
public List<MultimodalContent> createMultimodalInput() {
return List.of(
MultimodalContent.text("Analyze this image:"),
MultimodalContent.image("https://example.com/image.jpg", "image/jpeg"),
MultimodalContent.text("and this audio:"),
MultimodalContent.audio("https://example.com/audio.mp3", "audio/mpeg")
);
}
}import com.embabel.agent.api.MultimodalContent
import com.embabel.agent.api.annotation.Action
@Agent(description = "Content analyzer")
class ContentAnalyzer {
@Action(description = "Analyze multimedia content")
fun analyzeContent(content: List<MultimodalContent>, @Provided ai: Ai): Analysis {
return ai.withLlm(GeminiModels.GEMINI_2_5_PRO)
.createObject(content)
}
fun createContentList(): List<MultimodalContent> {
return listOf(
MultimodalContent.text("Process these files:"),
MultimodalContent.image("file:///images/chart.png"),
MultimodalContent.file("/data/report.pdf", "application/pdf")
)
}
}Messages sent during agent execution for logging, progress, and communication.
package com.embabel.agent.api
sealed class Message {
data class Info(val content: String) : Message()
data class Warning(val content: String) : Message()
data class Error(val content: String, val exception: Throwable?) : Message()
data class Progress(val content: String, val percentage: Double?) : Message()
data class User(val content: String) : Message()
data class Assistant(val content: String) : Message()
companion object {
fun info(content: String): Message.Info
fun warning(content: String): Message.Warning
fun error(content: String, exception: Throwable? = null): Message.Error
fun progress(content: String, percentage: Double? = null): Message.Progress
fun user(content: String): Message.User
fun assistant(content: String): Message.Assistant
}
}Types:
content: String - Informational messagecontent: String - Warning messagecontent: String - Error messageexception: Throwable? - Optional exceptioncontent: String - Progress messagepercentage: Double? - Optional percentage (0.0-100.0)content: String - User messagecontent: String - Assistant messageFactory Methods:
info(content: String): Message.Info - Create info messagewarning(content: String): Message.Warning - Create warning messageerror(content: String, exception: Throwable? = null): Message.Error - Create error messageprogress(content: String, percentage: Double? = null): Message.Progress - Create progress messageuser(content: String): Message.User - Create user messageassistant(content: String): Message.Assistant - Create assistant messageUsage:
import com.embabel.agent.api.Message;
import com.embabel.agent.api.ActionContext;
@Agent(description = "Reporting agent")
public class ReportingAgent {
@Action(description = "Generate report with progress")
public Report generateReport(Data data, @Provided ActionContext context) {
context.sendMessage(Message.info("Starting report generation"));
context.sendMessage(Message.progress("Analyzing data", 0.0));
Analysis analysis = analyze(data);
context.sendMessage(Message.progress("Data analyzed", 50.0));
Report report = createReport(analysis);
context.sendMessage(Message.progress("Report created", 100.0));
context.sendMessage(Message.info("Report generation complete"));
return report;
}
}import com.embabel.agent.api.Message
import com.embabel.agent.api.ActionContext
@Agent(description = "Data processor")
class DataProcessor {
@Action(description = "Process with detailed logging")
fun processData(input: Dataset, @Provided context: ActionContext): ProcessedData {
context.sendMessage(Message.info("Processing ${input.size} records"))
try {
context.sendMessage(Message.progress("Validating", 25.0))
val validated = validate(input)
context.sendMessage(Message.progress("Transforming", 50.0))
val transformed = transform(validated)
context.sendMessage(Message.progress("Finalizing", 75.0))
val result = finalize(transformed)
context.sendMessage(Message.progress("Complete", 100.0))
return result
} catch (e: Exception) {
context.sendMessage(Message.error("Processing failed", e))
throw e
}
}
}Channel for sending structured output events during agent execution.
package com.embabel.agent.api
interface OutputChannel {
fun send(event: OutputChannelEvent)
fun sendAndSave(event: OutputChannelEvent)
fun close()
}
data class OutputChannelEvent(
val type: EventType,
val content: Any,
val metadata: Map<String, Any> = emptyMap()
)
enum class EventType {
DATA, PROGRESS, LOG, ERROR, RESULT
}OutputChannel Methods:
send(event: OutputChannelEvent) - Send eventsendAndSave(event: OutputChannelEvent) - Send and persist eventclose() - Close channelOutputChannelEvent Properties:
type: EventType - Event typecontent: Any - Event contentmetadata: Map<String, Any> - Event metadata (default: empty)EventType Values:
DATA - Data eventPROGRESS - Progress eventLOG - Log eventERROR - Error eventRESULT - Result eventUsage:
import com.embabel.agent.api.OutputChannel;
import com.embabel.agent.api.OutputChannelEvent;
import com.embabel.agent.api.EventType;
@Action(description = "Stream results")
public void streamResults(@Provided OutputChannel channel) {
channel.send(new OutputChannelEvent(
EventType.PROGRESS,
Map.of("stage", "initialization", "percent", 0)
));
channel.send(new OutputChannelEvent(
EventType.DATA,
processedData,
Map.of("timestamp", Instant.now())
));
channel.send(new OutputChannelEvent(
EventType.RESULT,
finalResult
));
channel.close();
}Interface for listening to agent execution events for monitoring and observability.
package com.embabel.agent.api
interface AgenticEventListener {
fun onAgentStart(agent: Agent, input: Any)
fun onAgentComplete(agent: Agent, result: Any)
fun onAgentError(agent: Agent, error: Throwable)
fun onActionStart(action: Action, parameters: Map<String, Any>)
fun onActionComplete(action: Action, result: Any)
fun onActionError(action: Action, error: Throwable)
fun onPlanningStart(agent: Agent)
fun onPlanningComplete(agent: Agent, plan: Plan)
}Methods:
onAgentStart(agent: Agent, input: Any) - Agent execution startedonAgentComplete(agent: Agent, result: Any) - Agent execution completedonAgentError(agent: Agent, error: Throwable) - Agent execution erroronActionStart(action: Action, parameters: Map<String, Any>) - Action execution startedonActionComplete(action: Action, result: Any) - Action execution completedonActionError(action: Action, error: Throwable) - Action execution erroronPlanningStart(agent: Agent) - Planning startedonPlanningComplete(agent: Agent, plan: Plan) - Planning completedUsage:
import com.embabel.agent.api.AgenticEventListener;
import org.springframework.stereotype.Component;
@Component
public class MonitoringEventListener implements AgenticEventListener {
@Override
public void onAgentStart(Agent agent, Object input) {
log.info("Agent started: {} with input: {}", agent.getName(), input);
metrics.incrementCounter("agent.start");
}
@Override
public void onAgentComplete(Agent agent, Object result) {
log.info("Agent completed: {} with result: {}", agent.getName(), result);
metrics.incrementCounter("agent.complete");
}
@Override
public void onAgentError(Agent agent, Throwable error) {
log.error("Agent error: {}", agent.getName(), error);
metrics.incrementCounter("agent.error");
alerts.sendAlert("Agent failure: " + agent.getName());
}
@Override
public void onActionStart(Action action, Map<String, Object> parameters) {
log.debug("Action started: {}", action.getDescription());
}
@Override
public void onActionComplete(Action action, Object result) {
log.debug("Action completed: {}", action.getDescription());
}
@Override
public void onActionError(Action action, Throwable error) {
log.warn("Action error: {}", action.getDescription(), error);
}
@Override
public void onPlanningStart(Agent agent) {
log.debug("Planning started for agent: {}", agent.getName());
}
@Override
public void onPlanningComplete(Agent agent, Plan plan) {
log.debug("Planning complete: {} steps", plan.getSteps().size());
}
}Interface for implementing safety constraints and validation rules.
package com.embabel.agent.api
interface GuardRail {
fun validate(operation: Operation): ValidationResult
fun getName(): String
fun getDescription(): String
}
data class ValidationResult(
val passed: Boolean,
val message: String? = null,
val severity: Severity = Severity.ERROR
)
enum class Severity {
INFO, WARNING, ERROR, CRITICAL
}GuardRail Methods:
validate(operation: Operation): ValidationResult - Validate operationgetName(): String - Get guard rail namegetDescription(): String - Get guard rail descriptionValidationResult Properties:
passed: Boolean - Validation passed flagmessage: String? - Optional validation messageseverity: Severity - Severity level (default: ERROR)Severity Values:
INFO - InformationalWARNING - WarningERROR - ErrorCRITICAL - CriticalUsage:
import com.embabel.agent.api.GuardRail;
import com.embabel.agent.api.ValidationResult;
import com.embabel.agent.api.Severity;
import org.springframework.stereotype.Component;
@Component
public class CostGuardRail implements GuardRail {
private static final double MAX_COST = 1000.0;
@Override
public ValidationResult validate(Operation operation) {
double cost = operation.estimateCost();
if (cost > MAX_COST) {
return new ValidationResult(
false,
String.format("Operation cost %.2f exceeds maximum %.2f", cost, MAX_COST),
Severity.ERROR
);
} else if (cost > MAX_COST * 0.8) {
return new ValidationResult(
true,
String.format("Operation cost %.2f is approaching maximum", cost),
Severity.WARNING
);
}
return new ValidationResult(true);
}
@Override
public String getName() {
return "cost-guard-rail";
}
@Override
public String getDescription() {
return "Prevents operations that exceed cost limits";
}
}Type-safe representation of values between 0.0 and 1.0.
package com.embabel.agent.api
data class ZeroToOne private constructor(val value: Double) {
companion object {
val ZERO: ZeroToOne
val ONE: ZeroToOne
fun of(value: Double): ZeroToOne
}
}Properties:
value: Double - Value between 0.0 and 1.0Factory Methods:
ZERO: ZeroToOne - Zero value (0.0)ONE: ZeroToOne - One value (1.0)of(value: Double): ZeroToOne - Create from double (validates 0.0-1.0 range)Usage:
import com.embabel.agent.api.ZeroToOne;
@Condition(name = "hasStock", cost = ZeroToOne.of(0.1))
public boolean hasStock(String productId) {
return inventory.getStock(productId) > 0;
}import com.embabel.agent.api.ZeroToOne
@Condition(name = "userAuthenticated", cost = ZeroToOne.of(0.05))
fun isAuthenticated(userId: String): Boolean {
return authService.isAuthenticated(userId)
}Execution budget configuration (time or steps).
package com.embabel.agent.api
data class Budget(
val type: BudgetType,
val value: Long
) {
companion object {
fun of(time: Long, unit: TimeUnit): Budget
fun ofSteps(steps: Long): Budget
fun unlimited(): Budget
}
}
enum class BudgetType {
TIME, STEPS, UNLIMITED
}Properties:
type: BudgetType - Budget typevalue: Long - Budget valueFactory Methods:
of(time: Long, unit: TimeUnit): Budget - Create time budgetofSteps(steps: Long): Budget - Create step budgetunlimited(): Budget - Create unlimited budgetBudgetType Values:
TIME - Time-based budgetSTEPS - Step-based budgetUNLIMITED - No budget limitUsage:
import com.embabel.agent.api.Budget;
import java.util.concurrent.TimeUnit;
AgentInvocation<AnalysisResult> invocation = AgentInvocation.builder(platform)
.withBudget(Budget.of(60, TimeUnit.SECONDS))
.build(AnalysisResult.class);Logging verbosity levels.
package com.embabel.agent.api
enum class Verbosity {
SILENT, MINIMAL, NORMAL, DETAILED, DEBUG
}Values:
SILENT - No loggingMINIMAL - Minimal loggingNORMAL - Normal logging (default)DETAILED - Detailed loggingDEBUG - Debug-level loggingUsage:
import com.embabel.agent.api.Verbosity;
AgentInvocation<Report> invocation = AgentInvocation.builder(platform)
.withVerbosity(Verbosity.DETAILED)
.build(Report.class);tessl i tessl/maven-com-embabel-agent--embabel-agent-starter@0.3.1docs