1- # ' Shiny module for commons agents
1+ # ' Shiny chat UI and server for commons agents
22# '
3- # ' These functions wrap [shinychat::chat_mod_ui ()] and
4- # ' [shinychat::chat_mod_server()] with commons-specific answer provenance UI.
5- # ' Answers produced from registered measures get a compact verified-answer
6- # ' pill. Answers produced from fallback SQL or R can cite text from the
7- # ' agent's context, measure definitions, or data documentation; verified
8- # ' citations render as footnotes whose tooltips name their source. Fallback
9- # ' answers with no verified citation get a potentially-untrusted caution pill.
3+ # ' These functions wrap [shinychat::chat_ui ()] and [shinychat::chat_server()]
4+ # ' with commons-specific answer provenance UI. Answers produced from
5+ # ' registered measures get a compact verified-answer pill. Answers produced
6+ # ' from fallback SQL or R can cite text from the agent's context, measure
7+ # ' definitions, or data documentation; verified citations render as footnotes
8+ # ' whose tooltips name their source. Fallback answers with no verified
9+ # ' citation get a potentially-untrusted caution pill.
1010# '
11- # ' @param id Module ID.
12- # ' @param ... Arguments passed to [shinychat::chat_mod_ui()] or
13- # ' [shinychat::chat_mod_server ()].
11+ # ' @param id The ID of the chat element; must match between `commons_ui()`
12+ # ' and `commons_server()`.
13+ # ' @param ... Extra HTML attributes passed to [shinychat::chat_ui ()].
1414# ' @param messages Initial messages shown in the chat. Passed to
15- # ' [shinychat::chat_mod_ui ()].
15+ # ' [shinychat::chat_ui ()].
1616# ' @param height Chat container height. Defaults to `"100%"` so the chat input
1717# ' stays docked at the bottom of fill layouts.
1818# ' @param client A [commons()] agent. Create a new agent for each Shiny session.
19- # ' @param bookmark_on_input,bookmark_on_response Whether to add Shiny
20- # ' bookmarking hooks for user inputs and assistant responses.
2119# '
22- # ' @return `commons_mod_ui ()` returns UI. `commons_mod_server ()` returns the
23- # ' shinychat module server result.
20+ # ' @return `commons_ui ()` returns UI. `commons_server ()` returns the
21+ # ' [ shinychat::chat_server()] result.
2422# '
2523# ' @examples
2624# ' \dontrun{
2725# ' library(shiny)
2826# '
2927# ' ui <- page_fillable(
30- # ' commons_mod_ui ("chat")
28+ # ' commons_ui ("chat")
3129# ' )
3230# '
3331# ' server <- function(input, output, session) {
3432# ' agent <- commons(
3533# ' ellmer::chat_anthropic(),
3634# ' data_sources = data_source(sales = sales)
3735# ' )
38- # ' commons_mod_server ("chat", agent)
36+ # ' commons_server ("chat", agent)
3937# ' }
4038# '
4139# ' shinyApp(ui, server)
4240# ' }
4341# '
4442# ' @export
45- commons_mod_ui <- function (id , ... , messages = NULL , height = " 100%" ) {
43+ commons_ui <- function (id , ... , messages = NULL , height = " 100%" ) {
4644 check_chat_packages()
47- ui <- shinychat :: chat_mod_ui (id , ... , messages = messages , height = height )
45+ ui <- shinychat :: chat_ui (id , ... , messages = messages , height = height )
4846 htmltools :: attachDependencies(ui , commons_chat_dependency(), append = TRUE )
4947}
5048
51- # ' @rdname commons_mod_ui
49+ # ' @rdname commons_ui
5250# ' @export
53- commons_mod_server <- function (
54- id ,
55- client ,
56- bookmark_on_input = TRUE ,
57- bookmark_on_response = TRUE
58- ) {
51+ commons_server <- function (id , client ) {
5952 check_chat_packages()
6053 check_commons_client(client )
6154
@@ -67,37 +60,35 @@ commons_mod_server <- function(
6760 tryCatch(client $ prewarm(), error = function (err ) NULL )
6861 })
6962
70- mod <- shinychat :: chat_mod_server(
71- id ,
72- client = client ,
73- bookmark_on_input = bookmark_on_input ,
74- bookmark_on_response = bookmark_on_response
75- )
63+ chat <- shinychat :: chat_server(id , client = client )
7664
77- shiny :: moduleServer(id , function (input , output , session ) {
78- session $ onFlushed(function () {
79- seed_commons_pills(session , client )
80- }, once = TRUE )
65+ session <- shiny :: getDefaultReactiveDomain()
8166
82- shiny :: observeEvent(mod $ last_turn(), {
83- provenance <- commons_last_provenance(client )
84- if (is.na(provenance $ tag )) {
85- return ()
86- }
67+ shiny :: observeEvent(chat $ last_turn(), ignoreNULL = TRUE , {
68+ provenance <- commons_last_provenance(client )
69+ if (is.na(provenance $ tag )) {
70+ return ()
71+ }
8772
88- send_commons_pill(session , provenance )
89- }, ignoreNULL = TRUE )
73+ send_commons_pill(session , id , provenance )
9074 })
9175
92- mod
76+ session $ onFlushed(
77+ function () {
78+ seed_commons_pills(session , id , client )
79+ },
80+ once = TRUE
81+ )
82+
83+ chat
9384}
9485
95- send_commons_pill <- function (session , provenance ) {
86+ send_commons_pill <- function (session , id , provenance ) {
9687 html <- htmltools :: renderTags(commons_answer_pill(provenance $ tag ))$ html
9788 session $ sendCustomMessage(
9889 " commonsProvenancePill" ,
9990 list (
100- id = session $ ns(" chat " ),
91+ id = session $ ns(id ),
10192 html = html ,
10293 citations = citations_payload(provenance $ citations )
10394 )
@@ -106,7 +97,7 @@ send_commons_pill <- function(session, provenance) {
10697
10798# Restored history renders as streams, so all seeded pills go in one
10899# message and the client places them only once the transcript settles.
109- seed_commons_pills <- function (session , client ) {
100+ seed_commons_pills <- function (session , id , client ) {
110101 provenances <- commons_exchange_provenance(
111102 client $ get_turns(include_system_prompt = FALSE ),
112103 client $ citation_corpus()
@@ -131,7 +122,7 @@ seed_commons_pills <- function(session, client) {
131122
132123 session $ sendCustomMessage(
133124 " commonsProvenancePillSeed" ,
134- list (id = session $ ns(" chat " ), count = n , pills = pills )
125+ list (id = session $ ns(id ), count = n , pills = pills )
135126 )
136127}
137128
@@ -161,7 +152,7 @@ check_chat_packages <- function(call = rlang::caller_env()) {
161152 cli :: cli_abort(
162153 c(
163154 " The {.pkg commons} chat module requires missing package{?s}: {.pkg {missing}}." ,
164- i = " Install {.pkg {missing}} to use {.fn commons_mod_ui } and {.fn commons_mod_server }."
155+ i = " Install {.pkg {missing}} to use {.fn commons_ui } and {.fn commons_server }."
165156 ),
166157 call = call
167158 )
0 commit comments