diff --git a/bundled-skills/last30days/scripts/last30days.py b/bundled-skills/last30days/scripts/last30days.py index c6b119f..b62e515 100644 --- a/bundled-skills/last30days/scripts/last30days.py +++ b/bundled-skills/last30days/scripts/last30days.py @@ -145,6 +145,7 @@ from lib import ( schema, score, ui, + websearch, xai_x, youtube_yt, ) diff --git a/src/components/chat/message-bubble.tsx b/src/components/chat/message-bubble.tsx index 2cc13ee..851c5e7 100644 --- a/src/components/chat/message-bubble.tsx +++ b/src/components/chat/message-bubble.tsx @@ -25,6 +25,35 @@ export function MessageBubble({ message }: MessageBubbleProps) { (p) => p.type.startsWith("tool-") || p.type === "dynamic-tool" ); + // The agent often emits final answers via the `response` tool with no text part. + // Surface that output as regular assistant text so the user always sees it. + const responseToolText = toolParts + .map((part) => { + if (part.type === "dynamic-tool") { + const dp = part as { + toolName?: string; + state?: string; + output?: unknown; + }; + if (dp.toolName !== "response" || dp.state !== "output-available") return ""; + return typeof dp.output === "string" ? dp.output : JSON.stringify(dp.output ?? ""); + } + + if (!part.type.startsWith("tool-")) return ""; + const tp = part as { + type: string; + state?: string; + output?: unknown; + }; + const toolName = tp.type.replace("tool-", ""); + if (toolName !== "response" || tp.state !== "output-available") return ""; + return typeof tp.output === "string" ? tp.output : JSON.stringify(tp.output ?? ""); + }) + .filter(Boolean) + .join("\n\n"); + + const visibleTextContent = textContent || responseToolText; + return (
{textContent}
+{visibleTextContent}
) : (