The Java SDK uses virtual threads for background I/O. Events are delivered through a Consumer<Event> callback:
sdk.streamPrompt(params, event -> {
switch (event) {
case Events.MessageUpdateEvent mue -> System.out.print(mue.delta());
case Events.ToolStartEvent tse -> logger.info("Tool: {}", tse.toolName());
case Events.PermissionRequestEvent pre -> {
// Auto-allow read-only tools
if (pre.tool().equals("read_file") || pre.tool().equals("git_status")) {
sdk.allowPermission(pre.requestId(), DecisionScope.SESSION);
} else {
sdk.denyPermission(pre.requestId(), DecisionScope.ONCE);
}
}
default -> {}
}
});Plan mode restricts the agent to read-only planning tools:
sdk.enablePlanMode();
sdk.streamPrompt(new PromptParams("Plan this refactor"), event -> { /* ... */ });
// Review the plan, then disable plan mode to execute
sdk.disablePlanMode();Replace the entire system prompt:
AutohandSDK sdk = new AutohandSDK();
sdk.setSystemPrompt("./SYSTEM_PROMPT.md");
sdk.start();Append to the default system prompt:
sdk.appendSystemPrompt("Always run mvn verify before summarizing.");
sdk.start();Change the model at runtime:
sdk.setModel("openrouter/anthropic/claude-sonnet-4");Register hooks for extensibility:
HookDefinition hook = new HookDefinition(
HookEvent.PRE_TOOL,
"echo 'Running tool: ${HOOK_TOOL}'",
"Log tool usage",
true,
5000,
true,
null,
null
);
sdk.addHook(hook);Configure MCP servers dynamically:
McpServerConfig filesystem = new McpServerConfig(
"stdio",
"npx",
List.of("-y", "@modelcontextprotocol/server-filesystem", "/path/to/files"),
null, null, null, true
);
sdk.setMcpServers(Map.of("filesystem", filesystem));Monitor context window usage:
ContextUsage usage = sdk.getContextUsage();
System.out.println("Total: " + usage.total() + " tokens");
System.out.println("System prompt: " + usage.systemPrompt() + " tokens");The SDK uses structured exceptions:
try {
sdk.start();
} catch (IOException e) {
System.err.println("Failed to start CLI: " + e.getMessage());
}
try {
var result = agent.runJson("Return JSON", MyClass.class);
} catch (StructuredOutputError e) {
System.err.println("Invalid JSON: " + e.getMessage());
System.err.println("Raw: " + e.rawResponse());
}Keep the same agent alive across multiple prompts:
Agent agent = Agent.create(options);
try {
agent.run("First task");
agent.run("Second task");
agent.run("Third task");
} finally {
agent.close();
}Persist and resume sessions:
SDKConfig config = new SDKConfig(
".", null, false, 300_000,
null, null, null, null, null,
null, null, null, null,
null, null, null, null,
null, null, null, null, null, null,
null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null,
null, null, null, null, null,
null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null
);
// Use session settings in config