Spaces:
Running
on
CPU Upgrade
Running
on
CPU Upgrade
import json | |
def format_user_message(msg): | |
"""Format a user message for display.""" | |
# Extract the content based on role | |
content = msg.get("content", "") | |
# Handle None content | |
if content is None: | |
content = "" | |
elif isinstance(content, (int, float)): | |
content = str(content) | |
elif isinstance(content, list): | |
# Handle list-type content (may contain multiple parts) | |
content_text = "" | |
for item in content: | |
if item is None: | |
continue | |
if isinstance(item, dict) and "text" in item: | |
text_value = item.get("text", "") | |
if text_value is not None: | |
content_text += str(text_value) + "\n" | |
elif isinstance(item, str): | |
content_text += item + "\n" | |
elif item is not None: | |
content_text += str(item) + "\n" | |
content = content_text.strip() | |
# User message - align right using text-align instead of flex | |
return f""" | |
<div style=" | |
text-align: right; | |
margin-bottom: 1.25rem; | |
padding: 0 0.5rem;"> | |
<div style=" | |
display: inline-block; | |
max-width: 85%; | |
background-color: var(--message-bg-user); | |
padding: 1rem; | |
border-radius: 1rem 0 1rem 1rem; | |
color: var(--text-color); | |
text-align: left; | |
box-shadow: 0 1px 2px var(--shadow-color);"> | |
<div style=" | |
font-weight: 500; | |
margin-bottom: 0.5rem; | |
color: var(--primary-text); | |
display: flex; | |
align-items: center;"> | |
<span style="margin-right: 0.5rem;">👤</span>User | |
</div> | |
<div style="white-space: pre-wrap; line-height: 1.5;"> | |
{content} | |
</div> | |
</div> | |
</div> | |
""" | |
def format_tool_call(tool_name, tool_input): | |
"""Format a tool call for display.""" | |
# Ensure tool_name is a string | |
if tool_name is None: | |
tool_name = "Unknown Tool" | |
elif not isinstance(tool_name, str): | |
tool_name = str(tool_name) | |
# Ensure tool_input is serializable | |
if tool_input is None: | |
tool_input = {} | |
try: | |
# Try to serialize the tool input as JSON | |
tool_input_json = json.dumps(tool_input, indent=2) | |
except TypeError: | |
# If serialization fails, create a simplified representation | |
if isinstance(tool_input, dict): | |
simplified_input = {} | |
for k, v in tool_input.items(): | |
if v is None or isinstance(v, (str, int, float, bool, list, dict)): | |
simplified_input[k] = v | |
else: | |
simplified_input[k] = str(v) | |
tool_input_json = json.dumps(simplified_input, indent=2) | |
else: | |
tool_input_json = str(tool_input) | |
return f""" | |
<div style=" | |
background-color: var(--surface-color-alt); | |
padding: 0.75rem; | |
border-radius: 0.5rem; | |
margin-top: 0.75rem; | |
border-left: 3px solid var(--primary-text-light);"> | |
<div style=" | |
font-weight: 500; | |
margin-bottom: 0.5rem; | |
font-size: 0.9rem; | |
color: var(--primary-text);"> | |
<span style="margin-right: 0.5rem;">🔧</span>{tool_name} | |
</div> | |
<div style=" | |
font-family: monospace; | |
font-size: 0.85rem; | |
white-space: pre-wrap;"> | |
{tool_input_json} | |
</div> | |
</div> | |
""" | |
def extract_assistant_content(msg): | |
"""Extract text content and tool calls from an assistant message.""" | |
assistant_text = "" | |
tool_calls_html = "" | |
if "content" in msg: | |
content = msg["content"] | |
# Handle string content | |
if content is None: | |
assistant_text = "" | |
elif isinstance(content, str): | |
assistant_text = content | |
elif isinstance(content, (int, float)): | |
assistant_text = str(content) | |
# Handle list content with text and tool calls | |
elif isinstance(content, list): | |
for item in content: | |
if item is None: | |
continue | |
if isinstance(item, dict): | |
if "text" in item: | |
text_value = item.get("text", "") | |
if text_value is not None: | |
assistant_text += str(text_value) + "\n" | |
elif "type" in item and item["type"] == "tool_use": | |
# Format tool call in a nicer way | |
tool_name = item.get("name", "Unknown Tool") | |
tool_input = item.get("input", {}) | |
if tool_input is None: | |
tool_input = {} | |
tool_calls_html += format_tool_call(tool_name, tool_input) | |
elif isinstance(item, str): | |
assistant_text += item + "\n" | |
elif item is not None: | |
assistant_text += str(item) + "\n" | |
# Extract tool calls if present | |
elif "tool_calls" in msg: | |
assistant_text = "The assistant used the following tools:" | |
tool_calls = msg.get("tool_calls", []) | |
if tool_calls is None: | |
tool_calls = [] | |
for tool_call in tool_calls: | |
if tool_call is None: | |
continue | |
tool_name = tool_call.get("name", "Unknown Tool") | |
tool_args = tool_call.get("args", {}) | |
if tool_args is None: | |
tool_args = {} | |
tool_calls_html += format_tool_call(tool_name, tool_args) | |
return assistant_text.strip(), tool_calls_html | |
def format_assistant_message(msg): | |
"""Format an assistant message for display.""" | |
assistant_text, tool_calls_html = extract_assistant_content(msg) | |
return f""" | |
<div style=" | |
text-align: left; | |
margin-bottom: 1.25rem; | |
padding: 0 0.5rem;"> | |
<div style=" | |
display: inline-block; | |
max-width: 85%; | |
background-color: var(--message-bg-assistant); | |
padding: 1rem; | |
border-radius: 0 1rem 1rem 1rem; | |
color: var(--text-color); | |
text-align: left; | |
box-shadow: 0 1px 2px var(--shadow-color);"> | |
<div style=" | |
font-weight: 500; | |
margin-bottom: 0.5rem; | |
color: var(--primary-text); | |
display: flex; | |
align-items: center;"> | |
<span style="margin-right: 0.5rem;">🤖</span>Assistant | |
</div> | |
<div style="white-space: pre-wrap; line-height: 1.5;"> | |
{assistant_text} | |
</div> | |
{tool_calls_html} | |
</div> | |
</div> | |
""" | |
def format_system_message(msg): | |
"""Format a system or other message for display.""" | |
content = msg.get("content", "") | |
# Handle None content | |
if content is None: | |
content = "" | |
elif isinstance(content, (int, float)): | |
content = str(content) | |
elif isinstance(content, list): | |
content_text = "" | |
for item in content: | |
if item is None: | |
continue | |
if isinstance(item, dict) and "text" in item: | |
text_value = item.get("text", "") | |
if text_value is not None: | |
content_text += str(text_value) + "\n" | |
elif isinstance(item, str): | |
content_text += item + "\n" | |
elif item is not None: | |
content_text += str(item) + "\n" | |
content = content_text.strip() | |
return f""" | |
<div style=" | |
text-align: center; | |
margin-bottom: 1rem; | |
padding: 0 0.5rem;"> | |
<div style=" | |
display: inline-block; | |
max-width: 85%; | |
background-color: var(--message-bg-system); | |
padding: 0.75rem; | |
border-radius: 0.5rem; | |
color: var(--text-color); | |
text-align: left; | |
font-style: italic; | |
font-size: 0.9rem;"> | |
{content} | |
</div> | |
</div> | |
""" | |
def parse_complex_response(response): | |
"""Parse complex JSON response and extract text and tool calls.""" | |
try: | |
# Ensure response is a string | |
if response is None: | |
return "", "" | |
if isinstance(response, (int, float)): | |
return str(response), "" | |
# Convert to string if it's not already | |
if not isinstance(response, str): | |
response = str(response) | |
# Try to parse as JSON | |
if not response.strip().startswith("[") and not response.strip().startswith( | |
"{" | |
): | |
return response, "" | |
response_obj = json.loads(response) | |
# Handle array format like in the example | |
if isinstance(response_obj, list) and len(response_obj) > 0: | |
response_obj = response_obj[0] # Take first item in array | |
# Extract text content and tool calls | |
text_content = "" | |
tool_calls_html = "" | |
# Handle content field which can be string or list | |
if "content" in response_obj: | |
content = response_obj["content"] | |
if content is None: | |
text_content = "" | |
elif isinstance(content, str): | |
text_content = content | |
elif isinstance(content, (int, float)): | |
text_content = str(content) | |
elif isinstance(content, list): | |
# Extract only text content from items with type="text" | |
for item in content: | |
if item is None: | |
continue | |
if isinstance(item, dict): | |
if "type" in item and item["type"] == "text" and "text" in item: | |
text_value = item.get("text", "") | |
if text_value is not None: | |
text_content += str(text_value) + "\n" | |
# Get formatted tool calls if they exist | |
if "tool_calls" in response_obj: | |
tool_calls = response_obj.get("tool_calls", []) | |
if tool_calls is None: | |
tool_calls = [] | |
if tool_calls: | |
try: | |
tool_calls_html = f""" | |
<div style=" | |
background-color: var(--surface-color-alt); | |
padding: 0.75rem; | |
border-radius: 0.5rem; | |
margin-top: 0.75rem; | |
border-left: 3px solid var(--primary-text-light);"> | |
<div style=" | |
font-weight: 500; | |
margin-bottom: 0.5rem; | |
font-size: 0.9rem; | |
color: var(--primary-text);"> | |
<span style="margin-right: 0.5rem;">🔧</span>Tool Calls | |
</div> | |
<div style=" | |
font-family: monospace; | |
font-size: 0.85rem; | |
white-space: pre-wrap;"> | |
{json.dumps(tool_calls, indent=2)} | |
</div> | |
</div> | |
""" | |
except: | |
# Fallback if JSON serialization fails | |
tool_calls_html = ( | |
"<div>Tool calls present but could not be formatted.</div>" | |
) | |
return text_content.strip(), tool_calls_html | |
except Exception as e: | |
# If parsing fails, return the original response with error info | |
return f"{response}\n\nError parsing response: {str(e)}", "" | |
def format_final_response(response): | |
"""Format the final response for display.""" | |
# First try to process as complex JSON with tool calls | |
text_content, tool_calls_html = parse_complex_response(response) | |
# If that didn't work, try basic JSON parsing | |
if text_content == response: | |
# Clean up JSON response if it looks like JSON | |
if response.strip().startswith("{") and "content" in response: | |
try: | |
response_obj = json.loads(response) | |
if isinstance(response_obj, dict) and "content" in response_obj: | |
if isinstance(response_obj["content"], str): | |
text_content = response_obj["content"] | |
else: | |
text_content = json.dumps(response_obj["content"], indent=2) | |
else: | |
text_content = response | |
except: | |
text_content = response | |
else: | |
text_content = response | |
return f""" | |
<div style=" | |
text-align: left; | |
margin-bottom: 1.25rem; | |
margin-top: 1.5rem; | |
padding: 0 0.5rem;"> | |
<div style=" | |
display: inline-block; | |
max-width: 85%; | |
background-color: var(--response-bg); | |
padding: 1rem; | |
border-radius: 0 1rem 1rem 1rem; | |
color: var(--text-color); | |
text-align: left; | |
box-shadow: 0 1px 2px var(--shadow-color); | |
border-left: 4px solid var(--primary-text);"> | |
<div style=" | |
font-weight: 500; | |
margin-bottom: 0.5rem; | |
color: var(--primary-text); | |
display: flex; | |
align-items: center;"> | |
<span style="margin-right: 0.5rem;">🤖</span>Final Response | |
</div> | |
<div style=" | |
white-space: pre-wrap; | |
line-height: 1.5; | |
font-family: var(--font-sans);"> | |
{text_content} | |
</div> | |
{tool_calls_html} | |
</div> | |
</div> | |
""" | |
def update_chat_display(existing_display, new_message): | |
"""Update an existing chat display with a new message.""" | |
try: | |
# Parse the new message | |
role = new_message.get("role", "unknown").lower() | |
# Format the new message based on its role | |
if role == "user": | |
message_html = format_user_message(new_message) | |
elif role == "assistant" or role == "ai": | |
message_html = format_assistant_message(new_message) | |
else: | |
message_html = format_system_message(new_message) | |
# Find the position to insert the new message (before the Final Response section) | |
insert_marker = '<div style="padding-top: 0.5rem;margin-top: 1rem;margin-bottom: 1rem;border-top: 1px solid var(--border-color-light);' | |
parts = existing_display.split(insert_marker) | |
if len(parts) == 2: | |
# Insert the new message before the Final Response section | |
updated_display = parts[0] + message_html + insert_marker + parts[1] | |
return updated_display | |
else: | |
# If we can't find the insertion point, append to the end | |
return existing_display + message_html | |
except Exception as e: | |
return ( | |
existing_display | |
+ f""" | |
<div style=" | |
padding: 1rem; | |
color: var(--score-low); | |
background-color: var(--surface-color); | |
border: 1px solid var(--score-low); | |
border-radius: 10px; | |
margin-top: 1rem;"> | |
<div style="font-weight: 600; margin-bottom: 0.5rem;">Error Updating Chat</div> | |
<div style="font-family: monospace; white-space: pre-wrap;">{str(e)}</div> | |
</div> | |
""" | |
) | |
def format_chat_display(row): | |
"""Format the chat display with better styling for user and assistant messages.""" | |
try: | |
# Parse the conversation JSON | |
messages = json.loads(row["conversation"]) | |
# Create HTML for all messages | |
messages_html = "" | |
for msg in messages: | |
role = msg.get("role", "unknown").lower() | |
if role == "user": | |
messages_html += format_user_message(msg) | |
elif role == "assistant" or role == "ai": | |
messages_html += format_assistant_message(msg) | |
else: | |
# System or other message types | |
messages_html += format_system_message(msg) | |
# Format the final response from the assistant | |
response_html = format_final_response(row["response"]) | |
# Combine all HTML | |
full_chat_html = f""" | |
<div style=" | |
padding: 1.5rem; | |
background-color: var(--surface-color); | |
border-radius: 10px; | |
border: 1px solid var(--border-color); | |
box-shadow: 0 2px 6px var(--shadow-color); | |
height: 100%; | |
overflow-y: auto; | |
max-height: 600px; | |
font-family: var(--font-sans);"> | |
<div style=" | |
padding-bottom: 1rem; | |
margin-bottom: 1.5rem; | |
border-bottom: 1px solid var(--border-color-light); | |
display: flex; | |
align-items: center;"> | |
<div style=" | |
font-weight: 600; | |
font-size: 1.1rem; | |
color: var(--primary-text);"> | |
<span style="margin-right: 0.5rem;">💬</span>Conversation | |
</div> | |
</div> | |
{messages_html} | |
{response_html} | |
</div> | |
""" | |
return full_chat_html | |
except Exception as e: | |
return f""" | |
<div style=" | |
padding: 1.5rem; | |
color: var(--score-low); | |
background-color: var(--surface-color); | |
border: 1px solid var(--score-low); | |
border-radius: 10px;"> | |
<div style="font-weight: 600; margin-bottom: 0.5rem;">Error Formatting Chat</div> | |
<div style="font-family: monospace; white-space: pre-wrap;">{str(e)}</div> | |
<div style="margin-top: 1rem; font-family: monospace; font-size: 0.8rem;"> | |
Original conversation: {str(row["conversation"])} | |
</div> | |
</div> | |
""" | |
def parse_tool_schema(tool): | |
"""Parse tool schema to extract name, description, and parameters properly.""" | |
# Handle schema wrapped in a list | |
if isinstance(tool, list) and len(tool) > 0: | |
tool = tool[0] | |
# Extract function information from the new schema structure with "function" key | |
if "function" in tool: | |
function_data = tool["function"] | |
name = function_data.get("name", "Unnamed Tool") | |
description = function_data.get("description", "No description available") | |
parameters = {} | |
if ( | |
"parameters" in function_data | |
and "properties" in function_data["parameters"] | |
): | |
properties = function_data["parameters"]["properties"] | |
for param_name, param_data in properties.items(): | |
param_desc = param_data.get("description", "No description") | |
param_type = param_data.get("type", "unknown") | |
param_default = param_data.get("default", "None") | |
# Include default value in parameter description | |
parameters[param_name] = ( | |
f"{param_desc} (Type: {param_type}, Default: {param_default})" | |
) | |
# Check for required parameters | |
required_params = function_data.get("parameters", {}).get("required", []) | |
if required_params: | |
for param_name in required_params: | |
if param_name in parameters: | |
parameters[param_name] = f"[REQUIRED] {parameters[param_name]}" | |
else: | |
# Original schema parsing | |
name = tool.get("title", "Unnamed Tool") | |
description = tool.get("description", "No description available") | |
parameters = {} | |
if "properties" in tool: | |
for param_name, param_data in tool["properties"].items(): | |
param_desc = param_data.get("description", "No description") | |
param_type = param_data.get("type", "unknown") | |
param_title = param_data.get("title", param_name) | |
parameters[param_name] = ( | |
f"{param_desc} (Type: {param_type}, Title: {param_title})" | |
) | |
# Check for required parameters in the original schema | |
required_params = tool.get("required", []) | |
if required_params: | |
for param_name in required_params: | |
if param_name in parameters: | |
parameters[param_name] = f"[REQUIRED] {parameters[param_name]}" | |
return name, description, parameters | |
def format_parameters(parameters): | |
if not parameters: | |
return '<div style="color: var(--text-muted); font-style: italic;">No parameters</div>' | |
params_html = "" | |
for name, desc in parameters.items(): | |
is_required = "[REQUIRED]" in desc | |
param_style = "required" if is_required else "optional" | |
# Clean up the description to remove the REQUIRED marker but keep the info | |
cleaned_desc = desc.replace("[REQUIRED] ", "") if is_required else desc | |
params_html += f""" | |
<div style=" | |
margin-bottom: 1.2rem; | |
padding-bottom: 1.2rem; | |
border-bottom: 1px solid var(--border-color); | |
last-child: border-bottom: none;"> | |
<div style=" | |
display: flex; | |
align-items: center; | |
justify-content: space-between; | |
margin-bottom: 0.5rem;"> | |
<div style=" | |
font-weight: 600; | |
color: var(--primary-text); | |
font-size: 1.05rem; | |
display: flex; | |
align-items: center;"> | |
{name} | |
</div> | |
<div style=" | |
font-size: 0.8rem; | |
padding: 0.2rem 0.6rem; | |
border-radius: 12px; | |
background-color: {f"rgba(234, 67, 53, 0.1)" if is_required else "rgba(160, 160, 160, 0.1)"}; | |
color: var(--{param_style}-color); | |
font-weight: 500;"> | |
{f"Required" if is_required else "Optional"} | |
</div> | |
</div> | |
<div style=" | |
color: var(--text-color); | |
line-height: 1.5; | |
font-size: 0.95rem; | |
opacity: 0.9;"> | |
{cleaned_desc} | |
</div> | |
</div> | |
""" | |
# Remove the border-bottom from the last parameter | |
params_html = params_html.replace("last-child: border-bottom: none;", "") | |
return ( | |
params_html | |
+ """ | |
<style> | |
div:last-child { | |
border-bottom: none !important; | |
margin-bottom: 0 !important; | |
padding-bottom: 0 !important; | |
} | |
</style> | |
""" | |
) | |
def format_metrics(score, rationale, explanation): | |
"""Format metrics display with improved visual hierarchy and dark theme support.""" | |
# Determine score color and add emoji indicator | |
if score >= 0.7: | |
score_color = "var(--score-high)" | |
score_emoji = "🟢" | |
score_text = "High" | |
elif score >= 0.4: | |
score_color = "var(--score-med)" | |
score_emoji = "🟠" | |
score_text = "Medium" | |
else: | |
score_color = "var(--score-low)" | |
score_emoji = "🔴" | |
score_text = "Low" | |
return f""" | |
<div style=" | |
padding: 1.75rem; | |
background-color: var(--surface-color); | |
border-radius: 10px; | |
border: 1px solid var(--border-color); | |
box-shadow: 0 3px 8px var(--shadow-color);"> | |
<div style=" | |
display: flex; | |
align-items: center; | |
margin-bottom: 1.75rem; | |
padding-bottom: 1.5rem; | |
border-bottom: 1px solid var(--border-color-light);"> | |
<div style="flex: 1;"> | |
<h3 style=" | |
color: var(--text-color); | |
font-size: 1.2rem; | |
margin-bottom: 0.25rem; | |
font-weight: 600;">TSQ Score</h3> | |
<div style=" | |
display: flex; | |
align-items: baseline;"> | |
<div style=" | |
font-size: 2.5rem; | |
font-weight: 700; | |
color: {score_color};"> | |
{score:.2f} | |
</div> | |
<div style=" | |
margin-left: 0.75rem; | |
font-size: 1rem; | |
color: {score_color}; | |
font-weight: 500; | |
display: flex; | |
align-items: center;"> | |
<span style="margin-right: 0.5rem;">{score_emoji}</span>{score_text} | |
</div> | |
</div> | |
</div> | |
</div> | |
<div style="margin-bottom: 1.75rem;"> | |
<h3 style=" | |
color: var(--text-color); | |
font-size: 1.1rem; | |
margin-bottom: 0.75rem; | |
font-weight: 600; | |
display: flex; | |
align-items: center;"> | |
<span style=" | |
display: inline-block; | |
width: 18px; | |
height: 18px; | |
background-color: var(--primary-text-light); | |
border-radius: 4px; | |
margin-right: 0.5rem;"></span> | |
Rationale | |
</h3> | |
<div style=" | |
color: var(--text-color); | |
line-height: 1.6; | |
padding-left: 1.5rem; | |
border-left: 3px solid var(--primary-text-light); | |
font-size: 0.95rem;"> | |
{rationale} | |
</div> | |
</div> | |
<div> | |
<h3 style=" | |
color: var(--text-color); | |
font-size: 1.1rem; | |
margin-bottom: 0.75rem; | |
font-weight: 600; | |
display: flex; | |
align-items: center;"> | |
<span style=" | |
display: inline-block; | |
width: 18px; | |
height: 18px; | |
background-color: var(--primary-text-light); | |
border-radius: 4px; | |
margin-right: 0.5rem;"></span> | |
Explanation | |
</h3> | |
<div style=" | |
color: var(--text-color); | |
line-height: 1.6; | |
padding-left: 1.5rem; | |
border-left: 3px solid var(--primary-text-light); | |
font-size: 0.95rem;"> | |
{explanation} | |
</div> | |
</div> | |
</div> | |
""" | |
def format_metrics_display(row): | |
"""Format the metrics display with score, rationale and explanation.""" | |
try: | |
score = row["score"] | |
rationale = row["rationale"] | |
explanation = row["explanation"] | |
# Determine score color and add emoji indicator | |
if score >= 0.7: | |
score_color = "var(--score-high)" | |
score_emoji = "🟢" | |
score_text = "High" | |
elif score >= 0.4: | |
score_color = "var(--score-med)" | |
score_emoji = "🟠" | |
score_text = "Medium" | |
else: | |
score_color = "var(--score-low)" | |
score_emoji = "🔴" | |
score_text = "Low" | |
metrics_html = f""" | |
<div style=" | |
padding: 1.5rem; | |
background-color: var(--surface-color); | |
border-radius: 10px; | |
border: 1px solid var(--border-color); | |
box-shadow: 0 2px 6px var(--shadow-color); | |
height: 100%; | |
overflow-y: auto; | |
max-height: 600px;"> | |
<div style=" | |
padding-bottom: 1rem; | |
margin-bottom: 1.5rem; | |
border-bottom: 1px solid var(--border-color-light); | |
display: flex; | |
align-items: center;"> | |
<div style=" | |
font-weight: 600; | |
font-size: 1.1rem; | |
color: var(--primary-text);"> | |
<span style="margin-right: 0.5rem;">📊</span>Evaluation Metrics | |
</div> | |
</div> | |
<div style=" | |
margin-bottom: 1.5rem; | |
padding-bottom: 1.5rem; | |
border-bottom: 1px solid var(--border-color-light);"> | |
<div style=" | |
display: flex; | |
align-items: center; | |
justify-content: space-between;"> | |
<div> | |
<div style=" | |
font-weight: 600; | |
margin-bottom: 0.25rem; | |
color: var(--text-color);"> | |
TSQ Score | |
</div> | |
<div style=" | |
font-size: 2.5rem; | |
font-weight: 700; | |
color: {score_color}; | |
display: flex; | |
align-items: center;"> | |
{score:.2f} | |
<div style=" | |
margin-left: 0.75rem; | |
font-size: 1rem; | |
display: flex; | |
align-items: center;"> | |
{score_emoji} <span style="margin-left: 0.25rem;">{score_text}</span> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
<div style="margin-bottom: 1.5rem;"> | |
<div style=" | |
font-weight: 600; | |
margin-bottom: 0.75rem; | |
color: var(--text-color); | |
display: flex; | |
align-items: center;"> | |
<span style=" | |
display: inline-block; | |
width: 12px; | |
height: 12px; | |
background-color: var(--primary-text-light); | |
border-radius: 2px; | |
margin-right: 0.5rem;"></span> | |
Rationale | |
</div> | |
<div style=" | |
background-color: var(--surface-color-alt); | |
padding: 1rem; | |
border-radius: 8px; | |
border-left: 3px solid var(--primary-text-light); | |
line-height: 1.5; | |
color: var(--text-color); | |
font-size: 0.95rem;"> | |
{rationale} | |
</div> | |
</div> | |
<div> | |
<div style=" | |
font-weight: 600; | |
margin-bottom: 0.75rem; | |
color: var(--text-color); | |
display: flex; | |
align-items: center;"> | |
<span style=" | |
display: inline-block; | |
width: 12px; | |
height: 12px; | |
background-color: var(--primary-text-light); | |
border-radius: 2px; | |
margin-right: 0.5rem;"></span> | |
Explanation | |
</div> | |
<div style=" | |
background-color: var(--surface-color-alt); | |
padding: 1rem; | |
border-radius: 8px; | |
border-left: 3px solid var(--primary-text-light); | |
line-height: 1.5; | |
color: var(--text-color); | |
font-size: 0.95rem;"> | |
{explanation} | |
</div> | |
</div> | |
</div> | |
""" | |
return metrics_html | |
except Exception as e: | |
return f""" | |
<div style=" | |
padding: 1.5rem; | |
color: var(--score-low); | |
background-color: var(--surface-color); | |
border: 1px solid var(--score-low); | |
border-radius: 10px;"> | |
<div style="font-weight: 600; margin-bottom: 0.5rem;">Error Formatting Metrics</div> | |
<div style="font-family: monospace; white-space: pre-wrap;">{str(e)}</div> | |
</div> | |
""" | |
def format_tool_info(tools_data): | |
"""Format the tool information with improved styling.""" | |
try: | |
if not tools_data or tools_data == "[]": | |
return """ | |
<div style=" | |
padding: 1.5rem; | |
text-align: center; | |
color: var(--text-muted); | |
background-color: var(--surface-color); | |
border-radius: 10px; | |
border: 1px solid var(--border-color); | |
box-shadow: 0 2px 6px var(--shadow-color);"> | |
<div style="font-size: 1.5rem; margin-bottom: 0.75rem;">🔍</div> | |
<div style="font-weight: 500; margin-bottom: 0.5rem;">No Tool Information</div> | |
<div style="font-size: 0.9rem; font-style: italic;">This conversation doesn't use any tools</div> | |
</div> | |
""" | |
if isinstance(tools_data, str): | |
try: | |
tools = json.loads(tools_data) | |
except: | |
tools = [] | |
else: | |
tools = tools_data | |
if not tools: | |
return """ | |
<div style=" | |
padding: 1.5rem; | |
text-align: center; | |
color: var(--text-muted); | |
background-color: var(--surface-color); | |
border-radius: 10px; | |
border: 1px solid var(--border-color); | |
box-shadow: 0 2px 6px var(--shadow-color);"> | |
<div style="font-size: 1.5rem; margin-bottom: 0.75rem;">🔍</div> | |
<div style="font-weight: 500; margin-bottom: 0.5rem;">No Tool Information</div> | |
<div style="font-size: 0.9rem; font-style: italic;">This conversation doesn't use any tools</div> | |
</div> | |
""" | |
# Format each tool | |
tool_items = "" | |
for tool in tools: | |
name = tool.get("title", tool.get("name", "Unnamed Tool")) | |
description = tool.get("description", "No description available") | |
# Get parameters | |
parameters = {} | |
required_params = [] | |
# Handle different schema formats | |
if "function" in tool: | |
# Function schema format | |
function_data = tool["function"] | |
name = function_data.get("name", name) | |
description = function_data.get("description", description) | |
if ( | |
"parameters" in function_data | |
and "properties" in function_data["parameters"] | |
): | |
properties = function_data["parameters"]["properties"] | |
for param_name, param_data in properties.items(): | |
param_desc = param_data.get("description", "No description") | |
param_type = param_data.get("type", "unknown") | |
param_default = param_data.get("default", "None") | |
parameters[param_name] = { | |
"description": param_desc, | |
"type": param_type, | |
"default": param_default, | |
} | |
required_params = function_data.get("parameters", {}).get( | |
"required", [] | |
) | |
elif "properties" in tool: | |
# Original schema format | |
if "properties" in tool: | |
for param_name, param_data in tool["properties"].items(): | |
param_desc = param_data.get("description", "No description") | |
param_type = param_data.get("type", "unknown") | |
param_title = param_data.get("title", param_name) | |
parameters[param_name] = { | |
"description": param_desc, | |
"type": param_type, | |
"title": param_title, | |
} | |
required_params = tool.get("required", []) | |
# Format parameters | |
params_html = "" | |
if parameters: | |
for param_name, param_data in parameters.items(): | |
is_required = param_name in required_params | |
param_style = "required" if is_required else "optional" | |
params_html += f""" | |
<div style=" | |
margin-bottom: 1rem; | |
padding-bottom: 1rem; | |
border-bottom: 1px solid var(--border-color-light);"> | |
<div style=" | |
display: flex; | |
align-items: center; | |
justify-content: space-between; | |
margin-bottom: 0.5rem;"> | |
<div style=" | |
font-weight: 600; | |
color: var(--primary-text); | |
font-size: 0.95rem;"> | |
{param_name} | |
</div> | |
<div style=" | |
font-size: 0.75rem; | |
padding: 0.15rem 0.5rem; | |
border-radius: 12px; | |
background-color: {f"rgba(234, 67, 53, 0.1)" if is_required else "rgba(160, 160, 160, 0.1)"}; | |
color: {f"var(--score-low)" if is_required else "var(--text-muted)"}; | |
font-weight: 500;"> | |
{f"Required" if is_required else "Optional"} | |
</div> | |
</div> | |
<div style=" | |
color: var(--text-muted); | |
line-height: 1.5; | |
font-size: 0.85rem; | |
margin-bottom: 0.25rem;"> | |
{param_data.get("description", "No description")} | |
</div> | |
<div style=" | |
display: flex; | |
font-size: 0.8rem; | |
color: var(--text-muted);"> | |
<div style="margin-right: 1rem;"> | |
<span style="font-weight: 500;">Type:</span> {param_data.get("type", "unknown")} | |
</div> | |
{f'<div><span style="font-weight: 500;">Default:</span> {param_data.get("default", "None")}</div>' if "default" in param_data else ''} | |
</div> | |
</div> | |
""" | |
else: | |
params_html = """ | |
<div style=" | |
color: var(--text-muted); | |
font-style: italic; | |
padding: 0.75rem; | |
text-align: center; | |
font-size: 0.9rem;"> | |
No parameters | |
</div> | |
""" | |
# Remove border from last parameter | |
params_html += """ | |
<style> | |
.tool-params > div:last-child { | |
border-bottom: none !important; | |
margin-bottom: 0 !important; | |
padding-bottom: 0 !important; | |
} | |
</style> | |
""" | |
tool_items += f""" | |
<div style=" | |
margin-bottom: 1.5rem; | |
padding: 1.5rem; | |
border-radius: 8px; | |
background-color: var(--surface-color-alt); | |
border: 1px solid var(--border-color); | |
box-shadow: 0 1px 3px var(--shadow-color);"> | |
<div style=" | |
font-weight: 600; | |
color: var(--primary-text); | |
margin-bottom: 0.75rem; | |
font-size: 1.05rem; | |
display: flex; | |
align-items: center;"> | |
<span style="margin-right: 8px;">⚙️</span> {name} | |
</div> | |
<div style=" | |
color: var(--text-color); | |
margin-bottom: 1.25rem; | |
line-height: 1.5; | |
font-size: 0.95rem; | |
padding-left: 0.5rem; | |
border-left: 3px solid var(--primary-text-light);"> | |
{description} | |
</div> | |
<div style=" | |
font-weight: 600; | |
color: var(--text-color); | |
margin-bottom: 0.75rem; | |
font-size: 0.9rem;"> | |
Parameters: | |
</div> | |
<div class="tool-params"> | |
{params_html} | |
</div> | |
</div> | |
""" | |
full_tools_html = f""" | |
<div style=" | |
padding: 1.5rem; | |
background-color: var(--surface-color); | |
border-radius: 10px; | |
border: 1px solid var(--border-color); | |
box-shadow: 0 2px 6px var(--shadow-color); | |
height: 100%; | |
overflow-y: auto; | |
max-height: 600px;"> | |
<div style=" | |
padding-bottom: 1rem; | |
margin-bottom: 1.5rem; | |
border-bottom: 1px solid var(--border-color-light); | |
display: flex; | |
align-items: center;"> | |
<div style=" | |
font-weight: 600; | |
font-size: 1.1rem; | |
color: var(--primary-text);"> | |
<span style="margin-right: 0.5rem;">🛠️</span>Available Tools | |
</div> | |
</div> | |
{tool_items} | |
</div> | |
""" | |
return full_tools_html | |
except Exception as e: | |
return f""" | |
<div style=" | |
padding: 1.5rem; | |
color: var(--score-low); | |
background-color: var(--surface-color); | |
border: 1px solid var(--score-low); | |
border-radius: 10px;"> | |
<div style="font-weight: 600; margin-bottom: 0.5rem;">Error Formatting Tool Info</div> | |
<div style="font-family: monospace; white-space: pre-wrap;">{str(e)}</div> | |
</div> | |
""" | |