CtrlK
CommunityDocumentationLog inGet started
Tessl Logo

tessl/maven-com-embabel-agent--embabel-agent-a2a

A2A protocol integration for Embabel Agent Framework enabling agent-to-agent communication

Overview
Eval results
Files

configuration.mddocs/api/

Configuration API

Spring Boot auto-configuration for A2A endpoints.

A2AConfiguration

Main configuration class providing default AgentCardHandler bean.

/**
 * Spring Boot auto-configuration for A2A support.
 * Automatically creates AgentCardHandler bean when module is on classpath.
 */
@Configuration
class A2AConfiguration {

    /**
     * Creates default AgentCardHandler bean.
     * Exposes A2A endpoint at path "a2a" with all goals.
     *
     * @param agentPlatform Embabel agent platform
     * @param a2aMessageHandler Request handler implementation
     * @return AgentCardHandler instance
     */
    @Bean
    fun defaultAgentCardHandler(
        agentPlatform: AgentPlatform,
        a2aMessageHandler: AutonomyA2ARequestHandler
    ): AgentCardHandler
}

Default Implementation:

return EmbabelServerGoalsAgentCardHandler(
    path = "a2a",
    agentPlatform = agentPlatform,
    a2ARequestHandler = a2aMessageHandler,
    goalFilter = { true }  // Expose all goals
)

Auto-Configuration

Simply include the module as dependency:

Maven:

<dependency>
    <groupId>com.embabel.agent</groupId>
    <artifactId>embabel-agent-a2a</artifactId>
    <version>0.3.3</version>
</dependency>

Gradle:

implementation("com.embabel.agent:embabel-agent-a2a:0.3.3")

Automatic Setup:

  1. Spring Boot scans and loads A2AConfiguration
  2. Creates default AgentCardHandler bean
  3. A2AEndpointRegistrar registers web endpoints
  4. Endpoints exposed at application startup

Default Endpoints:

  • GET /a2a/.well-known/agent.json
  • POST /a2a

Override Default Configuration

Replace default bean with custom configuration:

@Configuration
class CustomA2AConfiguration {

    @Bean
    fun defaultAgentCardHandler(
        agentPlatform: AgentPlatform,
        a2aRequestHandler: AutonomyA2ARequestHandler
    ): AgentCardHandler {
        return EmbabelServerGoalsAgentCardHandler(
            path = "my-agent",
            agentPlatform = agentPlatform,
            a2ARequestHandler = a2aRequestHandler,
            goalFilter = { goal -> goal.tags.contains("external") }
        )
    }
}

Multiple Endpoints

Define multiple AgentCardHandler beans:

@Configuration
class MultiEndpointConfiguration {

    @Bean
    fun publicEndpoint(
        agentPlatform: AgentPlatform,
        a2aRequestHandler: AutonomyA2ARequestHandler
    ): AgentCardHandler {
        return EmbabelServerGoalsAgentCardHandler(
            path = "a2a-public",
            agentPlatform = agentPlatform,
            a2ARequestHandler = a2aRequestHandler,
            goalFilter = { goal -> goal.tags.contains("public") }
        )
    }

    @Bean
    fun internalEndpoint(
        agentPlatform: AgentPlatform,
        a2aRequestHandler: AutonomyA2ARequestHandler
    ): AgentCardHandler {
        return EmbabelServerGoalsAgentCardHandler(
            path = "a2a-internal",
            agentPlatform = agentPlatform,
            a2ARequestHandler = a2aRequestHandler,
            goalFilter = { goal -> goal.tags.contains("internal") }
        )
    }
}

// Creates endpoints:
// - /a2a-public/.well-known/agent.json and /a2a-public
// - /a2a-internal/.well-known/agent.json and /a2a-internal

Conditional Configuration

Profile-Based

@Configuration
@Profile("a2a")
class A2AProfileConfiguration {

    @Bean
    fun agentCardHandler(
        agentPlatform: AgentPlatform,
        a2aRequestHandler: AutonomyA2ARequestHandler
    ): AgentCardHandler {
        return EmbabelServerGoalsAgentCardHandler(
            path = "a2a",
            agentPlatform = agentPlatform,
            a2ARequestHandler = a2aRequestHandler,
            goalFilter = { true }
        )
    }
}

// Enable with: --spring.profiles.active=a2a

Property-Based

@Configuration
@ConditionalOnProperty(
    prefix = "embabel.a2a",
    name = ["enabled"],
    havingValue = "true"
)
class ConditionalA2AConfiguration {

    @Bean
    fun agentCardHandler(
        agentPlatform: AgentPlatform,
        a2aRequestHandler: AutonomyA2ARequestHandler
    ): AgentCardHandler {
        return EmbabelServerGoalsAgentCardHandler(
            path = "a2a",
            agentPlatform = agentPlatform,
            a2ARequestHandler = a2aRequestHandler,
            goalFilter = { true }
        )
    }
}

application.yml:

embabel:
  a2a:
    enabled: true

Configuration Properties

Custom Path

@Configuration
class PathConfiguredA2A {

    @Value("\${a2a.endpoint.path:a2a}")
    private lateinit var endpointPath: String

    @Bean
    fun agentCardHandler(
        agentPlatform: AgentPlatform,
        a2aRequestHandler: AutonomyA2ARequestHandler
    ): AgentCardHandler {
        return EmbabelServerGoalsAgentCardHandler(
            path = endpointPath,
            agentPlatform = agentPlatform,
            a2ARequestHandler = a2aRequestHandler,
            goalFilter = { true }
        )
    }
}

application.yml:

a2a:
  endpoint:
    path: my-agent-endpoint

Goal Filter by Tags

@Configuration
class FilterConfiguredA2A {

    @Value("\${a2a.goal.tags:}")
    private lateinit var allowedTags: String

    @Bean
    fun agentCardHandler(
        agentPlatform: AgentPlatform,
        a2aRequestHandler: AutonomyA2ARequestHandler
    ): AgentCardHandler {
        val tagSet = allowedTags.split(",").map { it.trim() }.toSet()

        return EmbabelServerGoalsAgentCardHandler(
            path = "a2a",
            agentPlatform = agentPlatform,
            a2ARequestHandler = a2aRequestHandler,
            goalFilter = { goal ->
                tagSet.isEmpty() || goal.tags.any { it in tagSet }
            }
        )
    }
}

application.yml:

a2a:
  goal:
    tags: public,external,partner

Required Dependencies

A2AConfiguration depends on these Spring beans:

AgentPlatform

@Bean
fun agentPlatform(): AgentPlatform {
    // Provided by embabel-agent-core
}

AutonomyA2ARequestHandler

@Service
class AutonomyA2ARequestHandler(
    private val autonomy: Autonomy,
    private val agenticEventListener: AgenticEventListener,
    private val streamingHandler: A2AStreamingHandler
) : A2ARequestHandler
// Automatically provided by embabel-agent-a2a

Bean Creation Order

  1. Core Services: TaskStateManager, A2AStreamingHandler
  2. Request Handler: AutonomyA2ARequestHandler
  3. Configuration: A2AConfiguration creates AgentCardHandler beans
  4. Endpoint Registration: A2AEndpointRegistrar registers web endpoints

Security Integration

@Configuration
@EnableWebSecurity
class SecurityConfiguration {

    @Bean
    fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http.authorizeHttpRequests { auth ->
            auth
                // Public AgentCard
                .requestMatchers("/a2a/.well-known/agent.json").permitAll()
                // Secured JSON-RPC
                .requestMatchers("/a2a").authenticated()
                .anyRequest().permitAll()
        }.httpBasic()

        return http.build()
    }
}

Testing Configuration

@SpringBootTest
class A2AConfigurationTest {

    @Autowired
    lateinit var agentCardHandler: AgentCardHandler

    @Test
    fun `should create default agent card handler`() {
        assertNotNull(agentCardHandler)
        assertEquals("a2a", agentCardHandler.path)
    }

    @Test
    fun `should generate agent card`() {
        val card = agentCardHandler.agentCard("http", "localhost", 8080)
        assertEquals("http://localhost:8080/a2a", card.url)
        assertTrue(card.capabilities.streaming)
    }
}

Troubleshooting

AgentCardHandler Not Created

Issue: No AgentCardHandler beans found

Solution: Ensure component scanning includes A2A package:

@SpringBootApplication
@ComponentScan(basePackages = [
    "com.embabel.agent.a2a",
    "your.application.package"
])
class Application

Multiple Handlers Conflict

Issue: Multiple handlers with same path

Solution: Ensure unique paths:

@Bean
fun handler1(...): AgentCardHandler =
    EmbabelServerGoalsAgentCardHandler(path = "a2a-1", ...)

@Bean
fun handler2(...): AgentCardHandler =
    EmbabelServerGoalsAgentCardHandler(path = "a2a-2", ...)

Endpoints Not Registered

Issue: Endpoints unavailable after startup

Solution: Check logs for A2AEndpointRegistrar messages:

INFO  c.e.a.a.s.A2AEndpointRegistrar - Registering 1 A2A endpoints
INFO  c.e.a.a.s.A2AEndpointRegistrar - Registering web endpoint under /a2a/.well-known/agent.json

See Also

  • AgentCard API - AgentCard handler interface
  • Endpoint Registration API - Dynamic endpoint setup
  • Common Tasks - Configuration examples
  • Troubleshooting - Configuration issues
tessl i tessl/maven-com-embabel-agent--embabel-agent-a2a@0.3.3

docs

api

agent-card.md

configuration.md

endpoint-registration.md

events.md

overview.md

request-handling.md

skill-factory.md

streaming.md

task-state.md

index.md

tile.json