CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-com-embabel-agent--embabel-agent-api

Fluent DSL and Kotlin DSL for building autonomous agents with planning capabilities on the JVM, featuring annotation-based and programmatic configuration for agentic flows with Spring Boot integration

Overview
Eval results
Files

invocation.mddocs/

Agent Invocation

The invocation API provides a fluent interface for programmatically executing agents with typed inputs and outputs. It supports synchronous and asynchronous execution, configuration options, and result handling.

Capabilities

AgentInvocation Interface

Main interface for invoking agents programmatically.

interface AgentInvocation<T> : TypedInvocation<T, AgentInvocation<T>> {
    /** Set the agent platform */
    fun withAgentPlatform(agentPlatform: AgentPlatform): AgentInvocation<T>

    /** Change return type */
    fun <U> returning(resultType: Class<U>): AgentInvocation<U>

    companion object {
        /** Create invocation with result type */
        fun <T> create(
            agentPlatform: AgentPlatform,
            resultType: Class<T>
        ): AgentInvocation<T>

        /** Create invocation with reified type (Kotlin) */
        inline fun <reified T> create(
            agentPlatform: AgentPlatform
        ): AgentInvocation<T>

        /** Create untyped invocation */
        fun on(agentPlatform: AgentPlatform): AgentInvocation<Any>

        /** Get builder for invocation */
        fun builder(agentPlatform: AgentPlatform): Builder
    }
}

Basic Invocation Example:

@Service
class OrderService(
    private val agentPlatform: AgentPlatform
) {

    fun processOrder(order: Order): OrderResult {
        return AgentInvocation.create<OrderResult>(agentPlatform)
            .withAgentName("order-processor")
            .withInput(order)
            .execute()
    }

    fun processOrderAsync(order: Order): CompletableFuture<OrderResult> {
        return AgentInvocation.create<OrderResult>(agentPlatform)
            .withAgent(orderProcessorAgent)
            .withInput(order)
            .executeAsync()
    }
}

Typed Invocation

Generic invocation interface with configuration methods.

interface TypedInvocation<T, SELF> {
    /** Set agent by reference */
    fun withAgent(agent: Agent): SELF

    /** Set agent by name */
    fun withAgentName(name: String): SELF

    /** Add input object */
    fun withInput(input: Any): SELF

    /** Add multiple inputs */
    fun withInputs(inputs: List<Any>): SELF

    /** Set blackboard state */
    fun withBlackboard(blackboard: Blackboard): SELF

    /** Add goal to achieve */
    fun withGoal(goal: Goal): SELF

    /** Add goals to achieve */
    fun withGoals(goals: List<Goal>): SELF

    /** Set output channel */
    fun withOutputChannel(channel: OutputChannel): SELF

    /** Add event listener */
    fun withEventListener(listener: AgenticEventListener): SELF

    /** Set process options */
    fun withProcessOptions(options: ProcessOptions): SELF

    /** Set autonomy level */
    fun withAutonomy(autonomy: Autonomy): SELF

    /** Set user context */
    fun withUser(user: User): SELF

    /** Set timeout */
    fun withTimeout(timeout: Duration): SELF

    /** Execute synchronously */
    fun execute(): T

    /** Execute asynchronously */
    fun executeAsync(): CompletableFuture<T>
}

Configuration Example:

fun processWithFullConfig(
    data: Dataset,
    agentPlatform: AgentPlatform
): Report {
    val eventLogger = object : AgenticEventListener {
        override fun onEvent(event: AgenticEvent) {
            logger.info("Event: ${event::class.simpleName}")
        }
    }

    return AgentInvocation.create<Report>(agentPlatform)
        .withAgentName("data-analyzer")
        .withInput(data)
        .withGoal(Goal.of("data_analyzed"))
        .withEventListener(eventLogger)
        .withOutputChannel(consoleOutputChannel)
        .withAutonomy(Autonomy.HUMAN_IN_LOOP)
        .withTimeout(Duration.ofMinutes(5))
        .withProcessOptions(ProcessOptions.builder()
            .maxPlanningIterations(10)
            .earlyTerminationPolicy(EarlyTerminationPolicy.ON_GOAL_ACHIEVED)
            .build())
        .execute()
}

Builder Pattern

Use builder for complex invocations.

val result = AgentInvocation.builder(agentPlatform)
    .agent(myAgent)
    .input(inputData)
    .goal("process_complete")
    .autonomy(Autonomy.FULLY_AUTONOMOUS)
    .build()
    .execute()

Scoped Invocation

Invocation within an agent scope.

interface ScopedInvocation<T> : TypedInvocation<T, ScopedInvocation<T>> {
    /** Set agent scope */
    fun withScope(scope: AgentScope): ScopedInvocation<T>
}

Scoped Invocation Example:

fun executeInScope(
    scope: AgentScope,
    input: Data
): Result {
    return ScopedInvocation.create<Result>(scope)
        .withInput(input)
        .execute()
}

Supervisor Invocation

Invoke supervisor agents that coordinate multiple subagents.

interface SupervisorInvocation<T> : TypedInvocation<T, SupervisorInvocation<T>> {
    /** Add subagent to supervise */
    fun withSubagent(subagent: Subagent): SupervisorInvocation<T>

    /** Add multiple subagents */
    fun withSubagents(subagents: List<Subagent>): SupervisorInvocation<T>
}

Supervisor Example:

fun coordinateWorkflow(
    task: ComplexTask,
    agentPlatform: AgentPlatform
): WorkflowResult {
    return SupervisorInvocation.create<WorkflowResult>(agentPlatform)
        .withAgentName("workflow-supervisor")
        .withInput(task)
        .withSubagent(Subagent(dataProcessorAgent, Dataset::class.java))
        .withSubagent(Subagent(reportGeneratorAgent, Report::class.java))
        .withSubagent(Subagent(notificationAgent, Notification::class.java))
        .execute()
}

Utility Invocation

Invoke utility agents for specific tasks.

interface UtilityInvocation<T> : TypedInvocation<T, UtilityInvocation<T>>

Blackboard Configuration

Provide initial state via blackboard.

fun processWithInitialState(
    agentPlatform: AgentPlatform
): Result {
    val blackboard = Blackboard.create()
    blackboard.put("config", AppConfig(mode = "production"))
    blackboard.put("timestamp", Instant.now())

    return AgentInvocation.create<Result>(agentPlatform)
        .withAgentName("processor")
        .withBlackboard(blackboard)
        .execute()
}

Event Monitoring

Monitor agent execution with event listeners.

class ExecutionMonitor : AgenticEventListener {
    private val events = mutableListOf<AgenticEvent>()

    override fun onEvent(event: AgenticEvent) {
        events.add(event)

        when (event) {
            is ActionExecutionStartEvent ->
                logger.info("Action started: ${event.action.name}")

            is ActionExecutionResultEvent ->
                logger.info("Action completed: ${event.result}")

            is LlmRequestEvent<*> ->
                logger.info("LLM called with ${event.messages.size} messages")

            is AgentProcessCompletedEvent ->
                logger.info("Agent completed: ${event.result}")

            is AgentProcessFailedEvent ->
                logger.error("Agent failed", event.cause)
        }
    }

    fun getEventSummary(): EventSummary {
        return EventSummary(
            totalEvents = events.size,
            actionCount = events.filterIsInstance<ActionExecutionStartEvent>().size,
            llmCallCount = events.filterIsInstance<LlmRequestEvent<*>>().size
        )
    }
}

// Usage
val monitor = ExecutionMonitor()

val result = AgentInvocation.create<Report>(agentPlatform)
    .withAgentName("analyzer")
    .withInput(data)
    .withEventListener(monitor)
    .execute()

val summary = monitor.getEventSummary()
logger.info("Execution used ${summary.llmCallCount} LLM calls")

Async Execution

Execute agents asynchronously with CompletableFuture.

fun processMultipleAsync(
    orders: List<Order>,
    agentPlatform: AgentPlatform
): List<OrderResult> {
    val futures = orders.map { order ->
        AgentInvocation.create<OrderResult>(agentPlatform)
            .withAgentName("order-processor")
            .withInput(order)
            .executeAsync()
    }

    // Wait for all to complete
    return CompletableFuture.allOf(*futures.toTypedArray())
        .thenApply { futures.map { it.join() } }
        .join()
}

fun processWithCallback(
    order: Order,
    agentPlatform: AgentPlatform
) {
    AgentInvocation.create<OrderResult>(agentPlatform)
        .withAgentName("order-processor")
        .withInput(order)
        .executeAsync()
        .thenAccept { result ->
            logger.info("Order processed: ${result.orderId}")
            notificationService.notify(result)
        }
        .exceptionally { error ->
            logger.error("Order processing failed", error)
            null
        }
}

Goal-Based Invocation

Specify goals for the agent to achieve.

fun achieveGoals(
    data: Data,
    agentPlatform: AgentPlatform
): Result {
    val primaryGoal = Goal.of("data_processed", value = 1.0)
    val secondaryGoal = Goal.of("report_generated", value = 0.8)

    return AgentInvocation.create<Result>(agentPlatform)
        .withAgentName("data-processor")
        .withInput(data)
        .withGoals(listOf(primaryGoal, secondaryGoal))
        .execute()
}

Process Options

Configure agent execution behavior.

fun processWithOptions(
    task: Task,
    agentPlatform: AgentPlatform
): Result {
    val options = ProcessOptions.builder()
        .maxPlanningIterations(15)
        .maxExecutionTime(Duration.ofMinutes(10))
        .earlyTerminationPolicy(EarlyTerminationPolicy.ON_GOAL_ACHIEVED)
        .enableReplanning(true)
        .build()

    return AgentInvocation.create<Result>(agentPlatform)
        .withAgentName("task-processor")
        .withInput(task)
        .withProcessOptions(options)
        .execute()
}

Timeout Handling

Set execution timeouts.

fun processWithTimeout(
    data: Data,
    agentPlatform: AgentPlatform
): Result {
    return try {
        AgentInvocation.create<Result>(agentPlatform)
            .withAgentName("processor")
            .withInput(data)
            .withTimeout(Duration.ofSeconds(30))
            .execute()
    } catch (e: TimeoutException) {
        logger.warn("Processing timed out")
        Result.timeout()
    }
}

User Context

Provide user context for personalization and permissions.

fun processForUser(
    request: UserRequest,
    user: User,
    agentPlatform: AgentPlatform
): Response {
    return AgentInvocation.create<Response>(agentPlatform)
        .withAgentName("request-processor")
        .withInput(request)
        .withUser(user)
        .execute()
}

Types

interface AgentPlatform {
    fun getAgent(name: String): Agent?
    fun <T> executeAgent(agent: Agent, input: Any?, resultType: Class<T>): T
}

interface BaseInvocation<T> : TypedInvocation<T, BaseInvocation<T>>

interface ProcessOptions {
    val maxPlanningIterations: Int
    val maxExecutionTime: Duration
    val earlyTerminationPolicy: EarlyTerminationPolicy
    val enableReplanning: Boolean

    companion object {
        fun builder(): Builder
    }
}

enum class EarlyTerminationPolicy {
    NEVER,
    ON_GOAL_ACHIEVED,
    ON_NO_PROGRESS
}

enum class Autonomy {
    FULLY_AUTONOMOUS,
    HUMAN_IN_LOOP,
    HUMAN_APPROVAL_REQUIRED
}

interface Goal {
    val name: String
    val description: String
    val value: Double

    companion object {
        fun of(name: String, value: Double = 1.0): Goal
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-com-embabel-agent--embabel-agent-api@0.3.0

docs

actions-goals.md

agent-definition.md

builtin-tools.md

chat.md

conditions.md

events.md

human-in-the-loop.md

index.md

invocation.md

io-binding.md

llm-interaction.md

models.md

planning-workflows.md

platform-management.md

runtime-context.md

state-management.md

streaming.md

subagents.md

tools.md

type-system.md

typed-operations.md

validation.md

tile.json