Skip to content

Commit 10af6ab

Browse files
committed
Add support for Anthropic built-in tools display
Support displaying server_tool_use, web_search_tool_result, and other built-in tool types from Anthropic models in both streaming and chat history.
1 parent 0340bee commit 10af6ab

File tree

1 file changed

+20
-4
lines changed

1 file changed

+20
-4
lines changed

app/utils.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,14 +69,20 @@ def flush_thinking() -> None:
6969
if part_type == "thinking":
7070
# Accumulate thinking content in buffer
7171
thinking_buffer.append(part.get("thinking", ""))
72-
elif part_type == "tool_use":
73-
# Flush thinking before tool use
74-
flush_thinking()
7572
elif part_type == "text":
7673
# Flush thinking before displaying text
7774
flush_thinking()
7875
if text := part.get("text"):
7976
yield text
77+
elif "delta" in part_type:
78+
# Skip delta types (streaming intermediate states)
79+
continue
80+
else:
81+
# Other types (tool_use, server_tool_use, web_search_tool_result, etc.)
82+
flush_thinking()
83+
if tool_callback:
84+
title = part.get("name", part_type) if "name" in part else part_type
85+
tool_callback(f"🔧 {title}", part)
8086

8187
# OpenAI: content is a simple string
8288
elif isinstance(content, str):
@@ -158,18 +164,28 @@ def on_delete_thread(thread_id: str) -> None:
158164

159165
# Message display functions
160166
def render_part(part: Any) -> None:
161-
"""Display a single part of multimodal message content (text or image)."""
167+
"""Display a single part of multimodal message content (text, image, tool use, etc.)."""
162168
if not isinstance(part, dict):
163169
return
164170

165171
part_type = part.get("type")
172+
166173
if part_type == "text":
167174
st.write(part.get("text", ""))
168175
elif part_type == "image_url":
169176
url_part = part.get("image_url")
170177
url = url_part.get("url") if isinstance(url_part, dict) else url_part
171178
if url:
172179
st.image(url)
180+
elif part_type == "thinking":
181+
# Thinking blocks are handled separately in show_message
182+
pass
183+
else:
184+
# All other types (server_tool_use, web_search_tool_result, etc.)
185+
# Display generically in expander
186+
title = part.get("name", part_type) if "name" in part else part_type
187+
with st.expander(f"🔧 {title}", expanded=False):
188+
st.write(part)
173189

174190

175191
def render_content(content: str | list[Any]) -> None:

0 commit comments

Comments
 (0)