Skip to content
tnsaiDocs
GitHub

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.

EventHandler nameWhen
RunStartEventagent.startedRun begins
RunEndEventagent.stoppedRun finishes
ToolCallStartEventaction.startedTool invocation begins
ToolCallEndEventaction.completedTool invocation completes
TextDeltaEventllm.responseStreaming text chunk
ThoughtEventllm.thoughtReasoning / thought
ErrorEventerror.occurredFailure during the run
StatusEventstatus.updatedProgress update
BDIUpdateEventbdi.updatedBDI state change
ArtifactEventartifact.createdArtifact created
ApprovalRequestEventapproval.requestedHuman approval required
AgentHierarchyEventagent.hierarchyHierarchy change
UiComponentEventui.componentUI component payload
SkillActivationEventskill.activation.eventSkill 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, and isFinal() 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());