Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ ci-install-wheel: dist FORCE
install-deps: FORCE ## install dependencies
pip install -e ".[dev,test]" --upgrade
ci-install-deps: FORCE
uv pip install "htmltools @ git+https://github.com/posit-dev/py-htmltools.git"
uv pip install "htmltools @ git+https://github.com/posit-dev/py-htmltools.git@html_not_str"
uv pip install -e ".[dev,test]"

install-docs: FORCE
Expand Down
8 changes: 4 additions & 4 deletions shiny/ui/_chat.py
Original file line number Diff line number Diff line change
Expand Up @@ -489,7 +489,7 @@ def messages(
transform_user == "last" and i == len(messages) - 1
)
content_key = m["transform_key" if transform else "pre_transform_key"]
chat_msg = ChatMessage(content=m[content_key], role=m["role"])
chat_msg = ChatMessage(content=str(m[content_key]), role=m["role"])
if not isinstance(format, MISSING_TYPE):
chat_msg = as_provider_message(chat_msg, format)
res.append(chat_msg)
Expand Down Expand Up @@ -635,7 +635,7 @@ async def _send_append_message(
content_type = "html" if isinstance(content, HTML) else "markdown"

msg = ClientMessage(
content=content,
content=str(content),
role=message["role"],
content_type=content_type,
chunk_type=chunk_type,
Expand Down Expand Up @@ -790,7 +790,7 @@ async def _transform_message(
if content is None:
return None

res[key] = content
res[key] = content # type: ignore

return res

Expand Down Expand Up @@ -950,7 +950,7 @@ def user_input(self, transform: bool = False) -> str | None:
if msg is None:
return None
key = "content_server" if transform else "content_client"
return msg[key]
return str(msg[key])

def _user_input(self) -> str:
id = self.user_input_id
Expand Down
6 changes: 4 additions & 2 deletions shiny/ui/_chat_normalize.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
from abc import ABC, abstractmethod
from typing import TYPE_CHECKING, Any, Optional, cast

from htmltools import HTML

from ._chat_types import ChatMessage

if TYPE_CHECKING:
Expand Down Expand Up @@ -49,10 +51,10 @@ def normalize_chunk(self, chunk: Any) -> ChatMessage:
return ChatMessage(content=x or "", role="assistant")

def can_normalize(self, message: Any) -> bool:
return isinstance(message, str) or message is None
return isinstance(message, (str, HTML)) or message is None

def can_normalize_chunk(self, chunk: Any) -> bool:
return isinstance(chunk, str) or chunk is None
return isinstance(chunk, (str, HTML)) or chunk is None


class DictNormalizer(BaseMessageNormalizer):
Expand Down
4 changes: 3 additions & 1 deletion shiny/ui/_chat_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

from typing import Literal, TypedDict

from htmltools import HTML

Role = Literal["assistant", "user", "system"]


Expand All @@ -14,7 +16,7 @@ class ChatMessage(TypedDict):

# A message once transformed have been applied
class TransformedMessage(TypedDict):
content_client: str
content_client: str | HTML
content_server: str
role: Role
transform_key: Literal["content_client", "content_server"]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from typing import Union

from shiny.express import render, ui

# Set some Shiny page options
Expand All @@ -12,7 +14,7 @@

# TODO: test with append_message_stream() as well
@chat.transform_assistant_response
def transform(content: str) -> str:
def transform(content: str) -> Union[str, ui.HTML]:
if content == "return HTML":
return ui.HTML(f"<b>Transformed response</b>: {content}")
else:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from playwright.sync_api import Page, expect
from utils.deploy_utils import skip_on_webkit

from shiny import ui
from shiny.playwright import controller
from shiny.run import ShinyAppProc

Expand Down Expand Up @@ -48,7 +47,7 @@ def test_validate_chat_transform_assistant(page: Page, local_app: ShinyAppProc)
{"content": "Transformed response: `hello`", "role": "assistant"},
{"content": "return HTML", "role": "user"},
{
"content": ui.HTML("<b>Transformed response</b>: return HTML"),
"content": "<b>Transformed response</b>: return HTML",
"role": "assistant",
},
]
Expand Down
Loading