Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
12 changes: 11 additions & 1 deletion pkg-py/src/shinychat/_chat_normalize_chatlas.py
Original file line number Diff line number Diff line change
Expand Up @@ -288,8 +288,18 @@ def tool_result_contents(x: "ContentToolResult") -> Tagifiable:

tool = x.request.tool
tool_title = None
icon = None
if tool and tool.annotations:
tool_title = tool.annotations.get("title")
icon = tool.annotations.get("extras", {}).get("icon")
Copy link
Collaborator

Choose a reason for hiding this comment

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

shoot, it's extra, not extras: posit-dev/chatlas#173

icon = icon or tool.annotations.get("icon")

# Icon strings and HTML display never get escaped
icon = display.icon or icon
if icon and isinstance(icon, str):
icon = HTML(icon)
if value_type == "html" and isinstance(value, str):
value = HTML(value)

# display (tool *result* level) takes precedence over
# annotations (tool *definition* level)
Expand All @@ -301,7 +311,7 @@ def tool_result_contents(x: "ContentToolResult") -> Tagifiable:
status="success" if x.error is None else "error",
value=value,
value_type=value_type,
icon=display.icon,
icon=icon,
intent=intent,
show_request=display.show_request,
expanded=display.open,
Expand Down
14 changes: 9 additions & 5 deletions pkg-py/src/shinychat/_markdown_stream.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,9 @@ def __init__(
async def _mock_task() -> str:
return ""

self._latest_stream: reactive.Value[reactive.ExtendedTask[[], str]] = (
reactive.Value(_mock_task)
)
self._latest_stream: reactive.Value[
reactive.ExtendedTask[[], str]
] = reactive.Value(_mock_task)

async def stream(
self,
Expand Down Expand Up @@ -149,7 +149,9 @@ async def _task():
ui = self._session._process_ui(x)

result += ui["html"]
await self._send_content_message(ui["html"], "append", ui["deps"])
await self._send_content_message(
ui["html"], "append", ui["deps"]
)

return result

Expand Down Expand Up @@ -249,7 +251,9 @@ async def _send_custom_message(
):
if self._session.is_stub_session():
return
await self._session.send_custom_message("shinyMarkdownStreamMessage", {**msg})
await self._session.send_custom_message(
"shinyMarkdownStreamMessage", {**msg}
)

async def _raise_exception(self, e: BaseException):
if self.on_error == "unhandled":
Expand Down
81 changes: 35 additions & 46 deletions pkg-py/tests/playwright/tools/basic/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import faicons
from chatlas import ChatAuto, ContentToolResult
from chatlas.types import ToolAnnotations
from pydantic import BaseModel, Field
from shiny import reactive
from shiny.express import input, ui
from shinychat.express import Chat
Expand Down Expand Up @@ -39,20 +38,6 @@ def list_files_impl():
)


class ListFileParams(BaseModel):
"""
List files in the user's current directory. Always check again when asked.
"""

path: str = Field(..., description="The path to list files from")


class ListFileParamsWithIntent(ListFileParams):
intent: str = Field(
..., description="The user's intent for this tool", alias="_intent"
)


annotations: ToolAnnotations = {}
if TOOL_OPTS["with_title"]:
annotations["title"] = "List Files"
Expand All @@ -61,56 +46,60 @@ class ListFileParamsWithIntent(ListFileParams):
if TOOL_OPTS["async"]:
if TOOL_OPTS["with_intent"]:

async def list_files_func1(path: str, _intent: str):
async def list_files(path: str, _intent: str): # pyright: ignore[reportRedeclaration]
"""
List files in the user's current directory. Always check again when asked.

Parameters
----------
path
The path to list files from.
_intent
Reason for the request to explain the tool call to the user.
"""
await asyncio.sleep(random.uniform(1, 10))
return list_files_impl()

chat_client.register_tool(
list_files_func1,
name="list_files",
model=ListFileParamsWithIntent,
annotations=annotations,
)

else:

async def list_files_func2(path: str):
async def list_files(path: str): # pyright: ignore[reportRedeclaration]
"""
List files in the user's current directory. Always check again when asked.
"""
await asyncio.sleep(random.uniform(1, 10))
return list_files_impl()

chat_client.register_tool(
list_files_func2,
name="list_files",
model=ListFileParams,
annotations=annotations,
)

else:
if TOOL_OPTS["with_intent"]:

def list_files_func3(path: str, _intent: str):
def list_files(path: str, _intent: str): # pyright: ignore[reportRedeclaration]
"""
List files in the user's current directory. Always check again when asked.

Parameters
----------
path
The path to list files from.
_intent
Reason for the request to explain the tool call to the user.
"""
time.sleep(random.uniform(1, 3))
return list_files_impl()

chat_client.register_tool(
list_files_func3,
name="list_files",
model=ListFileParamsWithIntent,
annotations=annotations,
)

else:

def list_files_func4(path: str):
def list_files(path: str): # pyright: ignore[reportRedeclaration]
"""
List files in the user's current directory. Always check again when asked.
"""
time.sleep(random.uniform(1, 3))
return list_files_impl()

chat_client.register_tool(
list_files_func4,
name="list_files",
model=ListFileParams,
annotations=annotations,
)

chat_client.register_tool(
list_files,
annotations=annotations,
)

ui.page_opts(fillable=True)

Expand Down