Skip to content

Conversation

@gadenbuie
Copy link
Contributor

Fixes #159
Fixes #117

  • New client() method - QueryChat objects can now create standalone chat clients with configurable tools and callbacks, enabling use outside of Shiny applications.

  • New console() method - Launch interactive console-based chat sessions with your data source, with persistent conversation state across invocations (seems like a feature we might want to bring to the app() method, but there it's a little more complicated, so that can be follow-up).

  • Configurable tool selection - This happened to be easy to fold into this change. A new tools parameter allows selective inclusion of "query" and/or "update" tools, enabling privacy-focused workflows that prevent the LLM from accessing data.

    • Enabled tools are set when creating the class instance and the value is respected in all methods except console()
    • console() defaults to using tools = "query", since the update tool doesn't make sense in that context
    • client() defaults to the instance's tools value but can be overridden directly.
    • All the app-related methods call the client() method with the default: use the instance setting for tools

@gadenbuie gadenbuie requested a review from cpsievert December 16, 2025 15:00
Comment on lines 409 to 411
# Default to query-only for console (privacy)
if isinstance(tools, MISSING_TYPE) and (new or self._client_console is None):
tools = ("query",)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Query is the less private tool?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, it's not obvious to me why .console() should have different default tools from .app()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oops, no that comment isn't right, it's actually the opposite. I'll fix that.

.console() needs different tools from .app() because the update dashboard tool doesn't make sense in the console where there's no dashboard to update. Really, only the query tool makes sense and it's safe for that to be the default because this for interactive use, not something you'd put into production.

You could go through hoops to set up update_dashboard in a way that it works or makes sense for something you're working on, but tools = "query" is the right default choice for .console().

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be a little more concrete about the hoops: .console() accepts kwargs that are passed to .client() which you could use to setup update_dashboard and reset_dashboard callbacks.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good.

BTW, this PR does start to make me think that it'd useful to have non-Shiny/reactive versions of .df(), etc., that you could read directly from the instance. And in that case, tools would also now update the values that those methods return. Seems this would be somewhat useful R and also might end up being really nice for supporting streamlit, etc on the Python side. I was sort of planning on dedicating some time to streamlit this week, so maybe I'll explore this idea once this PR is done?

It does also kinda push me a direction of thinking a .chat() and .stream() method might be useful?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure about the non-reactive .df(), but as to .chat() and .stream() -- I created .client() to help us go down that path. My intuition is that in Streamlit, notebook, etc. contexts you might be able to get pretty far with superclasses that can rely on .client(), or maybe we'll need the .chat() and .stream() methods.

I don't think we should build any of these right this minute, but the goal of .client() is to make it easier to test and find out.

@gadenbuie gadenbuie requested a review from cpsievert December 16, 2025 16:50
Copy link
Contributor

@cpsievert cpsievert left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice addition, thanks! Good with me once CoPilot has a final say.

@cpsievert cpsievert requested a review from Copilot December 16, 2025 17:18

This comment was marked as resolved.

@gadenbuie gadenbuie merged commit 9cc73d9 into main Dec 16, 2025
17 of 18 checks passed
@gadenbuie gadenbuie deleted the feat/no-app branch December 16, 2025 17:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Access chat client outside of Shiny app Provide a way to disable analytical queries

3 participants