Docs

AI-Powered Grid

Use GridAIController to let users populate a Grid from the application database using natural language.

GridAIController populates a Grid with data from the application database based on natural-language requests. Given a DatabaseProvider, the controller exposes three tools to the LLM:

  • get_database_schema — describes the tables, columns, and SQL dialect.

  • get_grid_state — returns the SQL query currently driving the grid.

  • update_grid_data — queues a new SQL query for the grid.

When an LLM request completes, the queued query is executed and the grid re-renders with dynamically generated columns, type-appropriate renderers, right-aligned numeric columns, lazy loading via SQL LIMIT/OFFSET, and optional column grouping.

Basic Usage

Create a grid typed as Map<String, Object>, construct a controller with the grid and a DatabaseProvider, and attach it to an orchestrator:

Source code
Java
Grid<Map<String, Object>> grid = new Grid<>();
MessageInput messageInput = new MessageInput();

DatabaseProvider databaseProvider = new JdbcDatabaseProvider(dataSource);
GridAIController controller = new GridAIController(grid, databaseProvider);

AIOrchestrator.builder(provider, GridAIController.getSystemPrompt())
        .withInput(messageInput)
        .withController(controller)
        .build();

add(messageInput, grid);

A message list is not required — the grid itself is the output surface. Example prompts:

  • "Show me all employees in the Sales department."

  • "List the top 10 highest-paid employees with name, salary, and hire date."

  • "Show product name and category grouped under Product, and monthly revenue."

Tip
Recommended System Prompt
GridAIController.getSystemPrompt() returns a recommended system prompt that teaches the LLM how to use the controller’s tools. Concatenate it with your own instructions if you need additional behavior.

SQL Conventions

The tool description instructs the LLM to produce queries the grid can render cleanly:

  • Every column must have a human-readable AS alias. SELECT * is not allowed.

  • The grid handles pagination, so queries must not include LIMIT or OFFSET.

  • Dot-separated aliases — for example "Product.Name" and "Product.Category" — produce grouped column headers. A header row labelled "Product" spans both columns.

Before queueing an update, the controller executes a lightweight probe (SELECT * FROM (<query>) AS _v LIMIT 1) to validate the query. If the probe fails, the error is returned to the LLM so that it can correct the query on the next turn.

Persisting Grid State

Grid state is a single SQL query represented by the GridState record. Capture it with getState() and restore it later with restoreState(). Register a state change listener to persist the state automatically after each successful AI request:

Source code
Java
controller.addStateChangeListener(state ->
        sessionStore.save(sessionId, state));

// Restore on a new session
GridState saved = sessionStore.load(sessionId);
if (saved != null) {
    controller.restoreState(saved);
}

addStateChangeListener() fires only when the grid is updated by the LLM, not when restoreState() is called. The current query is also stored directly on the Grid component, so it survives session serialization automatically.

Reconnecting After Deserialization

GridAIController is not serializable. After session restore, create a new controller and pass it to the orchestrator’s reconnector together with the new provider:

Source code
Java
GridAIController controller = new GridAIController(grid, databaseProvider);
GridState saved = sessionStore.load(sessionId);
if (saved != null) {
    controller.restoreState(saved);
}

orchestrator.reconnect(provider)
        .withController(controller)
        .apply();

Multiple Grids

GridAIController manages a single grid. To coordinate several grids from the same orchestrator, implement a custom AIController that builds its tool list from GridAITools.createAll() with a custom GridAITools.Callbacks implementation. The callbacks — getGridIds(), getState(gridId), and updateData(gridId, query) — let the LLM address each grid by its ID.

Updated