Skip to content

Commit 8c48e12

Browse files
cpsievertgadenbuie
andauthored
feat(pkg-py): pick up tool annotation icon and never escape icon or html display (#127)
* Follow up to #107: pick up tool annotation icon and never escape icon or html display * chore: make py-format --------- Co-authored-by: Garrick Aden-Buie <[email protected]>
1 parent 09f22a2 commit 8c48e12

File tree

3 files changed

+55
-52
lines changed

3 files changed

+55
-52
lines changed

pkg-py/src/shinychat/_chat_normalize_chatlas.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,8 +288,18 @@ def tool_result_contents(x: "ContentToolResult") -> Tagifiable:
288288

289289
tool = x.request.tool
290290
tool_title = None
291+
icon = None
291292
if tool and tool.annotations:
292293
tool_title = tool.annotations.get("title")
294+
icon = tool.annotations.get("extras", {}).get("icon")
295+
icon = icon or tool.annotations.get("icon")
296+
297+
# Icon strings and HTML display never get escaped
298+
icon = display.icon or icon
299+
if icon and isinstance(icon, str):
300+
icon = HTML(icon)
301+
if value_type == "html" and isinstance(value, str):
302+
value = HTML(value)
293303

294304
# display (tool *result* level) takes precedence over
295305
# annotations (tool *definition* level)
@@ -301,7 +311,7 @@ def tool_result_contents(x: "ContentToolResult") -> Tagifiable:
301311
status="success" if x.error is None else "error",
302312
value=value,
303313
value_type=value_type,
304-
icon=display.icon,
314+
icon=icon,
305315
intent=intent,
306316
show_request=display.show_request,
307317
expanded=display.open,

pkg-py/src/shinychat/_markdown_stream.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,9 @@ def __init__(
9292
async def _mock_task() -> str:
9393
return ""
9494

95-
self._latest_stream: reactive.Value[reactive.ExtendedTask[[], str]] = (
96-
reactive.Value(_mock_task)
97-
)
95+
self._latest_stream: reactive.Value[
96+
reactive.ExtendedTask[[], str]
97+
] = reactive.Value(_mock_task)
9898

9999
async def stream(
100100
self,
@@ -149,7 +149,9 @@ async def _task():
149149
ui = self._session._process_ui(x)
150150

151151
result += ui["html"]
152-
await self._send_content_message(ui["html"], "append", ui["deps"])
152+
await self._send_content_message(
153+
ui["html"], "append", ui["deps"]
154+
)
153155

154156
return result
155157

@@ -249,7 +251,9 @@ async def _send_custom_message(
249251
):
250252
if self._session.is_stub_session():
251253
return
252-
await self._session.send_custom_message("shinyMarkdownStreamMessage", {**msg})
254+
await self._session.send_custom_message(
255+
"shinyMarkdownStreamMessage", {**msg}
256+
)
253257

254258
async def _raise_exception(self, e: BaseException):
255259
if self.on_error == "unhandled":

pkg-py/tests/playwright/tools/basic/app.py

Lines changed: 35 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import faicons
77
from chatlas import ChatAuto, ContentToolResult
88
from chatlas.types import ToolAnnotations
9-
from pydantic import BaseModel, Field
109
from shiny import reactive
1110
from shiny.express import input, ui
1211
from shinychat.express import Chat
@@ -39,20 +38,6 @@ def list_files_impl():
3938
)
4039

4140

42-
class ListFileParams(BaseModel):
43-
"""
44-
List files in the user's current directory. Always check again when asked.
45-
"""
46-
47-
path: str = Field(..., description="The path to list files from")
48-
49-
50-
class ListFileParamsWithIntent(ListFileParams):
51-
intent: str = Field(
52-
..., description="The user's intent for this tool", alias="_intent"
53-
)
54-
55-
5641
annotations: ToolAnnotations = {}
5742
if TOOL_OPTS["with_title"]:
5843
annotations["title"] = "List Files"
@@ -61,56 +46,60 @@ class ListFileParamsWithIntent(ListFileParams):
6146
if TOOL_OPTS["async"]:
6247
if TOOL_OPTS["with_intent"]:
6348

64-
async def list_files_func1(path: str, _intent: str):
49+
async def list_files(path: str, _intent: str): # pyright: ignore[reportRedeclaration]
50+
"""
51+
List files in the user's current directory. Always check again when asked.
52+
53+
Parameters
54+
----------
55+
path
56+
The path to list files from.
57+
_intent
58+
Reason for the request to explain the tool call to the user.
59+
"""
6560
await asyncio.sleep(random.uniform(1, 10))
6661
return list_files_impl()
6762

68-
chat_client.register_tool(
69-
list_files_func1,
70-
name="list_files",
71-
model=ListFileParamsWithIntent,
72-
annotations=annotations,
73-
)
74-
7563
else:
7664

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

81-
chat_client.register_tool(
82-
list_files_func2,
83-
name="list_files",
84-
model=ListFileParams,
85-
annotations=annotations,
86-
)
87-
8872
else:
8973
if TOOL_OPTS["with_intent"]:
9074

91-
def list_files_func3(path: str, _intent: str):
75+
def list_files(path: str, _intent: str): # pyright: ignore[reportRedeclaration]
76+
"""
77+
List files in the user's current directory. Always check again when asked.
78+
79+
Parameters
80+
----------
81+
path
82+
The path to list files from.
83+
_intent
84+
Reason for the request to explain the tool call to the user.
85+
"""
9286
time.sleep(random.uniform(1, 3))
9387
return list_files_impl()
9488

95-
chat_client.register_tool(
96-
list_files_func3,
97-
name="list_files",
98-
model=ListFileParamsWithIntent,
99-
annotations=annotations,
100-
)
101-
10289
else:
10390

104-
def list_files_func4(path: str):
91+
def list_files(path: str): # pyright: ignore[reportRedeclaration]
92+
"""
93+
List files in the user's current directory. Always check again when asked.
94+
"""
10595
time.sleep(random.uniform(1, 3))
10696
return list_files_impl()
10797

108-
chat_client.register_tool(
109-
list_files_func4,
110-
name="list_files",
111-
model=ListFileParams,
112-
annotations=annotations,
113-
)
98+
99+
chat_client.register_tool(
100+
list_files,
101+
annotations=annotations,
102+
)
114103

115104
ui.page_opts(fillable=True)
116105

0 commit comments

Comments
 (0)