Advanced Agent Features
Beyond the basic Agent lifecycle (create, chat, stop), TnsAI.Core provides specialized subsystems for cognitive support, streaming, ensemble execution, hierarchy management, and chat orchestration. These are internal components extracted from the Agent class for cohesion; most are accessed through the Agent public API rather than directly.
AgentCognitiveSupport
com.tnsai.agents.AgentCognitiveSupport holds planning, reasoning, evaluation, environment perception, and feedback collection for an Agent. It is created internally during agent construction and accessed through AgentCapabilities.
Evaluation Hooks
Eval hooks fire at lifecycle points (before/after chat, before/after tool call, on error, on agent stop) and record metrics into an EvalContext.
// Add an evaluation hook
agent.addEvalHook(myHook);
// Enable/disable evaluation
agent.setEvalEnabled(true);
// Record goal completion
agent.recordGoalCompletion("goal-1", true, Map.of("steps", 3));Key methods on AgentCognitiveSupport:
| Method | Description |
|---|---|
addEvalHook(EvalHook hook) | Register an eval hook |
removeEvalHook(EvalHook hook) | Unregister an eval hook |
clearEvalContext() | Create a fresh EvalContext with new session ID |
setEvalEnabled(boolean) | Enable or disable all eval hooks |
isEvalEnabled() | Check if evaluation is active |
recordGoalCompletion(String goalId, boolean success, Map<String, Object> details) | Record a goal outcome |
fireOnBeforeChat(String message) | Fire pre-chat eval event |
fireOnAfterChat(String result, long latencyMs) | Fire post-chat eval event |
fireOnBeforeToolCall(String toolName, Map<String, Object> arguments) | Fire pre-tool eval event |
fireOnAfterToolCall(String toolName, Object result, boolean success, long latencyMs) | Fire post-tool eval event |
fireOnAgentStop(String status) | Fire agent stop event and complete the eval context |
Planning (BDI)
Planning uses a PlannerHandle (SPI, provided by tnsai-intelligence) for GOAP/HTN planning.
// Set a planner
agent.setPlannerHandle(myPlanner);
// Plan for all goals
List<PlannerHandle.PlanStep> steps = agent.plan();
// Plan for a specific goal
List<PlannerHandle.PlanStep> steps = agent.planForGoal("deliverPackage");
// Execute a plan
PlannerHandle.PlanResult result = agent.executePlan(steps);Key methods on AgentCognitiveSupport:
| Method | Signature |
|---|---|
plan | List<PlanStep> plan(List<Role> roles) |
planForGoal | List<PlanStep> planForGoal(String goalName, List<Role> roles) |
executePlan | PlanResult executePlan(List<PlanStep> steps, List<Role> roles) |
extractCurrentState | Map<String, Object> extractCurrentState(List<Role> roles) |
setPlannerHandle | void setPlannerHandle(PlannerHandle handle) |
getPlannerHandle | Optional<PlannerHandle> getPlannerHandle() |
isPlanningEnabled | boolean isPlanningEnabled() |
Reasoning Strategy
Reasoning strategies (ReAct, Tree-of-Thought, etc.) are pluggable via ReasoningStrategyHandle.
agent.setReasoningStrategy(reactStrategy);
// After chat, inspect reasoning
Optional<ReasoningResult> result = agent.getLastReasoningResult();When reasoning is enabled, AgentOrchestrator.chat() routes through the strategy instead of direct LLM invocation.
Environment Perception
Agents can perceive and act on environments (BDI perception-to-belief pipeline).
agent.setEnvironment(myEnvironment);
Percept percept = agent.perceive();
ActionOutcome outcome = agent.actOnEnvironment("moveForward", Map.of("speed", 5));Environment changes trigger onEnvironmentChangeWithRoles, which checks for unsatisfied goals if a planner is configured.
Feedback Collection
FeedbackCollector (SPI, provided by tnsai-intelligence) records tool outcomes for preference learning.
agent.setFeedbackCollector(myCollector);
FeedbackCollector collector = agent.getFeedbackCollector();Tool outcomes are recorded automatically via recordToolOutcome(toolName, result, success, latencyMs).
AgentEnsembleExecutor
com.tnsai.agents.ensemble.AgentEnsembleExecutor provides multi-LLM ensemble operations accessed via agent.getEnsembleExecutor().
Patterns
| Method | Signature | Description |
|---|---|---|
parallelChat | ParallelResults parallelChat(String message, List<LLMClient> llms) | Fan out to all LLMs, collect all responses |
raceChat | Optional<LLMResult> raceChat(String message, List<LLMClient> llms, long timeoutSeconds) | First successful response wins |
consensusChat | Optional<LLMResult> consensusChat(String message, List<LLMClient> llms, Function<String, Double> scorer) | Score responses, pick highest |
majorityVoteChat | Optional<LLMResult> majorityVoteChat(String message, List<LLMClient> llms) | Most common response pattern |
ensembleChat | Optional<String> ensembleChat(String message, List<LLMClient> llms, LLMClient aggregator) | Synthesize responses with aggregator LLM |
// Fan-out to multiple LLMs
ParallelLLM.ParallelResults results = agent.getEnsembleExecutor()
.parallelChat("Explain quantum computing", List.of(gpt4, claude, gemini));
// Race: first response wins
Optional<ParallelLLM.LLMResult> fastest = agent.getEnsembleExecutor()
.raceChat("Quick question", List.of(gpt4, claude), 10);
// Consensus with scoring
Optional<ParallelLLM.LLMResult> best = agent.getEnsembleExecutor()
.consensusChat("Review this code", llms, response -> scoreQuality(response));
// Ensemble synthesis
Optional<String> synthesized = agent.getEnsembleExecutor()
.ensembleChat("Complex analysis", List.of(gpt4, claude), aggregatorLLM);AgentHierarchyManager
com.tnsai.agents.hierarchy.AgentHierarchyManager manages parent-child relationships between agents, including bidirectional consistency and task delegation/escalation.
Hierarchy Setup
Agent supervisor = new SupervisorAgent();
Agent developer = new DeveloperAgent();
Agent tester = new TesterAgent();
// Bidirectional parent-child links
supervisor.addChild(developer);
supervisor.addChild(tester);
// developer.getParent() == supervisor
// supervisor.getChildren() contains both
// Add multiple at once
supervisor.addChildren(developer, tester, designer);Task Delegation and Escalation
// Supervisor delegates to child
supervisor.delegateToChild(developer.id(), "writeCode", Map.of(
"task", "Implement authentication",
"language", "Java"
));
// Developer escalates to supervisor
developer.escalateToParent("requestApproval", Map.of(
"reason", "Production deployment requires sign-off"
));Both methods use AgentCommunicationManager to send TaskMessageType.REQUEST messages. delegateToChild throws NoSuchElementException if the child is not found; escalateToParent throws IllegalStateException if no parent is set.
HierarchyContext Interface
The manager uses a HierarchyContext interface (implemented by Agent) to access internals:
public interface HierarchyContext {
String getAgentId();
Agent getAgentRef();
Agent getParentRef();
void setParentRef(Agent parent);
List<Agent> getChildrenSnapshot();
boolean hasChild(Agent child);
boolean addChildDirect(Agent child);
boolean removeChildDirect(Agent child);
Agent findChildById(String childId);
AgentCommunicationManager getCommunicationManager();
}AgentStreamingSupport
com.tnsai.agents.streaming.AgentStreamingSupport handles streaming and event-based chat operations.
Token Streaming
// Stream tokens as a Java Stream
Stream<String> tokens = agent.streamChat("Tell me about Java");
tokens.forEach(System.out::print);Streaming with Tool Calls
The streamChatWithTools method combines streaming with multi-turn tool execution (up to 10 iterations):
agent.streamChatWithTools("Search for TnsAI docs", chunk -> {
if (chunk.isContent()) {
System.out.print(chunk.getContent());
} else if (chunk.isToolCall()) {
System.out.println("Tool: " + chunk.getToolCall().get().getName());
}
});Flow: stream LLM response -\> if tool calls received, execute them -\> send results back to LLM -\> repeat until final text or max iterations (10).
Event-Based Chat (AG-UI)
// With direct event consumer
agent.chatWithEvents("Hello", event -> {
if (event instanceof TextDeltaEvent delta) {
System.out.print(delta.getText());
} else if (event instanceof ToolCallStartEvent tc) {
System.out.println("Calling: " + tc.getToolName());
}
});
// With session-based publisher
agent.chatWithEvents("Hello", sessionId);Events emitted: RunStartEvent, StatusEvent, TextDeltaEvent, ToolCallStartEvent, ToolCallEndEvent, ErrorEvent, RunEndEvent.
AgentChatOrchestrator
com.tnsai.agents.chat.AgentChatOrchestrator handles LLM invocation, response processing, structured output, and RAG augmentation.
LLM Invocation
// Full control
Object response = chatOrchestrator.invokeLLM(message, useHistory, useTools, trace);
// Process response (handles text and tool calls)
String result = chatOrchestrator.processLLMResponse(response, useHistory);Structured Output (Guardrails Pattern)
// With custom parser
MyOutput output = agent.chatWithStructure(
"Extract the key points",
new MyOutputParser(),
3 // maxRetries for correction
);
// With format detection (JSON, YAML, TOML)
MyRecord record = agent.chatWithFormat("Generate config", MyRecord.class, 2);
// With explicit format
MyRecord record = agent.chatWithFormat("Generate config", MyRecord.class, OutputFormat.YAML, 2);The orchestrator detects output format from @OutputFormatSpec on the target class or agent class, defaulting to JSON.
RAG (Knowledge Base Augmentation)
When a KnowledgeBase is set on the agent, the orchestrator automatically augments user messages with relevant knowledge results before sending to the LLM:
agent.setKnowledgeBase(myKnowledgeBase);
agent.setKnowledgeBaseTopK(5);
// Messages are now automatically augmented with knowledge context
agent.chat("What is our refund policy?");AgentOrchestrator
com.tnsai.agents.orchestration.AgentOrchestrator is the top-level coordinator that wires together AgentToolExecutor, AgentChatOrchestrator, AgentStreamingSupport, and AgentEnsembleExecutor. It implements the context interfaces for all three sub-delegates so they can access agent internals without circular dependencies.
Key Public Methods
| Method | Description |
|---|---|
chat(String message, boolean useHistory, boolean useTools) | Main chat entry point with eval hooks and context graph tracing |
streamChat(String message) | Token-by-token streaming |
streamChatWithTools(String message, Consumer<ChatChunk> handler) | Streaming with tool calling loop |
chatWithEvents(String message, Consumer<TnsAIEvent> consumer) | Event-based chat |
chatWithEvents(String message, String sessionId) | Event-based chat with session publisher |
executeActionPublic(String name, Map<String, Object> params) | Execute a named action |
executeActionTyped(ActionRequest request) | Execute with typed request/response |
executeActionOnRole(String roleId, String name, Map<String, Object> params) | Execute on a specific role |
setToolCallFilter(ToolCallFilter filter) | Set permission control for tool calls |
setToolCallListener(ToolCallListener listener) | Set progress callbacks |
setKnowledgeBase(KnowledgeBase kb) | Set RAG knowledge base |
shutdown() | End context conversations |
Context Graph Integration
When context graph is enabled, the orchestrator automatically:
- Starts/ends context conversations around chat sessions
- Creates snapshots at conversation boundaries
- Records
DecisionTraceentries for each chat (success or failure)
AgentCapabilities
com.tnsai.agents.capabilities.AgentCapabilities is the capability facade that bridges cognitive support, resilience, variants, and context graphs. Agent delegates to this class for all capability operations.
Variant Selection
agent.setVariant(AgentVariant.HIGH);
AgentVariant current = agent.getVariant();
// Auto-resolve based on task
AgentVariant resolved = agent.resolveVariant("Complex refactoring task");
// Custom selector
agent.setVariantSelector(mySelector);Context Graph
agent.enableContextGraph(snapshotStore, decisionTraceStore);
Optional<ContextManagerHandle> cm = agent.getContextManager();
boolean enabled = agent.isContextGraphEnabled();Resilience
AgentHealthState health = agent.getHealthState();
ResilienceExecutor executor = agent.getResilienceExecutor();
RetryPolicy policy = agent.getDefaultRetryPolicy();
DeadLetterQueue dlq = agent.getDeadLetterQueue();
agent.clearRecoveryState();Related Documentation
Schema, Identity, and Enums
TnsAI.Core provides typed schemas for LLM tool definitions, agent identity and communication style modeling, decentralized identifiers (DIDs), and a set of enums that control agent behavior.
Capabilities
Pluggable building blocks that give an agent power beyond raw LLM calls.