The Java framework for AI agents.
Open-source, annotation-driven, on Maven Central. Twelve modules, 13 LLM providers, 62 POJO toolkits (206 @Tool methods), multi-agent coordination, MCP, and native Anthropic prompt caching.
13 LLMs · one SPI
Single LLMClient interface across providers.
Three shapes of agent code
Same builder, same lifecycle. Conversational, RAG, multi-agent.
Conversational agent
A Role declares identity and duties; AgentBuilder wires it to an LLMClient. Streaming, tool routing, history 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 pipeline.
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. Plus debate, voting, auction, negotiation, workflow DAGs.
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?");12 modules · one version
Lockstep release. Pull tnsai-bom, depend on what you use, no per-module versions.
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 specifying 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, duties, 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 four pre-flight validators at build() time — missing role, missing LLM, capability mismatches (AGENT-V001…V003) — so misconfigurations throw AgentValidationException 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