shinychat and querychat

Programming with LLMs in R and Python

posit::conf(2026)

2026-09-14

Ask questions. Inspect the SQL.

querychat turns a question about your data into a SQL query, runs the query, and shows the result.

  • Ask questions in natural language.
  • Inspect the generated SQL.
  • See the filtered data in the same app.

The built-in app includes chat, a data table, and a SQL view.

Start with a data frame

R


library(ellmer)
library(querychat)

qc <- QueryChat$new(
  airbnb_data,
  "airbnb_data",
  client = chat_posit()
)

qc$app()

Python

import pandas as pd
from chatlas import ChatPosit
from querychat import QueryChat

qc = QueryChat(
    airbnb_data,
    "airbnb_data",
    client=ChatPosit(),
)

app = qc.app()

Your Turn 26_querychat

  1. Try to reach a conclusion from your earlier Posit Assistant conversation.
    Ex: Which neighborhood has the most private rooms?

  2. Open the data drawer and select Show Query to inspect the SQL.

  3. Restart the app with data_dict included.
    Among private rooms, which property types are most common?

  4. Hints: data_dict is already in the file — uncomment it and restart the app.

querychat in R

library(shiny)
library(bslib)
library(ellmer)
library(querychat)

mtcars_qc <- QueryChat$new(mtcars, client = chat_posit())

ui <- page_sidebar(
  sidebar = mtcars_qc$sidebar(),
  # plots, tables, etc.
)

server <- function(input, output, session) {
  mtcars_qc_vals <- mtcars_qc$server()

  output$table <- renderTable({
    mtcars_qc_vals$df()
  })
}

shinyApp(ui, server)

querychat in Python

import polars as pl
import querychat
from chatlas import ChatPosit
from shiny import App, render, ui

mtcars = pl.read_csv("data/mtcars.csv")

mtcars_qc = querychat.QueryChat(mtcars, "mtcars", client=ChatPosit())

app_ui = ui.page_sidebar(
    mtcars_qc.sidebar(),
    # plots, tables, etc.
)

def server(input, output, session):
    mtcars_qc_vals = mtcars_qc.server()

    @render.data_frame
    def data_table():
        return mtcars_qc_vals.df()

app = App(app_ui, server)

Demo: querychat dashboard

👨‍💻 _demos/27_querychat

A quick chat app in R

library(ellmer)
library(shinychat)

client <- chat_posit()
chat_app(client)

A chat app in R

For an app other people can use, create one client per session.

library(shiny)
library(ellmer)
library(shinychat)

ui <- page_chat(
  "My chat"
)

server <- function(input, output, session) {
  client <- chat_posit()
  chat_server("chat", client)
}

shinyApp(ui, server)

A chat app in Python

import chatlas
from shiny import App
from shinychat import Chat, page_chat

app_ui = page_chat("My chat", id="chat")

def server(input, output, session):
    client = chatlas.ChatPosit()
    Chat("chat", client=client)

app = App(app_ui, server)

Your Turn 06_word-games

  1. I’ve set up the basic Shiny app snippet and a system prompt.

  2. Your job: create a chatbot that plays a “20 questions” style word guessing game with you.

  3. The model was given a secret word, and it’s your job to guess it.

  4. Hints: Use page_chat(), chat_posit(), and chat_server()

Chat can be the application

page_chat() gives a conversation its own page.

It includes conversation history, a chat home, and room for artifacts and other application UI.

Start with page_chat()

R

ui <- page_chat(
  "Blockbuster renewal assistant",
  id = "chat"
)

server <- function(input, output, session) {
  client <- chat_posit()
  prep_blockbuster_agent(client, ...)
  chat_server("chat", client)
}

Python

app_ui = page_chat(
    "Blockbuster renewal assistant",
    id="chat",
)

def server(input, output, session):
    client = ChatPosit()
    prep_blockbuster_agent(client, ...)
    Chat("chat", client=client)

Give people a useful start

A greeting explains the app and can offer prompts they can use or edit.

## Welcome to the renewal desk

* <span class="suggestion submit">Draft renewal letters for the top three lapsed members.</span>
* <span class="suggestion submit">List the draft letters already in the workspace.</span>
* <span class="suggestion submit">Explain the renewal-letter skill.</span>

Your Turn 24_shinychat-1

  1. Open the Blockbuster renewal assistant.

  2. Add a greeting with three suggestion cards for common renewal tasks.

  3. Use a suggestion to draft letters for the top three lapsed members.

  4. Hints: chat_greeting() is wired up — write the greeting with <span class="suggestion"> cards.

Discussion: Did your app…?

  • Give the renewal agent a clear purpose before anyone typed?

  • Offer prompts that match the jobs the agent can do?

  • Keep the agent tools and skills out of the app code you edited?

  • Preserve the conversation after you followed a suggestion?

Artifacts stay beside the conversation

A drawer — chat_drawer() — can hold the drafts an agent creates.

The user selects a letter, edits it, and saves it to the workspace.

Tools can control the app

When the agent writes or edits a letter, it calls show_letter().

show_letter() uses updateSelectInput() to select the file, then opens the drawer for review.

Your Turn 25_shinychat-2

  1. Complete show_letter() so it selects a draft and opens the letter drawer.

  2. Ask the agent to draft a renewal letter for Elaine Wu.

  3. Edit the letter in the drawer, save it, then ask the agent to revise that draft.

  4. Hints: Use updateSelectInput() (or ui.update_select()) and chat_drawer_show()

Discussion: Did your agent…?

  • List the drafts before it created a new version?

  • Write a draft named elaine-wu-v1.md or the next available version?

  • Open the letter it wrote in the drawer?

  • Preserve your edit when you saved it?

  • Read the current letter before it tried to edit it?