AgentClient API
The AgentClient
offers a fluent API for communicating with autonomous agents. It provides a familiar interface for Spring developers, following the same patterns as Spring AI’s ChatClient
.
The fluent API allows you to build up goal requests that are passed to autonomous agents. Unlike traditional chat models that process conversational prompts, autonomous agents execute goals that can involve reading files, running commands, and making code changes.
1. Creating an AgentClient
The AgentClient
is created using an AgentModel
instance. Here is a simple example showing the complete flow:
import org.springaicommunity.agents.client.AgentClient;
import org.springaicommunity.agents.client.AgentClientResponse;
import org.springaicommunity.agents.claudecode.ClaudeCodeAgentModel;
import org.springaicommunity.agents.claudecode.ClaudeCodeAgentOptions;
import org.springaicommunity.agents.claudecode.sdk.ClaudeCodeClient;
public class HelloAgentWorld {
public static void main(String[] args) {
// 1. Create the Claude Code client
ClaudeCodeClient claudeClient = ClaudeCodeClient.create();
// 2. Configure agent options
ClaudeCodeAgentOptions options = ClaudeCodeAgentOptions.builder()
.model("claude-sonnet-4-0")
.yolo(true)
.build();
// 3. Create the agent model
ClaudeCodeAgentModel agentModel = new ClaudeCodeAgentModel(claudeClient, options);
// 4. Create AgentClient
AgentClient agentClient = AgentClient.create(agentModel);
// 5. Execute a goal
AgentClientResponse response = agentClient.run(
"Create a simple Hello World Java class"
);
// 6. Use the result
System.out.println("Goal completed: " + response.isSuccessful());
System.out.println("Result: " + response.getResult());
}
}
In this example:
-
We create a
ClaudeCodeClient
that manages communication with the Claude CLI -
We configure options like the model to use and whether to allow changes (
yolo
) -
We wrap the client in a
ClaudeCodeAgentModel
for Spring AI integration -
We create an
AgentClient
using the agent model -
We run a simple goal using the
.run()
method -
We access the results and check if the goal was successful
2. Basic Usage
2.1. Simple Goal Execution
The simplest way to run a goal:
// Assuming you have an AgentClient created as shown above
AgentClientResponse response = agentClient.run("Create a Hello World Java class");
System.out.println("Result: " + response.getResult());
System.out.println("Success: " + response.isSuccessful());
3. Configuration Options
3.1. Working Directory
Set the directory where the agent operates:
// Using string path
agentClient.goal("Generate unit tests")
.workingDirectory("/home/user/my-project")
.run();
// Using Path object
Path projectPath = Paths.get(System.getProperty("user.dir"));
agentClient.goal("Generate unit tests")
.workingDirectory(projectPath)
.run();
4. Response Handling
4.1. AgentClientResponse
The response object provides access to results and metadata:
AgentClientResponse response = agentClient.run("Generate a README file");
// Check if goal completed successfully
if (response.isSuccessful()) {
String result = response.getResult();
System.out.println("Agent completed: " + result);
} else {
System.err.println("Goal failed: " + response.getResult());
}
// Access metadata
AgentResponseMetadata metadata = response.getMetadata();
Duration duration = metadata.getDuration();
String model = metadata.getModel();
4.2. Error Handling
Handle various error conditions:
try {
AgentClientResponse response = agentClient.run("Complex refactoring goal");
if (!response.isSuccessful()) {
// Goal completed but failed
System.err.println("Agent reported failure: " + response.getResult());
}
} catch (AgentExecutionException e) {
// Agent process failed to start or crashed
System.err.println("Execution error: " + e.getMessage());
} catch (AgentTimeoutException e) {
// Goal exceeded timeout
System.err.println("Goal timed out after: " + e.getTimeout());
}
5. Spring Boot Integration
5.1. Dependency Injection
Configure AgentClient as a Spring bean:
@Configuration
public class AgentConfiguration {
@Bean
public ClaudeCodeClient claudeCodeClient() {
return ClaudeCodeClient.create();
}
@Bean
public ClaudeCodeAgentModel claudeCodeAgentModel(ClaudeCodeClient client) {
ClaudeCodeAgentOptions options = ClaudeCodeAgentOptions.builder()
.model("claude-sonnet-4-0")
.yolo(false) // Safe for production
.build();
return new ClaudeCodeAgentModel(client, options);
}
@Bean
public AgentClient agentClient(ClaudeCodeAgentModel agentModel) {
return AgentClient.create(agentModel);
}
}
5.2. Controller Usage
Use in REST controllers:
@RestController
public class DevelopmentController {
private final AgentClient agentClient;
public DevelopmentController(AgentClient agentClient) {
this.agentClient = agentClient;
}
@PostMapping("/generate-tests")
public ResponseEntity<String> generateTests(@RequestBody GenerateTestsRequest request) {
try {
AgentClientResponse response = agentClient
.goal("Generate unit tests for " + request.getClassName())
.workingDirectory(request.getProjectPath())
.yolo(false) // Safe mode for production
.run();
if (response.isSuccessful()) {
return ResponseEntity.ok(response.getResult());
} else {
return ResponseEntity.badRequest().body(response.getResult());
}
} catch (Exception e) {
return ResponseEntity.status(500).body("Goal execution failed: " + e.getMessage());
}
}
}
6. Best Practices
6.1. Goal Formulation
Write clear, specific goals:
// Good: Specific and actionable
client.run("Add input validation to the UserController.createUser() method");
// Poor: Vague and ambiguous
client.run("Make the code better");
6.2. Working Directory Management
Always set appropriate working directories:
// For multi-module projects
client.goal("Generate integration tests")
.workingDirectory(projectRoot.resolve("service-module"))
.run();
6.3. Resource Management
AgentClient instances are thread-safe and can be reused:
@Component
public class CodeGenerationService {
private final AgentClient agentClient;
public CodeGenerationService(AgentClient agentClient) {
this.agentClient = agentClient;
}
// Reuse the same client instance across methods
public String generateController(String entityName) {
return agentClient.run("Generate REST controller for " + entityName).getResult();
}
public String generateTests(String className) {
return agentClient.run("Generate unit tests for " + className).getResult();
}
}
7. Advanced Features
7.1. Timeout Configuration
Configure execution timeouts:
AgentOptions options = AgentOptions.builder()
.timeout(Duration.ofMinutes(15)) // Long-running refactoring goal
.build();
client.goal("Refactor entire codebase to use reactive patterns")
.options(options)
.run();
7.2. Result Streaming
For long-running tasks, some agents support progress updates:
// Note: Streaming support varies by agent implementation
AgentClientResponse response = client
.goal("Generate comprehensive test suite")
.options(AgentOptions.builder().streaming(true).build())
.run();
// Implementation-specific streaming access
if (response instanceof StreamingAgentResponse streaming) {
streaming.getProgressUpdates().forEach(System.out::println);
}
8. Next Steps
-
Learn how AgentClient compares to ChatClient in AgentClient vs ChatClient
-
Explore agent-specific features in Claude Code SDK
-
See real-world examples in Sample Agents