mirror of
https://gitee.com/wanwujie/deer-flow
synced 2026-04-03 06:12:14 +08:00
fix: load all thread pages in thread lists (#1044)
* fix(frontend): load all thread pages in thread lists * Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Willem Jiang <willem.jiang@gmail.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -1,27 +1,84 @@
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
|
||||
export function POST() {
|
||||
type ThreadSearchRequest = {
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
sortBy?: "updated_at" | "created_at";
|
||||
sortOrder?: "asc" | "desc";
|
||||
};
|
||||
|
||||
type MockThreadSearchResult = Record<string, unknown> & {
|
||||
thread_id: string;
|
||||
updated_at: string | undefined;
|
||||
};
|
||||
|
||||
export async function POST(request: Request) {
|
||||
const body = ((await request.json().catch(() => ({}))) ?? {}) as ThreadSearchRequest;
|
||||
|
||||
const rawLimit = body.limit;
|
||||
let limit = 50;
|
||||
if (typeof rawLimit === "number") {
|
||||
const normalizedLimit = Math.max(0, Math.floor(rawLimit));
|
||||
if (!Number.isNaN(normalizedLimit)) {
|
||||
limit = normalizedLimit;
|
||||
}
|
||||
}
|
||||
|
||||
const rawOffset = body.offset;
|
||||
let offset = 0;
|
||||
if (typeof rawOffset === "number") {
|
||||
const normalizedOffset = Math.max(0, Math.floor(rawOffset));
|
||||
if (!Number.isNaN(normalizedOffset)) {
|
||||
offset = normalizedOffset;
|
||||
}
|
||||
}
|
||||
const sortBy = body.sortBy ?? "updated_at";
|
||||
const sortOrder = body.sortOrder ?? "desc";
|
||||
|
||||
const threadsDir = fs.readdirSync(
|
||||
path.resolve(process.cwd(), "public/demo/threads"),
|
||||
{
|
||||
withFileTypes: true,
|
||||
},
|
||||
);
|
||||
|
||||
const threadData = threadsDir
|
||||
.map((threadId) => {
|
||||
.map<MockThreadSearchResult | null>((threadId) => {
|
||||
if (threadId.isDirectory() && !threadId.name.startsWith(".")) {
|
||||
const threadData = fs.readFileSync(
|
||||
path.resolve(`public/demo/threads/${threadId.name}/thread.json`),
|
||||
"utf8",
|
||||
);
|
||||
const threadData = JSON.parse(
|
||||
fs.readFileSync(
|
||||
path.resolve(`public/demo/threads/${threadId.name}/thread.json`),
|
||||
"utf8",
|
||||
),
|
||||
) as Record<string, unknown>;
|
||||
|
||||
return {
|
||||
...threadData,
|
||||
thread_id: threadId.name,
|
||||
values: JSON.parse(threadData).values,
|
||||
updated_at:
|
||||
typeof threadData.updated_at === "string"
|
||||
? threadData.updated_at
|
||||
: typeof threadData.created_at === "string"
|
||||
? threadData.created_at
|
||||
: undefined,
|
||||
};
|
||||
}
|
||||
return false;
|
||||
return null;
|
||||
})
|
||||
.filter(Boolean);
|
||||
return Response.json(threadData);
|
||||
.filter((thread): thread is MockThreadSearchResult => thread !== null)
|
||||
.sort((a, b) => {
|
||||
const aTimestamp = a[sortBy];
|
||||
const bTimestamp = b[sortBy];
|
||||
const aParsed =
|
||||
typeof aTimestamp === "string" ? Date.parse(aTimestamp) : 0;
|
||||
const bParsed =
|
||||
typeof bTimestamp === "string" ? Date.parse(bTimestamp) : 0;
|
||||
const aValue = Number.isNaN(aParsed) ? 0 : aParsed;
|
||||
const bValue = Number.isNaN(bParsed) ? 0 : bParsed;
|
||||
return sortOrder === "asc" ? aValue - bValue : bValue - aValue;
|
||||
});
|
||||
|
||||
const pagedThreads = threadData.slice(offset, offset + limit);
|
||||
return Response.json(pagedThreads);
|
||||
}
|
||||
|
||||
@@ -372,8 +372,55 @@ export function useThreads(
|
||||
return useQuery<AgentThread[]>({
|
||||
queryKey: ["threads", "search", params],
|
||||
queryFn: async () => {
|
||||
const response = await apiClient.threads.search<AgentThreadState>(params);
|
||||
return response as AgentThread[];
|
||||
const maxResults = params.limit;
|
||||
const initialOffset = params.offset ?? 0;
|
||||
const DEFAULT_PAGE_SIZE = 50;
|
||||
|
||||
// Preserve prior semantics: if a non-positive limit is explicitly provided,
|
||||
// delegate to a single search call with the original parameters.
|
||||
if (maxResults !== undefined && maxResults <= 0) {
|
||||
const response = await apiClient.threads.search<AgentThreadState>(params);
|
||||
return response as AgentThread[];
|
||||
}
|
||||
|
||||
const pageSize =
|
||||
typeof maxResults === "number" && maxResults > 0
|
||||
? Math.min(DEFAULT_PAGE_SIZE, maxResults)
|
||||
: DEFAULT_PAGE_SIZE;
|
||||
|
||||
const threads: AgentThread[] = [];
|
||||
let offset = initialOffset;
|
||||
|
||||
while (true) {
|
||||
if (typeof maxResults === "number" && threads.length >= maxResults) {
|
||||
break;
|
||||
}
|
||||
|
||||
const currentLimit =
|
||||
typeof maxResults === "number"
|
||||
? Math.min(pageSize, maxResults - threads.length)
|
||||
: pageSize;
|
||||
|
||||
if (typeof maxResults === "number" && currentLimit <= 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
const response = (await apiClient.threads.search<AgentThreadState>({
|
||||
...params,
|
||||
limit: currentLimit,
|
||||
offset,
|
||||
})) as AgentThread[];
|
||||
|
||||
threads.push(...response);
|
||||
|
||||
if (response.length < currentLimit) {
|
||||
break;
|
||||
}
|
||||
|
||||
offset += response.length;
|
||||
}
|
||||
|
||||
return threads;
|
||||
},
|
||||
refetchOnWindowFocus: false,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user