fix: tool call dot phases and colors for clearer execution feedback
Tool call dot/phase behavior: - Tool calls start in streaming phase (static grey) instead of ready - Added approvalsPending flag to prevent server tools from blinking during approval - Server tools promoted to running only after approvals complete Tool dot colors: - Fixed missing # in statusWarning hex literal - Running phase uses grey blinking instead of yellow Args rendering + crash fixes: - Args considered "complete" by JSON parseability, not just phase - Coerce argsText to string to avoid runtime errors - Fixed TDZ error from shadowed variable - Ready phase only blinks once streaming finished Behavioral fixes: - Server-side tools don't show "Cancelled" after approvals - Mixed server/client tools: server stays static during approval, blinks after - Args remain visible once complete 👾 Generated with [Letta Code](https://letta.com) Co-Authored-By: Letta <noreply@letta.com>
This commit is contained in:
@@ -104,7 +104,12 @@ export const ToolCallMessage = memo(
|
||||
|
||||
// Parse and format the tool call
|
||||
const rawName = line.name ?? "?";
|
||||
const argsText = line.argsText ?? "...";
|
||||
const argsText =
|
||||
typeof line.argsText === "string"
|
||||
? line.argsText
|
||||
: line.argsText == null
|
||||
? ""
|
||||
: JSON.stringify(line.argsText);
|
||||
|
||||
// Task tool rendering decision:
|
||||
// - Cancelled/rejected: render as error tool call (won't appear in SubagentGroupDisplay)
|
||||
@@ -165,16 +170,35 @@ export const ToolCallMessage = memo(
|
||||
// - Phase "running"/"finished" or stream done: args complete, show formatted
|
||||
let args = "";
|
||||
if (!isQuestionTool(rawName)) {
|
||||
// Args are complete once running, finished, or stream is done
|
||||
const parseArgs = (): {
|
||||
formatted: ReturnType<typeof formatArgsDisplay> | null;
|
||||
parseable: boolean;
|
||||
} => {
|
||||
if (!argsText.trim()) {
|
||||
return { formatted: null, parseable: true };
|
||||
}
|
||||
try {
|
||||
const formatted = formatArgsDisplay(argsText, rawName);
|
||||
return { formatted, parseable: true };
|
||||
} catch {
|
||||
return { formatted: null, parseable: false };
|
||||
}
|
||||
};
|
||||
|
||||
// Args are complete once running/finished, stream done, or JSON is parseable.
|
||||
const { formatted, parseable } = parseArgs();
|
||||
const argsComplete =
|
||||
line.phase === "running" || line.phase === "finished" || !isStreaming;
|
||||
parseable ||
|
||||
line.phase === "running" ||
|
||||
line.phase === "finished" ||
|
||||
!isStreaming;
|
||||
|
||||
if (!argsComplete) {
|
||||
args = "(…)";
|
||||
} else {
|
||||
const formatted = formatArgsDisplay(argsText, rawName);
|
||||
const formattedArgs = formatted ?? formatArgsDisplay(argsText, rawName);
|
||||
// Normalize newlines to spaces to prevent forced line breaks
|
||||
const normalizedDisplay = formatted.display.replace(/\n/g, " ");
|
||||
const normalizedDisplay = formattedArgs.display.replace(/\n/g, " ");
|
||||
// For max 2 lines: boxWidth * 2, minus parens (2) and margin (2)
|
||||
const argsBoxWidth = rightWidth - displayName.length;
|
||||
const maxArgsChars = Math.max(0, argsBoxWidth * 2 - 4);
|
||||
@@ -206,7 +230,8 @@ export const ToolCallMessage = memo(
|
||||
return undefined;
|
||||
}
|
||||
})();
|
||||
const dotShouldAnimate = line.phase === "ready" || line.phase === "running";
|
||||
const dotShouldAnimate =
|
||||
line.phase === "running" || (line.phase === "ready" && !isStreaming);
|
||||
|
||||
// Format result for display
|
||||
const getResultElement = () => {
|
||||
|
||||
@@ -47,7 +47,7 @@ export const brandColors = {
|
||||
textDisabled: "#46484A", // dark grey
|
||||
// status colors
|
||||
statusSuccess: "#64CF64", // green
|
||||
statusWarning: "FEE19C", // yellow
|
||||
statusWarning: "#FEE19C", // yellow
|
||||
statusError: "#F1689F", // red
|
||||
} as const;
|
||||
|
||||
@@ -126,8 +126,8 @@ const _colors = {
|
||||
tool: {
|
||||
pending: brandColors.textSecondary, // blinking dot (ready/waiting for approval)
|
||||
completed: brandColors.statusSuccess, // solid green dot (finished successfully)
|
||||
streaming: brandColors.textDisabled, // solid gray dot (streaming/in progress)
|
||||
running: brandColors.statusWarning, // blinking yellow dot (executing)
|
||||
streaming: brandColors.textSecondary, // solid gray dot (streaming/in progress)
|
||||
running: brandColors.textSecondary, // blinking gray dot (executing)
|
||||
error: brandColors.statusError, // solid red dot (failed)
|
||||
memoryName: brandColors.primaryAccent, // memory tool name highlight (matches thinking spinner)
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user