+ {msg.role === "user" ? (
+
+ ) : (
+
+ {/* Tool calls for this message */}
+ {msg.toolCalls && msg.toolCalls.length > 0 && (
+
+ {msg.toolCalls.map((tc, tcIdx) => (
+
+ ))}
+
+ )}
+ {/* Response */}
+
+
+
+
+ )}
-
+ {/* Active tool calls (in-progress) */}
+ {isLoading && activeToolCalls.length > 0 && (
+
+ {activeToolCalls.map((tc, idx) => (
+
+ ))}
)}
+ {/* Status / spinner */}
{isLoading && !streamingContent && (
-
-
-
- {statusMessage && (
- {statusMessage}
- )}
-
+
+
+ {statusMessage || "Thinking..."}
+
+ )}
+
+ {/* Streaming response */}
+ {streamingContent && (
+
+
)}
diff --git a/ui/litellm-dashboard/src/components/networking.tsx b/ui/litellm-dashboard/src/components/networking.tsx
index 57e4030b818..322676f1e23 100644
--- a/ui/litellm-dashboard/src/components/networking.tsx
+++ b/ui/litellm-dashboard/src/components/networking.tsx
@@ -5907,6 +5907,14 @@ export const enrichPolicyTemplateStream = async (
}
};
+export interface UsageAiToolCallEvent {
+ tool_name: string;
+ tool_label: string;
+ arguments: Record
;
+ status: "running" | "complete" | "error";
+ error?: string;
+}
+
export const usageAiChatStream = async (
accessToken: string,
messages: { role: string; content: string }[],
@@ -5915,6 +5923,7 @@ export const usageAiChatStream = async (
onDone: () => void,
onError?: (error: string) => void,
onStatus?: (message: string) => void,
+ onToolCall?: (event: UsageAiToolCallEvent) => void,
signal?: AbortSignal,
) => {
const url = proxyBaseUrl
@@ -5960,6 +5969,8 @@ export const usageAiChatStream = async (
onChunk(event.content);
} else if (event.type === "status") {
onStatus?.(event.message);
+ } else if (event.type === "tool_call") {
+ onToolCall?.(event as UsageAiToolCallEvent);
} else if (event.type === "done") {
onDone();
} else if (event.type === "error") {