Events
An agent run publishes events: run start and end, tool calls, text deltas, errors and more. Every event is a record in the sealed TnsAIEvent hierarchy in com.tnsai.events, so the set of types is fixed.
Subscribe for one chat turn
Pass a Consumer<TnsAIEvent> to chatWithEvents. The callback receives every event the turn publishes.
String response = agent.chatWithEvents("Do research on AI", event -> {
switch (event) {
case RunStartEvent e -> log.info("Agent run started");
case ToolCallStartEvent e -> log.info("Tool: {}", e.toolName());
case ToolCallEndEvent e -> log.info("Result: {}", e.result());
case TextDeltaEvent e -> log.debug("Delta: {}", e.content());
case ErrorEvent e -> log.error("Error: {}", e.message());
case RunEndEvent e -> log.info("Run completed");
default -> {}
}
});Event types
The left column is the type you match on. The right column is the name an @EventHandler method subscribes to.
| Event | Handler name | When |
|---|---|---|
RunStartEvent | agent.started | Run begins |
RunEndEvent | agent.stopped | Run finishes |
ToolCallStartEvent | action.started | Tool invocation begins |
ToolCallEndEvent | action.completed | Tool invocation completes |
TextDeltaEvent | llm.response | Streaming text chunk |
ThoughtEvent | llm.thought | Reasoning / thought |
ErrorEvent | error.occurred | Failure during the run |
StatusEvent | status.updated | Progress update |
BDIUpdateEvent | bdi.updated | BDI state change |
ArtifactEvent | artifact.created | Artifact created |
ApprovalRequestEvent | approval.requested | Human approval required |
AgentHierarchyEvent | agent.hierarchy | Hierarchy change |
UiComponentEvent | ui.component | UI component payload |
SkillActivationEvent | skill.activation.event | Skill activated |
A recoverable failure is an ErrorEvent with recoverable() == true.
Tool and streaming accessors
ToolCallStartEvent:toolCallId(),toolName(),arguments().ToolCallEndEvent:toolCallId(),toolName(),result(),success(),error(),durationMs().TextDeltaEvent:content()is the chunk, andisFinal()marks the last chunk of that message.
Publish and subscribe on a session
TnsAIEventPublisher.publish takes a session id and one of the event records above.
TnsAIEventPublisher publisher = agent.getEventPublisher();
publisher.publish(sessionId, TextDeltaEvent.of("msg-1", "Hello"));agent.chatWithEvents(message, sessionId) publishes the turn's events onto that session. To listen on the same bus:
publisher.subscribe(sessionId, event -> log.info("{}", event.eventType()));Handle events with annotations
Agent registers @EventHandler methods from the agent and its roles. The event attribute is the handler name from the table.
@EventHandler(event = "action.completed")
public void onToolComplete(ToolCallEndEvent event) {
log.info("Tool {} took {}ms", event.toolName(), event.durationMs());
}To route a session's events to those handlers, subscribe the agent's registry:
EventHandlerRegistry registry = agent.getEventHandlerRegistry();
publisher.subscribe(sessionId, registry.asEventConsumer());Related
- Streaming: text deltas as they arrive.
- Create an agent: the chat methods.
- Monitor: traces and metrics built on these events.