>({});
+
+ if (!searchResults || searchResults.length === 0) {
+ return null;
+ }
+
+ const toggleResult = (pageIndex: number, resultIndex: number) => {
+ const key = `${pageIndex}-${resultIndex}`;
+ setExpandedResults((prev) => ({
+ ...prev,
+ [key]: !prev[key],
+ }));
+ };
+
+ const totalResults = searchResults.reduce((sum, page) => sum + page.data.length, 0);
+
+ return (
+
+
+
+ {isExpanded && (
+
+
+ {searchResults.map((resultPage, pageIndex) => (
+
+
+ Query:
+ "{resultPage.search_query}"
+ •
+ {resultPage.data.length} result{resultPage.data.length !== 1 ? 's' : ''}
+
+
+
+ {resultPage.data.map((result, resultIndex) => {
+ const isResultExpanded = expandedResults[`${pageIndex}-${resultIndex}`] || false;
+
+ return (
+
+
toggleResult(pageIndex, resultIndex)}
+ >
+
+
+
+
+ {result.filename || result.file_id || `Result ${resultIndex + 1}`}
+
+
+ {result.score.toFixed(3)}
+
+
+
+
+ {isResultExpanded && (
+
+
+ {result.content.map((content, contentIndex) => (
+
+ ))}
+
+ {result.attributes && Object.keys(result.attributes).length > 0 && (
+
+
Metadata:
+
+ {Object.entries(result.attributes).map(([key, value]) => (
+
+ {key}:
+ {String(value)}
+
+ ))}
+
+
+ )}
+
+
+ )}
+
+ );
+ })}
+
+
+ ))}
+
+
+ )}
+
+ );
+}
+
diff --git a/ui/litellm-dashboard/src/components/chat_ui/llm_calls/chat_completion.tsx b/ui/litellm-dashboard/src/components/chat_ui/llm_calls/chat_completion.tsx
index 44aea48986bb..7baad24e48c4 100644
--- a/ui/litellm-dashboard/src/components/chat_ui/llm_calls/chat_completion.tsx
+++ b/ui/litellm-dashboard/src/components/chat_ui/llm_calls/chat_completion.tsx
@@ -1,6 +1,7 @@
import openai from "openai";
import { ChatCompletionMessageParam } from "openai/resources/chat/completions";
import { TokenUsage } from "../ResponseMetrics";
+import { VectorStoreSearchResponse } from "../types";
import { getProxyBaseUrl } from "@/components/networking";
export async function makeOpenAIChatCompletionRequest(
@@ -18,6 +19,7 @@ export async function makeOpenAIChatCompletionRequest(
guardrails?: string[],
selectedMCPTools?: string[],
onImageGenerated?: (imageUrl: string, model?: string) => void,
+ onSearchResults?: (searchResults: VectorStoreSearchResponse[]) => void,
) {
// base url should be the current base_url
const isLocal = process.env.NODE_ENV === "development";
@@ -127,6 +129,12 @@ export async function makeOpenAIChatCompletionRequest(
fullReasoningContent += reasoningContent;
}
+ // Check for search results in provider_specific_fields
+ if (delta && delta.provider_specific_fields?.search_results && onSearchResults) {
+ console.log("Search results found:", delta.provider_specific_fields.search_results);
+ onSearchResults(delta.provider_specific_fields.search_results);
+ }
+
// Check for usage data using type assertion
const chunkWithUsage = chunk as any;
if (chunkWithUsage.usage && onUsageData) {
diff --git a/ui/litellm-dashboard/src/components/chat_ui/types.ts b/ui/litellm-dashboard/src/components/chat_ui/types.ts
index 454256e56cb1..e8a98473cf40 100644
--- a/ui/litellm-dashboard/src/components/chat_ui/types.ts
+++ b/ui/litellm-dashboard/src/components/chat_ui/types.ts
@@ -56,6 +56,20 @@ export interface StreamingResponse {
usage?: Usage;
}
+export interface VectorStoreSearchResult {
+ score: number;
+ content: Array<{ text: string; type: string }>;
+ file_id?: string;
+ filename?: string;
+ attributes?: Record
;
+}
+
+export interface VectorStoreSearchResponse {
+ object: string;
+ search_query: string;
+ data: VectorStoreSearchResult[];
+}
+
export interface MessageType {
role: string;
content: string | MultimodalContent[];
@@ -75,6 +89,7 @@ export interface MessageType {
url: string;
detail: string;
};
+ searchResults?: VectorStoreSearchResponse[];
}
export interface MultimodalContent {