Class LlmDataSetGenerationSupport

java.lang.Object
io.jmix.reportsflowui.support.LlmDataSetGenerationSupport

@NullMarked @Component("report_LlmDataSetGenerationSupport") public class LlmDataSetGenerationSupport extends Object
Serves the designer's side of the DataSetType.LLM data set type: whether the type can be authored here, what a query may be generated from, and how a query is stored.

The UI module needs no dependency on the AI Tools add-on for this: the type can be authored when an LlmDataQueryService bean exists, and its query can be generated when that bean also reports generation as available. Reports auto-configuration supplies the default bean on top of the add-on's data-load services, and an application may substitute another implementation of the seam. Running a data set needs neither.

  • Field Details

    • llmDataQueryServiceProvider

      @Autowired protected org.springframework.beans.factory.ObjectProvider<LlmDataQueryService> llmDataQueryServiceProvider
    • llmDataQuerySerializer

      @Autowired protected LlmDataQuerySerializer llmDataQuerySerializer
    • parameterClassResolver

      @Autowired protected ParameterClassResolver parameterClassResolver
  • Constructor Details

    • LlmDataSetGenerationSupport

      public LlmDataSetGenerationSupport()
  • Method Details

    • isTypeSupported

      public boolean isTypeSupported()
      Tells whether this application is one where such a data set can be authored: an implementation of the seam has to be there to turn a prompt into a query and to check one. Running a data set needs none of that — a report authored elsewhere runs here either way — and generating a query needs more than that, see isGenerationAvailable().
      Returns:
      true if the data set type can be authored in this application
    • isGenerationAvailable

      public boolean isGenerationAvailable()
      Tells whether a query can be generated in this application: an implementation of the seam has to be there and report generation as available. Reports may auto-configure the default implementation when the add-on's data-load beans exist even though the model needed by generation is not configured — a data set can then still be edited and run, but not generated anew.
      Returns:
      true if queries can be generated
    • createGenerationRequest

      public LlmQueryGenerationRequest createGenerationRequest(DataSet dataSet)
      Describes what a query for this data set may be generated from: its prompt and the parameters the query is allowed to reference.
      Parameters:
      dataSet - data set whose prompt is being turned into a query
      Returns:
      the request to pass to generate(LlmQueryGenerationRequest)
    • isGenerationRequestCurrent

      public boolean isGenerationRequestCurrent(DataSet dataSet, LlmQueryGenerationRequest request)
      Checks whether the inputs from which a request was built still describe the data set. Parameter values are deliberately ignored: the designer only exposes their names, types and cardinality to generation.
      Parameters:
      dataSet - data set whose current generation inputs are checked
      request - request captured when generation started
      Returns:
      true if completing the request would still answer the current data set state
    • sameParameterDeclarations

      protected boolean sameParameterDeclarations(List<LlmQueryParameter> left, List<LlmQueryParameter> right)
    • generate

      public LlmDataQuery generate(LlmQueryGenerationRequest request)
      Generates a query. Runs the LLM, so callers are expected to do this in a background task.
      Parameters:
      request - prompt together with the parameters the query may reference
      Returns:
      the generated query
      Throws:
      LlmDataQueryException - if the query cannot be generated
    • validate

      public List<String> validate(LlmDataQuery query)
      Reports what makes a query unrunnable, so that an author is told about a broken query while looking at it. Nothing is reported when the AI Tools add-on is absent: there is nothing to check the query with, and nothing to run it with either.
      Parameters:
      query - query to check
      Returns:
      one message per problem, or an empty list if the query is runnable
    • storeGeneratedQuery

      public void storeGeneratedQuery(DataSet dataSet, LlmDataQuery query)
      Stores a generated query in the data set, so that report runs execute it instead of generating anew.
      Parameters:
      dataSet - data set to store the query in
      query - query to store
    • storeEditedQuery

      public void storeEditedQuery(DataSet dataSet, String jpql, List<String> resultProperties)
      Stores a query being edited by hand: parameters are re-derived from the text, and the previous document's explanation and warnings are carried over (LlmDataQuerySerializer.assemble(java.lang.String, java.util.List<java.lang.String>, io.jmix.reports.llm.LlmDataQuery)). Blank text is left alone — an empty editor is a query on its way to being retyped; dropping one is finishEditedQuery(DataSet, String, List)'s job.
      Parameters:
      dataSet - data set to store the query in
      jpql - query text as edited
      resultProperties - column names in select-clause order
    • finishEditedQuery

      public void finishEditedQuery(DataSet dataSet, String jpql, List<String> resultProperties)
      Stores the query as the author finally left it. An empty query text means the author took the query away, so the document is cleared rather than stored empty — and the data set is then one the designer refuses to save, because a run has nothing to execute without it.
      Parameters:
      dataSet - data set to store the query in
      jpql - query text as edited
      resultProperties - column names in select-clause order
    • collectReportParameters

      protected void collectReportParameters(DataSet dataSet, Map<String,LlmQueryParameter> parameters)
      Offers the report's input parameters under their aliases, typed as the report itself types them.
    • collectParentBandColumns

      protected void collectParentBandColumns(DataSet dataSet, Map<String,LlmQueryParameter> parameters)
      Offers the columns of the parent bands under the flattened names the loader binds them by. Only an LLM parent with a stored query is known here: a JPQL or SQL parent states its columns as aliases inside the query text, and reading them out of there is not worth it — such a parameter is written by hand.

      The walk stops short of the root band — the one band without a parent — because the loader stops there too: a run offers no Root_<field> name, so offering one here would have generation reference a parameter nothing could ever bind. Every report has a data set on its root band, and it may well be an LLM one.

    • collectCrossTabAxisColumns

      protected void collectCrossTabAxisColumns(DataSet dataSet, Map<String,LlmQueryParameter> parameters, List<String> requiredResultProperties)
      Offers the columns of the axes of a cross-tab band, so that a cell query can filter itself by them and alias its own columns accordingly. Only an axis that is an LLM data set with a stored query states its columns; against a JPQL or SQL axis they exist only once it has run.

      One column per axis is required back — its first one. A cross-tab links a cell to its axis by the first returned column named after that axis, so requiring every column would let a caption come first and the matrix be linked by the caption text, as the loader's own collection explains.

    • isCrossTabAxis

      protected boolean isCrossTabAxis(DataSet dataSet)
      Tells an axis data set of a cross-tab band from the cell data set of that band, by the name the extraction controller recognises its axes by. Only a cell query is given the columns of the axes: a run of an axis itself receives no axis rows at all, so a query generated for one against another axis would reference a parameter the run has nothing to bind.
    • storedColumnsOf

      protected List<String> storedColumnsOf(BandDefinition band)
    • storedColumnsOf

      protected List<String> storedColumnsOf(DataSet dataSet)
    • readStoredQuery

      public @Nullable LlmDataQuery readStoredQuery(DataSet dataSet)
      Reads the query stored in a data set, or returns null when there is none or the stored document cannot be read — for a caller that only wants the columns of another data set and has nothing to say about a document that is broken.
      Parameters:
      dataSet - data set to read the stored query of
      Returns:
      the stored query, or null
    • readStoredQueryOrFail

      public @Nullable LlmDataQuery readStoredQueryOrFail(DataSet dataSet)
      Reads the query stored in a data set, reporting an unreadable document instead of hiding it: a panel that showed nothing would let the author save a report that fails on the first run.
      Parameters:
      dataSet - data set to read the stored query of
      Returns:
      the stored query, or null if none is stored yet
      Throws:
      LlmDataQueryException - if the stored document cannot be read
    • unguardedOptionalParameters

      public List<String> unguardedOptionalParameters(DataSet dataSet, LlmDataQuery query)
      Names the optional parameters a query references without guarding them — the one way this type prints wrong data instead of failing, since a run binds an empty optional as null and an unguarded comparison then matches nothing. The guard is recognised in the form the contract dictates (:name is null joined by or, either order), so it cannot see another way of writing the same intent, nor a parameter guarded in one condition and compared bare in a second: a warning worth a second look, not a verdict.
      Parameters:
      dataSet - data set whose report states which parameters are optional
      query - query to read
      Returns:
      aliases of the optional parameters the query references without a guard, in the report's order
    • resolveJavaType

      protected String resolveJavaType(ReportInputParameter inputParameter)
    • compareColumns

      public LlmDataSetGenerationSupport.ColumnsChange compareColumns(List<String> previous, List<String> current)
      Tells what a regenerated query changed about the columns of the one it replaced, so that a report whose template prints a column that is no longer produced can be noticed while the author is still there.

      Compared as sets: a template refers to a column by name, so the same names in another order break nothing. A first generation reports no change, having nothing to compare against.

      Parameters:
      previous - columns of the query being replaced
      current - columns of the generated query
      Returns:
      what was added and what disappeared