feat(py): Add chat_mod_ui() and chat_mod_server() module functions#232
feat(py): Add chat_mod_ui() and chat_mod_server() module functions#232gadenbuie wants to merge 13 commits into
chat_mod_ui() and chat_mod_server() module functions#232Conversation
Batteries-included module wrappers that wire a chatlas client to the shinychat UI, mirroring the R package's `chat_mod_ui()`/`chat_mod_server()`. Features: - Automatic streaming (user submit -> stream_async -> append_message_stream) - Cancel support via ExtendedTask.cancel() - Reactive status(), last_input(), last_turn() accessors - set_client() with deferred swap during streaming - clear() with client_history management - Greeting system (static, callable, callable with client clone) - Bookmarking integration with re-registration on client swap Closes #144
Prevents Shiny's ID validation from rejecting the hyphenated
"{module_id}-chat" string.
31 pytest unit tests covering chat_mod_ui() rendering, ChatServerState interface structure, and imports. 5 Playwright integration tests covering UI rendering, cancel button, message submission/response, status tracking, and multi-message flow.
…ference Adds a new "Chat Module" section to the quartodoc config.
- Remove `bookmark_on_input` parameter (dead code; underlying Chat.enable_bookmarking() only supports response-triggered bookmarks) - Implement `clear(client_history="set"/"append")` properly using chatlas UserTurn/AssistantTurn instead of no-op stubs - Fix cancel button test to verify `enable-cancel` attribute on the container rather than asserting DOM presence of a conditionally- rendered element
`chatlas.Chat.stream_async()` is an async def returning an AsyncGenerator, so it must be awaited. The missing await caused a TypeError in `wrap_async_iterable` at runtime.
- Note cancel is enabled by default in chat_mod_ui() - Fix last_turn() return type to Optional[Any] - Note client property is not reactive - Tighten append() role type to Literal["assistant", "user"] - Tighten clear() messages type to list[Union[dict[str, str], str]] - Replace internal input name with behavioral description in clear() - Note async callable support in chat_mod_server() greeting param
Add a "Chat module" section showing chat_mod_ui/chat_mod_server usage and a note that chat_mod_server handles cancellation automatically.
Passes static greeting values through to `chat_ui()`, matching the R package where greeting flows through `...`.
chat_mod_ui() and chat_mod_server() module functions
The pre-existing test_chat_module.py in chat/module/ collides with new test files of the same name. Rename to test_chat_mod.py (unit) and test_chat_mod_e2e.py (Playwright) so pytest can collect all three.
…ator Matches the real chatlas.Chat.stream_async signature so that `await client.stream_async(...)` works correctly in chat_mod_server.
|
Thanks for looking at this! I've been prototyping a parallel version on Express support. My branch adds a Supporting Express also inspired a different naming convention. In Express, the existing API is This also drove a couple of downstream design choices:
Exposing more of the Bookmarking error handling. The Let me know if you'd like me to push my branch so you can compare side-by-side, or if you'd rather I send patches for any of these. |
|
Good point, I hadn't fully though out the implications of Express. Happy to defer this PR in favor of what you have cooking. |
Closes #144
Summary
Adds batteries-included module functions for Shiny Core apps that use chatlas.
chat_mod_ui()+chat_mod_server()handle streaming, cancellation, bookmarking, and greetings automatically — replacing the manual wiring ofChat+chat_ui+on_user_submit+StreamController.New public API
chat_mod_ui(id, ...)— thin wrapper aroundchat_ui()with namespaced ID,enable_cancel=True, and pass-through forgreeting,messages,placeholder,width,height,fill,icon_assistant,footer.chat_mod_server(id, client, ...)— module server that wires a chatlas client to the chat UI. Accepts static or dynamicgreeting(sync or async callables, with optionalclientparameter for auto-cloned greeting clients). Returns aChatServerState.ChatServerState— return type with reactive accessors (last_input(),last_turn(),status()) and action methods (update_user_input(),append(),clear(),set_client(),set_greeting()).set_client()supports deferred swap during active streaming.Files changed
pkg-py/src/shinychat/_chat_module.pychat_mod_ui(),chat_mod_server(),ChatServerStatepkg-py/src/shinychat/__init__.pypkg-py/docs/_quarto.ymlpkg-py/docs/index.qmdpkg-py/tests/pytest/test_chat_module.pyChatServerStatestructure, importspkg-py/tests/playwright/chat/chat_module/Examples
Set
ANTHROPIC_API_KEYbefore running.Minimal — just
chat_mod_ui()+chat_mod_server():Dynamic greeting — async greeting function with auto-cloned client:
Client swap — switch models mid-session with
set_client():