the java framework for ai agents
Open-source and annotation-driven, on Maven Central. 13 modules, 31 LLM providers behind one LLMClient SPI, 62 tool kits (200+ @Tool methods), multi-agent coordination, MCP, and native Anthropic prompt caching.
three shapes of agent code
Same builder, same lifecycle — conversational, retrieval-augmented, and a multi-agent council.
conversational agent
A Role declares identity and duties; AgentBuilder wires it to an LLMClient. Streaming, tool routing, and history are built in.
read the docs// AssistantRole extends Role — identity + dutiesAgent agent = AgentBuilder.create() .role(new AssistantRole()) .llm(AnthropicClient.builder() .model("claude-sonnet-4").build()) .build(); agent.start();String reply = agent.chat("Hi!");rag over your docs
HybridRAGStrategy fuses BM25 keyword search with vector retrieval. RAGPipeline composes the full retrieve-then-generate flow.
read the docs// Hybrid = BM25 + vector storeRAGStrategy strategy = new HybridRAGStrategy( new BM25Index(corpus), vectorStore); RAGPipeline pipeline = RAGPipeline .builder(strategy).build(); String answer = pipeline.execute( "What is BDI?");multi-agent council
CouncilExecutor runs Karpathy's 3-stage llm-council — parallel deliberation and a skeptical chair, not a role-play pipeline.
read the docs// Karpathy 3-stage llm-councilCouncilExecutor council = CouncilExecutor.builder() .members(List.of(gpt4, claude, gemini)) .chairman(gemini) .anonymize(true) .build(); CouncilResult r = council.deliberate( "How should we architect auth?");13 modules · one version
Lockstep release. Pull tnsai-bom, depend on what you use — no per-module version juggling.
apache-2.0 · maven central · BOM-pinned · JDK 21+. each module ships as io.github.tansuasici:tnsai-*:0.12.0.
three steps
add the bom
One Maven import pins every tnsai-* module to the same version. Depend on what you use without naming versions twice.
<dependencyManagement> <dependency> <groupId>io.github.tansuasici</groupId> <artifactId>tnsai-bom</artifactId> <version>0.12.0</version> <type>pom</type><scope>import</scope> </dependency></dependencyManagement>define a role
A role extends Role and declares its identity and actions. @ActionSpec methods become tools the agent can call; @Param maps tool arguments to method parameters.
public class ResearcherRole extends Role { @Override public RoleIdentity getIdentity() { return new RoleIdentity("researcher", "Find academic papers", "research"); } @ActionSpec(type = ActionType.LOCAL) public List<Paper> search(@Param(name="q") String q) { return arxiv.find(q); }}build, start, chat
AgentBuilder runs pre-flight validators at build() time — missing role, missing LLM, capability mismatches — so misconfigurations throw before the first message goes out.
Agent agent = AgentBuilder.create() .role(new ResearcherRole()) .llm(AnthropicClient.builder() .model("claude-sonnet-4") .withPromptCaching() // −75% input cost .build()) .build(); // throws on misconfig agent.start();String reply = agent.chat("Find papers on RAG eval.");need more depth? installation guide · agent concepts · quickstart