Skip to content

Composing Agents

An agent is more than just a single skill; it’s a collection of skills unified under a single identity and purpose. Radkit makes it easy to compose an agent from the skills you’ve built and run it as an A2A-compliant server.

You compose an agent using the Agent::builder(). You give the agent an ID and name, and then you add your skills to it.

use radkit::agent::{Agent, AgentDefinition, OnRequestResult, SkillHandler};
use radkit::errors::AgentResult;
use radkit::models::Content;
use radkit::runtime::context::{Context, TaskContext};
use radkit::runtime::Runtime;
// Assume ProfileExtractorSkill and ReportGeneratorSkill are defined as in previous guides
# pub struct ProfileExtractorSkill;
# #[async_trait]
# impl SkillHandler for ProfileExtractorSkill {
# async fn on_request(&self, state: &mut State, progress: &ProgressSender, runtime: &dyn Runtime, content: Content) -> AgentResult<OnRequestResult> {
# unimplemented!()
# }
# }
# pub struct ReportGeneratorSkill;
# #[async_trait]
# impl SkillHandler for ReportGeneratorSkill {
# async fn on_request(&self, state: &mut State, progress: &ProgressSender, runtime: &dyn Runtime, content: Content) -> AgentResult<OnRequestResult> {
# unimplemented!()
# }
# }
// This function defines your agent.
pub fn configure_agent() -> AgentDefinition {
Agent::builder()
.with_name("HR Assistant Agent")
.with_description("An intelligent agent for handling HR tasks like resume processing and report generation.")
// Add the skills to the agent
.with_skill(ProfileExtractorSkill)
.with_skill(ReportGeneratorSkill)
.build()
}

The Agent::builder() creates a serializable AgentDefinition. This definition is the blueprint for your agent that gets deployed.

To test your agent, you can run it locally. The runtime provides a simple, A2A-compliant web server for this purpose.

To enable the server, you must enable the runtime feature for Radkit in your Cargo.toml:

[dependencies]
radkit = { version = "0.0.2", features = ["runtime"] }
# ... other dependencies

Then, you can add a main function to run the server.

# use radkit::agent::AgentDefinition;
# use radkit::models::providers::AnthropicLlm;
# use radkit::runtime::Runtime;
# pub fn configure_agent() -> AgentDefinition { unimplemented!() }
// This main function will only be compiled for native targets, not for WASM.
#[cfg(not(all(target_os = "wasi", target_env = "p1")))]
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// 1. Create an LLM instance
let llm = AnthropicLlm::from_env("claude-sonnet-4-5-20250929")?;
// 2. Create a runtime environment with the agent + LLM
Runtime::builder(configure_agent(), llm)
.build()
.serve("127.0.0.1:8080")
.await?;
Ok(())
}

Now, run your project:

Terminal window
cargo run

Your A2A agent is now running at http://127.0.0.1:8080! You can interact with it using any A2A-compliant client.

Turn on the dev-ui feature for an interactive, browser-based playground that sits on top of the runtime: