Interface AIController


public interface AIController
Contributes tools and lifecycle hooks to an AIOrchestrator — domain-specific behaviour like populating a grid, building a chart, or filling a form from natural-language requests.

Controllers are not serialized with the orchestrator. After deserialization, restore controllers via reconnect(provider).withController(controller).apply().

Since:
25.3
Author:
Vaadin Ltd
  • Method Summary

    Modifier and Type
    Method
    Description
    Returns the tools this controller exposes to the LLM.
    default void
    Called synchronously on the UI thread just before the LLM stream opens.
    default void
    Called when the turn ends: normally when the LLM stream has completed, successfully or with an error, but also when the turn fails before a stream ever opens.
  • Method Details

    • getTools

      Returns the tools this controller exposes to the LLM.
      Returns:
      list of tools, or empty list if controller provides no tools
    • onRequest

      default void onRequest(RequestListener.RequestEvent event)
      Called synchronously on the UI thread just before the LLM stream opens. The event carries the user message, the messageId assigned to it, and the attachments included with it; it is the same event the RequestListener receives for the turn. By the time this method fires, the user message is already in the message list and the assistant is shown in its typing indicator; the turn is committed to the conversation history and the RequestListener only after this method returns successfully. Implementations can prepare for the turn — locking UI surfaces, snapshotting state the tool definitions depend on, and so on. Since tools may execute on a background thread, this is the moment to capture any state that depends on Vaadin thread locals such as UI.getCurrent() or VaadinSession.getCurrent().

      The default does nothing. Throwing from this method aborts the turn before the commit step: the conversation history is unchanged, the request listener is not notified, the LLM stream is not opened, the assistant message shows a generic error message, onResponse(ResponseListener.ResponseEvent) fires with the thrown exception so per-turn state captured before the throw can still be released, and the exception propagates back to the caller of the prompt entry point.

      Parameters:
      event - the request being submitted — user message, message id, and attachments — never null
    • onResponse

      default void onResponse(ResponseListener.ResponseEvent event)
      Called when the turn ends: normally when the LLM stream has completed, successfully or with an error, but also when the turn fails before a stream ever opens. The call runs through ui.access(), so the session lock is held and Vaadin thread locals are bound — though not necessarily on a request thread.

      Fires at most once per prompt. A prompt rejected by the RequestInterceptor ends without firing it, as does a postponed prompt abandoned because its UI was detached. A turn whose UI is detached when it ends also skips the hook, which requires ui.access().

      On success ResponseListener.ResponseEvent.getError() is empty; use the call to commit staged state or run deferred UI updates. On failure it carries the cause (stream error, timeout, or any throw on the prompt path before the stream opens); release per-turn state captured in onRequest (locks, pending writes, snapshots) and discard the staged work. Note that a failure before onRequest(RequestListener.RequestEvent) — for example a throwing RequestInterceptor — also fires this method, so it can run without a preceding onRequest call.

      An error is not the only abnormal ending. A turn cut off at the model's output limit ends with no error at all, and ResponseListener.ResponseEvent.getMetadata() carries the finish reason that tells the two apart — committing staged state on such a turn applies work the model never finished describing. The finish reason is the underlying framework's own word, so a controller that acts on it decides which values matter to it; see ResponseMetadata.

      The default does nothing. Exceptions thrown from the hook are caught and logged; Errors propagate.

      Parameters:
      event - the outcome of the turn — response text, error, and provider metadata — never null