Class ChartAIController

java.lang.Object
com.vaadin.flow.component.ai.chart.ChartAIController
All Implemented Interfaces:
AIController

public class ChartAIController extends Object implements AIController
AI controller for creating interactive chart visualizations from database data.

This controller provides tools that allow the LLM to query database schemas and create or update chart visualizations based on natural language requests. Attach it to an AIOrchestrator via AIOrchestrator.Builder.withController(AIController) to expose its tools to the LLM. Workflow instructions are delivered through the description of the get_chart_instructions tool, which the LLM reads as part of the tool manifest.

 var controller = new ChartAIController(chart, databaseProvider);
 AIOrchestrator orchestrator = AIOrchestrator
         .builder(llmProvider, systemPrompt).withController(controller)
         .withMessageList(messageList).build();
 

State changes requested by the LLM are deferred and applied in onResponseComplete(), avoiding partial state and multiple redraws during a multi-tool LLM turn. The chart state is stored directly on the Chart component, so it survives serialization.

If the LLM turn fails, the orchestrator fires onResponseFailed(Throwable) instead — pending changes are discarded and the chart keeps its last successfully-rendered state.

Data conversion from SQL query results to chart series is handled by a DataConverter. A default implementation is used unless overridden via setDataConverter(DataConverter).

Serialization: This controller is not serialized with the orchestrator. After deserialization, create a new controller and restore transient dependencies via reconnect(provider) .withController(controller).apply(). The chart data can be captured via getState() and re-applied via restoreState(ChartState):

 var controller = new ChartAIController(chart, databaseProvider);
 orchestrator.reconnect(llmProvider).withController(controller).apply();
 if (savedState != null) {
     controller.restoreState(savedState);
 }
 

Register a listener via addStateChangeListener(SerializableConsumer) to be notified when the chart state changes, for example to persist getState() after each successful AI request.

Provider compatibility: The chart tools use optional properties in their parameter schemas, which are incompatible with OpenAI's strict tool-calling mode (strict mode requires every property listed under properties to also appear in required). Strict tool calling is off by default in both LangChain4J and Spring AI; only users who explicitly opt in (e.g. strictTools(true) on LangChain4J's OpenAiStreamingChatModel builder) are affected.

Author:
Vaadin Ltd
See Also:
  • Constructor Details

    • ChartAIController

      public ChartAIController(com.vaadin.flow.component.charts.Chart chart, DatabaseProvider databaseProvider)
      Creates a new AI chart controller.
      Parameters:
      chart - the chart component to update, not null
      databaseProvider - the database provider for schema and query execution, not null
  • Method Details

    • setDataConverter

      public void setDataConverter(DataConverter dataConverter)
      Sets a custom data converter for transforming query results into chart series data. Replaces the default converter used to produce series points from the rows returned by the configured SQL queries.
      Parameters:
      dataConverter - the data converter to use, not null
    • getTools

      public List<LLMProvider.ToolSpec> getTools()
      Description copied from interface: AIController
      Returns the tools this controller exposes to the LLM.
      Specified by:
      getTools in interface AIController
      Returns:
      list of tools, or empty list if controller provides no tools
    • getState

      public ChartState getState()
      Returns the current chart state, including the SQL queries and configuration. Returns null if the chart has no data queries.
      Returns:
      the current state, or null
    • restoreState

      public void restoreState(ChartState state)
      Restores a previously saved chart state. Applies the configuration, sets the queries, and re-renders the chart.

      Does not fire state change listeners.

      Parameters:
      state - the state to restore, not null
    • addStateChangeListener

      public com.vaadin.flow.shared.Registration addStateChangeListener(com.vaadin.flow.function.SerializableConsumer<ChartState> listener)
      Adds a listener that is notified when the chart state changes after an AI request completes successfully. This is typically used to persist the chart state — for example by calling getState() and saving the result so that it can be reapplied with restoreState(ChartState) after deserialization.

      The listener is not fired by restoreState(ChartState).

      Parameters:
      listener - the listener, not null
      Returns:
      a registration for removing the listener
    • onResponseComplete

      public void onResponseComplete()
      Description copied from interface: AIController
      Called on the UI thread under the session lock when the LLM stream completes successfully — after all tool calls for the turn have run and the LLM has produced its final response. Use it for deferred UI updates or to commit staged state.

      Mutually exclusive with AIController.onResponseFailed(Throwable): every turn fires exactly one of the two. Exceptions thrown from the hook are caught and the user sees a generic error message; Errors propagate.

      Specified by:
      onResponseComplete in interface AIController
    • onResponseFailed

      public void onResponseFailed(Throwable error)
      Description copied from interface: AIController
      Called on the UI thread under the session lock when an LLM turn fails — stream error, timeout, or any throw between AIController.onRequestStart() and the start of the stream. Implementations should release per-turn state captured in onRequestStart (locks, pending writes, snapshots).

      Mutually exclusive with AIController.onResponseComplete(): every turn fires exactly one of the two. The default does nothing. Exceptions thrown from the hook are caught and logged; Errors propagate.

      Specified by:
      onResponseFailed in interface AIController
      Parameters:
      error - the cause of the failure (Exception or Error), never null