fix: handle string results in tool renderers
Previously, tool renderers assumed result was always a dict and would crash with AttributeError when result was a string (e.g., error messages). Now all renderers properly check for string results and display them.
This commit is contained in:
@@ -110,6 +110,9 @@ class StrReplaceEditorRenderer(BaseToolRenderer):
|
|||||||
text.append(" ")
|
text.append(" ")
|
||||||
text.append(line)
|
text.append(line)
|
||||||
|
|
||||||
|
elif isinstance(result, str) and result.strip():
|
||||||
|
text.append("\n ")
|
||||||
|
text.append(result.strip(), style="dim")
|
||||||
elif not (result and isinstance(result, dict) and "content" in result) and not path:
|
elif not (result and isinstance(result, dict) and "content" in result) and not path:
|
||||||
text.append(" ")
|
text.append(" ")
|
||||||
text.append("Processing...", style="dim")
|
text.append("Processing...", style="dim")
|
||||||
|
|||||||
@@ -102,7 +102,10 @@ class ListNotesRenderer(BaseToolRenderer):
|
|||||||
text.append("📝 ")
|
text.append("📝 ")
|
||||||
text.append("Notes", style="bold #fbbf24")
|
text.append("Notes", style="bold #fbbf24")
|
||||||
|
|
||||||
if result and isinstance(result, dict) and result.get("success"):
|
if isinstance(result, str) and result.strip():
|
||||||
|
text.append("\n ")
|
||||||
|
text.append(result.strip(), style="dim")
|
||||||
|
elif result and isinstance(result, dict) and result.get("success"):
|
||||||
count = result.get("total_count", 0)
|
count = result.get("total_count", 0)
|
||||||
notes = result.get("notes", []) or []
|
notes = result.get("notes", []) or []
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,10 @@ class ListRequestsRenderer(BaseToolRenderer):
|
|||||||
text.append("📋 ")
|
text.append("📋 ")
|
||||||
text.append("Listing requests", style="bold #06b6d4")
|
text.append("Listing requests", style="bold #06b6d4")
|
||||||
|
|
||||||
if result and isinstance(result, dict) and "requests" in result:
|
if isinstance(result, str) and result.strip():
|
||||||
|
text.append("\n ")
|
||||||
|
text.append(result.strip(), style="dim")
|
||||||
|
elif result and isinstance(result, dict) and "requests" in result:
|
||||||
requests = result["requests"]
|
requests = result["requests"]
|
||||||
if isinstance(requests, list) and requests:
|
if isinstance(requests, list) and requests:
|
||||||
for req in requests[:25]:
|
for req in requests[:25]:
|
||||||
@@ -70,7 +73,10 @@ class ViewRequestRenderer(BaseToolRenderer):
|
|||||||
text.append("👀 ")
|
text.append("👀 ")
|
||||||
text.append(f"Viewing {part}", style="bold #06b6d4")
|
text.append(f"Viewing {part}", style="bold #06b6d4")
|
||||||
|
|
||||||
if result and isinstance(result, dict):
|
if isinstance(result, str) and result.strip():
|
||||||
|
text.append("\n ")
|
||||||
|
text.append(result.strip(), style="dim")
|
||||||
|
elif result and isinstance(result, dict):
|
||||||
if "content" in result:
|
if "content" in result:
|
||||||
content = result["content"]
|
content = result["content"]
|
||||||
content_preview = content[:2000] + "..." if len(content) > 2000 else content
|
content_preview = content[:2000] + "..." if len(content) > 2000 else content
|
||||||
@@ -117,7 +123,10 @@ class SendRequestRenderer(BaseToolRenderer):
|
|||||||
text.append("📤 ")
|
text.append("📤 ")
|
||||||
text.append(f"Sending {method}", style="bold #06b6d4")
|
text.append(f"Sending {method}", style="bold #06b6d4")
|
||||||
|
|
||||||
if result and isinstance(result, dict):
|
if isinstance(result, str) and result.strip():
|
||||||
|
text.append("\n ")
|
||||||
|
text.append(result.strip(), style="dim")
|
||||||
|
elif result and isinstance(result, dict):
|
||||||
status_code = result.get("status_code")
|
status_code = result.get("status_code")
|
||||||
response_body = result.get("body", "")
|
response_body = result.get("body", "")
|
||||||
|
|
||||||
@@ -161,7 +170,10 @@ class RepeatRequestRenderer(BaseToolRenderer):
|
|||||||
text.append("🔄 ")
|
text.append("🔄 ")
|
||||||
text.append("Repeating request", style="bold #06b6d4")
|
text.append("Repeating request", style="bold #06b6d4")
|
||||||
|
|
||||||
if result and isinstance(result, dict):
|
if isinstance(result, str) and result.strip():
|
||||||
|
text.append("\n ")
|
||||||
|
text.append(result.strip(), style="dim")
|
||||||
|
elif result and isinstance(result, dict):
|
||||||
status_code = result.get("status_code")
|
status_code = result.get("status_code")
|
||||||
response_body = result.get("body", "")
|
response_body = result.get("body", "")
|
||||||
|
|
||||||
@@ -220,7 +232,10 @@ class ListSitemapRenderer(BaseToolRenderer):
|
|||||||
text.append("🗺️ ")
|
text.append("🗺️ ")
|
||||||
text.append("Listing sitemap", style="bold #06b6d4")
|
text.append("Listing sitemap", style="bold #06b6d4")
|
||||||
|
|
||||||
if result and isinstance(result, dict) and "entries" in result:
|
if isinstance(result, str) and result.strip():
|
||||||
|
text.append("\n ")
|
||||||
|
text.append(result.strip(), style="dim")
|
||||||
|
elif result and isinstance(result, dict) and "entries" in result:
|
||||||
entries = result["entries"]
|
entries = result["entries"]
|
||||||
if isinstance(entries, list) and entries:
|
if isinstance(entries, list) and entries:
|
||||||
for entry in entries[:30]:
|
for entry in entries[:30]:
|
||||||
@@ -256,7 +271,10 @@ class ViewSitemapEntryRenderer(BaseToolRenderer):
|
|||||||
text.append("📍 ")
|
text.append("📍 ")
|
||||||
text.append("Viewing sitemap entry", style="bold #06b6d4")
|
text.append("Viewing sitemap entry", style="bold #06b6d4")
|
||||||
|
|
||||||
if result and isinstance(result, dict) and "entry" in result:
|
if isinstance(result, str) and result.strip():
|
||||||
|
text.append("\n ")
|
||||||
|
text.append(result.strip(), style="dim")
|
||||||
|
elif result and isinstance(result, dict) and "entry" in result:
|
||||||
entry = result["entry"]
|
entry = result["entry"]
|
||||||
if isinstance(entry, dict):
|
if isinstance(entry, dict):
|
||||||
label = entry.get("label", "")
|
label = entry.get("label", "")
|
||||||
|
|||||||
@@ -104,7 +104,13 @@ class PythonRenderer(BaseToolRenderer):
|
|||||||
return text
|
return text
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _append_output(cls, text: Text, result: dict[str, Any]) -> None:
|
def _append_output(cls, text: Text, result: dict[str, Any] | str) -> None:
|
||||||
|
if isinstance(result, str):
|
||||||
|
if result.strip():
|
||||||
|
text.append("\n")
|
||||||
|
text.append_text(cls._format_output(result))
|
||||||
|
return
|
||||||
|
|
||||||
stdout = result.get("stdout", "")
|
stdout = result.get("stdout", "")
|
||||||
stderr = result.get("stderr", "")
|
stderr = result.get("stderr", "")
|
||||||
|
|
||||||
@@ -143,7 +149,7 @@ class PythonRenderer(BaseToolRenderer):
|
|||||||
else:
|
else:
|
||||||
text.append("Running...", style="dim")
|
text.append("Running...", style="dim")
|
||||||
|
|
||||||
if result and isinstance(result, dict):
|
if result:
|
||||||
cls._append_output(text, result)
|
cls._append_output(text, result)
|
||||||
|
|
||||||
css_classes = cls.get_css_classes(status)
|
css_classes = cls.get_css_classes(status)
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ class TerminalRenderer(BaseToolRenderer):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _build_content(
|
def _build_content(
|
||||||
cls, command: str, is_input: bool, status: str, result: dict[str, Any] | None
|
cls, command: str, is_input: bool, status: str, result: dict[str, Any] | str | None
|
||||||
) -> Text:
|
) -> Text:
|
||||||
text = Text()
|
text = Text()
|
||||||
terminal_icon = ">_"
|
terminal_icon = ">_"
|
||||||
@@ -208,8 +208,14 @@ class TerminalRenderer(BaseToolRenderer):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _append_output(
|
def _append_output(
|
||||||
cls, text: Text, result: dict[str, Any], tool_status: str, command: str = ""
|
cls, text: Text, result: dict[str, Any] | str, tool_status: str, command: str = ""
|
||||||
) -> None:
|
) -> None:
|
||||||
|
if isinstance(result, str):
|
||||||
|
if result.strip():
|
||||||
|
text.append("\n")
|
||||||
|
text.append_text(cls._format_output(result))
|
||||||
|
return
|
||||||
|
|
||||||
raw_output = result.get("content", "")
|
raw_output = result.get("content", "")
|
||||||
output = cls._clean_output(raw_output, command)
|
output = cls._clean_output(raw_output, command)
|
||||||
error = result.get("error")
|
error = result.get("error")
|
||||||
|
|||||||
@@ -52,7 +52,10 @@ class CreateTodoRenderer(BaseToolRenderer):
|
|||||||
text.append("📋 ")
|
text.append("📋 ")
|
||||||
text.append("Todo", style="bold #a78bfa")
|
text.append("Todo", style="bold #a78bfa")
|
||||||
|
|
||||||
if result and isinstance(result, dict):
|
if isinstance(result, str) and result.strip():
|
||||||
|
text.append("\n ")
|
||||||
|
text.append(result.strip(), style="dim")
|
||||||
|
elif result and isinstance(result, dict):
|
||||||
if result.get("success"):
|
if result.get("success"):
|
||||||
_format_todo_lines(text, result)
|
_format_todo_lines(text, result)
|
||||||
else:
|
else:
|
||||||
@@ -80,7 +83,10 @@ class ListTodosRenderer(BaseToolRenderer):
|
|||||||
text.append("📋 ")
|
text.append("📋 ")
|
||||||
text.append("Todos", style="bold #a78bfa")
|
text.append("Todos", style="bold #a78bfa")
|
||||||
|
|
||||||
if result and isinstance(result, dict):
|
if isinstance(result, str) and result.strip():
|
||||||
|
text.append("\n ")
|
||||||
|
text.append(result.strip(), style="dim")
|
||||||
|
elif result and isinstance(result, dict):
|
||||||
if result.get("success"):
|
if result.get("success"):
|
||||||
_format_todo_lines(text, result)
|
_format_todo_lines(text, result)
|
||||||
else:
|
else:
|
||||||
@@ -108,7 +114,10 @@ class UpdateTodoRenderer(BaseToolRenderer):
|
|||||||
text.append("📋 ")
|
text.append("📋 ")
|
||||||
text.append("Todo Updated", style="bold #a78bfa")
|
text.append("Todo Updated", style="bold #a78bfa")
|
||||||
|
|
||||||
if result and isinstance(result, dict):
|
if isinstance(result, str) and result.strip():
|
||||||
|
text.append("\n ")
|
||||||
|
text.append(result.strip(), style="dim")
|
||||||
|
elif result and isinstance(result, dict):
|
||||||
if result.get("success"):
|
if result.get("success"):
|
||||||
_format_todo_lines(text, result)
|
_format_todo_lines(text, result)
|
||||||
else:
|
else:
|
||||||
@@ -136,7 +145,10 @@ class MarkTodoDoneRenderer(BaseToolRenderer):
|
|||||||
text.append("📋 ")
|
text.append("📋 ")
|
||||||
text.append("Todo Completed", style="bold #a78bfa")
|
text.append("Todo Completed", style="bold #a78bfa")
|
||||||
|
|
||||||
if result and isinstance(result, dict):
|
if isinstance(result, str) and result.strip():
|
||||||
|
text.append("\n ")
|
||||||
|
text.append(result.strip(), style="dim")
|
||||||
|
elif result and isinstance(result, dict):
|
||||||
if result.get("success"):
|
if result.get("success"):
|
||||||
_format_todo_lines(text, result)
|
_format_todo_lines(text, result)
|
||||||
else:
|
else:
|
||||||
@@ -164,7 +176,10 @@ class MarkTodoPendingRenderer(BaseToolRenderer):
|
|||||||
text.append("📋 ")
|
text.append("📋 ")
|
||||||
text.append("Todo Reopened", style="bold #f59e0b")
|
text.append("Todo Reopened", style="bold #f59e0b")
|
||||||
|
|
||||||
if result and isinstance(result, dict):
|
if isinstance(result, str) and result.strip():
|
||||||
|
text.append("\n ")
|
||||||
|
text.append(result.strip(), style="dim")
|
||||||
|
elif result and isinstance(result, dict):
|
||||||
if result.get("success"):
|
if result.get("success"):
|
||||||
_format_todo_lines(text, result)
|
_format_todo_lines(text, result)
|
||||||
else:
|
else:
|
||||||
@@ -192,7 +207,10 @@ class DeleteTodoRenderer(BaseToolRenderer):
|
|||||||
text.append("📋 ")
|
text.append("📋 ")
|
||||||
text.append("Todo Removed", style="bold #94a3b8")
|
text.append("Todo Removed", style="bold #94a3b8")
|
||||||
|
|
||||||
if result and isinstance(result, dict):
|
if isinstance(result, str) and result.strip():
|
||||||
|
text.append("\n ")
|
||||||
|
text.append(result.strip(), style="dim")
|
||||||
|
elif result and isinstance(result, dict):
|
||||||
if result.get("success"):
|
if result.get("success"):
|
||||||
_format_todo_lines(text, result)
|
_format_todo_lines(text, result)
|
||||||
else:
|
else:
|
||||||
|
|||||||
Reference in New Issue
Block a user