Modern AI UX — chat panels, tool-calling agents, assistants that remember context and even suggest your next step — has lived in JavaScript SaaS for years. The Java enterprise stack has been left doing it the hard way.
TabForge AI closes that gap. It's a complete platform for building AI-powered web apps on Jakarta EE + PrimeFaces — from the multi-tab UI shell down to a clean, provider-agnostic AI layer. Library, live demo, starter project, and a drop-in UI template — all shipped.
Here's the whole thing, top to bottom.
1. Tabs as annotated beans — DynTabs #
You describe a tab; the framework handles opening, closing, lifecycle, and state. Each open tab gets its own isolated CDI bean via a custom @TabScoped
scope.
@Named
@TabScoped
@DynTab(name = "OrdersDynTab", uniqueIdentifier = "Orders",
title = "Orders", includePage = "/WEB-INF/orders.xhtml",
trackActivity = true)
public class OrdersBean extends BaseDyntabCdiBean {
// open the same tab twice → two independent instances
}
java
No manual navigation, no page-state juggling. Open a tab, get a bean; close it, it's gone.
One fluent entry point over LangChain4j. Chat, tools, agents, and structured extraction — provider-agnostic, so the model behind it is a config detail.
// A typed assistant with a business service exposed as tools
OrdersAssistant ai = EasyAI.assistant(OrdersAssistant.class)
.withTools(orderService)
.build();
String reply = ai.ask("cancel order ORD-002");
You opt methods in as tools explicitly — no accidental exposure:
@EasyTool("Cancels an active order")
public String cancelOrder(String orderId) { ... }
Agents are powerful but unpredictable. When you want a repeatable, testable process, flow() lets you own the steps and call the model only at the edges that actually need language:
EasyAI.flow()
.step("understand", ctx -> EasyAI.extract(OrderRequest.class).from(ctx.inputText()))
.step("checkStock", ctx -> inventory.check(ctx.get("understand", OrderRequest.class)))
.step("place", ctx -> orders.place(ctx.get("understand", OrderRequest.class)))
.build()
.run(userText);
Your logic stays in plain Java. The LLM does one job: turn language into structure.
The framework quietly records what the user does in the app — opening a record, running a search — and makes that timeline available to the assistant. So deixis just works:
@ActivityTracked(type = BUSINESS_ACTION, verb = "view",
entityType = "order", entityIdParams = "orderId")
public String viewOrder(String orderId) { ... }
Now the user can open an order and type "cancel this" — no id — and the assistant resolves "this" from what it just
saw them do.
This is the piece you normally only see in Copilot, Gmail's Smart Compose, or Notion AI — and almost never as a first-class pattern in a Java web framework.
Built on Ambient Memory, the app can offer the next useful step before you ask. Open two orders for the same customer, and a dismissible chip appears: "Looking at several Acme orders — want a quick account summary?"
The important part: it's not a black-box agent watching you. A small, deterministic rule — plain Java you write and unit-test — decides if and what to suggest. The model only phrases the sentence.
public interface SuggestionRule {
Optional<Suggestion> evaluate(List<UserActivityEvent> recent);
}
Detect synchronously (cheap, predictable), phrase-and-push asynchronously, with a per-user cooldown so it's helpful and never naggy. Deterministic code decides; the model is reserved for the one thing it's good at.
A self-contained PrimeFaces template: responsive layout, light/dark/dim themes, a transport-agnostic AI panel (chat + live activity over SSE), a command palette, and now proactive suggestion chips. Drop-in — no build dependency.
Getting started
The fastest path is the starter — a pre-wired WAR you clone and deploy. Or add the library to an existing Jakarta EE 11+ project:
<dependency>
<groupId>io.github.tabforgeai</groupId>
<artifactId>tabforge-ai</artifactId>
<version>3.1.0</version>
</dependency>
Chat- and tools-only apps stay lean; RAG and vector-store integrations are optional add-ons you pull in only if you use them.
The philosophy
One idea runs through all of it: let deterministic code decide, and reserve the model for the irreducible — language. That's what makes AI in a serious enterprise app predictable, testable, and safe.
Proactive UX just arrived, first-class, in the Java stack.
The library
All OpenSource