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

conditions.mddocs/

Conditions

Conditions are boolean predicates that determine whether specific states are true. They are evaluated during planning to determine which actions are available and during execution to verify preconditions and postconditions.

Capabilities

Condition Definition

Define conditions that evaluate to boolean values based on context state.

@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
annotation class Condition(
    /** Name of the condition (defaults to method name) */
    val name: String = "",
    /** Cost to evaluate condition (0.0-1.0 scale) */
    val cost: ZeroToOne = 0.0
)

Basic Condition Example:

@Agent(name = "order-processor", provider = "ecommerce", description = "Processes orders")
class OrderProcessorAgent {

    @Action(
        description = "Process payment",
        pre = ["payment_info_valid", "inventory_available"]
    )
    fun processPayment(order: Order): PaymentResult {
        return paymentService.process(order)
    }

    @Condition(name = "payment_info_valid")
    fun isPaymentInfoValid(context: ActionContext): Boolean {
        val order = context.last(Order::class.java)
        return order?.paymentInfo?.isValid() == true
    }

    @Condition(name = "inventory_available")
    fun hasInventory(context: ActionContext): Boolean {
        val order = context.last(Order::class.java)
        return order?.items?.all { item ->
            inventoryService.checkStock(item.productId) >= item.quantity
        } == true
    }
}

Condition with Cost

Specify evaluation cost for expensive condition checks.

@Agent(name = "data-validator", provider = "quality", description = "Validates data quality")
class DataValidatorAgent {

    @Action(
        description = "Import dataset",
        post = ["data_imported"]
    )
    fun importData(source: DataSource): DataSet {
        return dataImporter.import(source)
    }

    @Condition(
        name = "data_quality_verified",
        cost = 0.3  // Expensive quality check
    )
    fun verifyDataQuality(context: ActionContext): Boolean {
        val dataset = context.last(DataSet::class.java) ?: return false
        // Perform expensive validation
        return qualityChecker.verify(dataset).passed
    }

    @Condition(
        name = "schema_valid",
        cost = 0.1  // Cheaper schema check
    )
    fun isSchemaValid(context: ActionContext): Boolean {
        val dataset = context.last(DataSet::class.java) ?: return false
        return dataset.schema.isValid()
    }
}

Condition Evaluation with State

Access blackboard state to evaluate conditions.

@Agent(name = "workflow-manager", provider = "automation", description = "Manages workflows")
class WorkflowManagerAgent {

    @Condition(name = "all_tasks_complete")
    fun areAllTasksComplete(context: OperationContext): Boolean {
        val workflow = context.last(Workflow::class.java) ?: return false
        return workflow.tasks.all { task ->
            task.status == TaskStatus.COMPLETED
        }
    }

    @Condition(name = "has_pending_approvals")
    fun hasPendingApprovals(context: OperationContext): Boolean {
        val approvals = context.get("pending_approvals", List::class.java)
        return !approvals.isNullOrEmpty()
    }

    @Condition(name = "deadline_approaching")
    fun isDeadlineApproaching(context: OperationContext): Boolean {
        val workflow = context.last(Workflow::class.java) ?: return false
        val hoursUntilDeadline = Duration.between(Instant.now(), workflow.deadline).toHours()
        return hoursUntilDeadline < 24
    }
}

Parameterized Conditions

Conditions can accept parameters for evaluation.

@Agent(name = "access-control", provider = "security", description = "Controls access")
class AccessControlAgent {

    @Condition(name = "user_has_permission")
    fun hasPermission(
        userId: String,
        resource: String,
        context: OperationContext
    ): Boolean {
        val user = userService.getUser(userId)
        return authService.hasPermission(user, resource)
    }

    @Condition(name = "resource_exists")
    fun resourceExists(resourceId: String): Boolean {
        return resourceRepository.exists(resourceId)
    }

    @Condition(name = "quota_available")
    fun hasQuotaAvailable(
        userId: String,
        requiredAmount: Int
    ): Boolean {
        val quota = quotaService.getQuota(userId)
        return quota.remaining >= requiredAmount
    }
}

LLM-Based Condition Evaluation

Use LLMs to evaluate complex conditions that require reasoning.

@Agent(name = "content-moderator", provider = "moderation", description = "Moderates content")
class ContentModeratorAgent {

    @Condition(name = "content_appropriate")
    fun isContentAppropriate(context: ActionContext): Boolean {
        val content = context.last(UserContent::class.java) ?: return false

        // Use LLM for nuanced content evaluation
        val evaluation = context.promptRunner()
            .thinking()
            .createObject("""
                Evaluate if this content is appropriate for a general audience:
                ${content.text}

                Consider: profanity, hate speech, violence, explicit content.
            """.trimIndent(), ContentEvaluation::class.java)

        return evaluation.content.isAppropriate
    }

    @Condition(
        name = "sentiment_positive",
        cost = 0.2  // LLM evaluation has cost
    )
    fun hasSentimentPositive(context: ActionContext): Boolean {
        val review = context.last(CustomerReview::class.java) ?: return false

        val sentiment = context.promptRunner()
            .createObject<Sentiment>(
                "Analyze sentiment of: ${review.text}"
            )

        return sentiment.score > 0.5
    }
}

data class ContentEvaluation(
    val isAppropriate: Boolean,
    val reason: String
)

data class Sentiment(
    val score: Double,
    val label: String
)

Condition in Planning

Conditions are used by the planner to determine action availability.

@Agent(
    name = "deployment-manager",
    provider = "devops",
    description = "Manages application deployments",
    planner = PlannerType.GOAP
)
class DeploymentManagerAgent {

    @Action(
        description = "Run tests",
        post = ["tests_passed"]
    )
    fun runTests(): TestResult {
        return testRunner.run()
    }

    @Action(
        description = "Build application",
        pre = ["tests_passed"],
        post = ["build_complete"]
    )
    fun buildApp(): BuildArtifact {
        return buildService.build()
    }

    @Action(
        description = "Deploy to production",
        pre = ["build_complete", "approvals_obtained", "maintenance_window_open"]
    )
    fun deployToProd(artifact: BuildArtifact): Deployment {
        return deploymentService.deploy(artifact, Environment.PRODUCTION)
    }

    @Condition(name = "tests_passed")
    fun testsHavePassed(context: OperationContext): Boolean {
        val testResult = context.last(TestResult::class.java)
        return testResult?.allPassed() == true
    }

    @Condition(name = "build_complete")
    fun buildIsComplete(context: OperationContext): Boolean {
        return context.last(BuildArtifact::class.java) != null
    }

    @Condition(name = "approvals_obtained")
    fun hasApprovals(context: OperationContext): Boolean {
        val approvals = context.get("approvals", List::class.java)
        return approvals?.size ?: 0 >= 2
    }

    @Condition(name = "maintenance_window_open")
    fun isMaintenanceWindowOpen(): Boolean {
        val now = LocalTime.now()
        return now.isAfter(LocalTime.of(2, 0)) &&
               now.isBefore(LocalTime.of(4, 0))
    }
}

Condition-Based Planning

Use conditions without explicit goals for condition-based planning.

@Agent(
    name = "incident-responder",
    provider = "ops",
    description = "Responds to incidents",
    planner = PlannerType.UTILITY
)
class IncidentResponderAgent {

    @Action(
        description = "Detect incident",
        post = ["incident_detected"]
    )
    fun detectIncident(metrics: SystemMetrics): Incident {
        return incidentDetector.analyze(metrics)
    }

    @Action(
        description = "Assess severity",
        pre = ["incident_detected"],
        post = ["severity_assessed"]
    )
    fun assessSeverity(incident: Incident): SeverityAssessment {
        return severityAnalyzer.assess(incident)
    }

    @Action(
        description = "Notify on-call team",
        pre = ["severity_assessed", "is_critical"]
    )
    fun notifyOnCall(incident: Incident): Notification {
        return notificationService.alertOnCall(incident)
    }

    @Condition(name = "incident_detected")
    fun hasIncident(context: OperationContext): Boolean {
        return context.last(Incident::class.java) != null
    }

    @Condition(name = "severity_assessed")
    fun hasSeverityAssessment(context: OperationContext): Boolean {
        return context.last(SeverityAssessment::class.java) != null
    }

    @Condition(name = "is_critical")
    fun isCritical(context: OperationContext): Boolean {
        val assessment = context.last(SeverityAssessment::class.java)
        return assessment?.level == SeverityLevel.CRITICAL
    }
}

Types

/** Type alias for values constrained to 0.0-1.0 range */
typealias ZeroToOne = Double

interface Condition {
    /** Name of the condition */
    val name: String
    /** Cost to evaluate (0.0-1.0) */
    val cost: Double
    /** Evaluate the condition given context */
    fun evaluate(context: OperationContext): Boolean
}

interface OperationContext {
    /** Get value from blackboard by key and type */
    fun <T> get(key: String, type: Class<T>): T?
    /** Get most recent value of type from blackboard */
    fun <T> last(type: Class<T>): T?
    /** Access all domain object instances */
    fun domainObjectInstances(): List<Any>
}

Install with Tessl CLI

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

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