|
|
@@ -1,5 +1,6 @@
|
|
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
|
import { useWebSocket } from "../../../hooks/useWebSocket";
|
|
|
+import { request } from "../../../api/client";
|
|
|
import type { Goal } from "../../../types/goal";
|
|
|
import type { Message } from "../../../types/message";
|
|
|
|
|
|
@@ -108,90 +109,83 @@ export const useFlowChartData = (traceId: string | null, refreshTrigger?: number
|
|
|
setReloading(true);
|
|
|
let nextSinceEventId: number | null = null;
|
|
|
try {
|
|
|
- const [traceRes, messagesRes] = await Promise.all([
|
|
|
- fetch(`http://localhost:8000/api/traces/${traceId}`),
|
|
|
- fetch(`http://localhost:8000/api/traces/${traceId}/messages?mode=all`),
|
|
|
+ const [traceJson, messagesJson] = await Promise.all([
|
|
|
+ request<unknown>(`/api/traces/${traceId}`),
|
|
|
+ request<unknown>(`/api/traces/${traceId}/messages?mode=all`),
|
|
|
]);
|
|
|
|
|
|
- if (traceRes.ok) {
|
|
|
- const json = (await traceRes.json()) as unknown;
|
|
|
- const root = isRecord(json) ? json : {};
|
|
|
- const trace = isRecord(root.trace) ? root.trace : undefined;
|
|
|
- const goalTree = isRecord(root.goal_tree) ? root.goal_tree : undefined;
|
|
|
- const goalList = goalTree && Array.isArray(goalTree.goals) ? (goalTree.goals as Goal[]) : [];
|
|
|
-
|
|
|
- const lastEventId = trace && typeof trace.last_event_id === "number" ? trace.last_event_id : undefined;
|
|
|
- if (typeof lastEventId === "number") {
|
|
|
- currentEventIdRef.current = Math.max(currentEventIdRef.current, lastEventId);
|
|
|
- setSinceEventId(lastEventId);
|
|
|
- nextSinceEventId = lastEventId;
|
|
|
- }
|
|
|
+ const traceRoot = isRecord(traceJson) ? traceJson : {};
|
|
|
+ const trace = isRecord(traceRoot.trace) ? traceRoot.trace : undefined;
|
|
|
+ const goalTree = isRecord(traceRoot.goal_tree) ? traceRoot.goal_tree : undefined;
|
|
|
+ const goalList = goalTree && Array.isArray(goalTree.goals) ? (goalTree.goals as Goal[]) : [];
|
|
|
|
|
|
- if (goalList.length > 0) {
|
|
|
- setGoals((prev) => {
|
|
|
- const mergedFlat = goalList.map((ng) => {
|
|
|
- const existing = prev.find((p) => p.id === ng.id);
|
|
|
- if (!existing) return ng;
|
|
|
- const merged: Goal = { ...existing, ...ng };
|
|
|
- if (existing.sub_trace_ids && !merged.sub_trace_ids) {
|
|
|
- merged.sub_trace_ids = existing.sub_trace_ids;
|
|
|
- }
|
|
|
- if (existing.agent_call_mode && !merged.agent_call_mode) {
|
|
|
- merged.agent_call_mode = existing.agent_call_mode;
|
|
|
- }
|
|
|
- if (existing.knowledge && !merged.knowledge) {
|
|
|
- merged.knowledge = existing.knowledge;
|
|
|
- }
|
|
|
- return merged;
|
|
|
- });
|
|
|
- return buildSubGoals(mergedFlat);
|
|
|
- });
|
|
|
- }
|
|
|
+ const lastEventId = trace && typeof trace.last_event_id === "number" ? trace.last_event_id : undefined;
|
|
|
+ if (typeof lastEventId === "number") {
|
|
|
+ currentEventIdRef.current = Math.max(currentEventIdRef.current, lastEventId);
|
|
|
+ setSinceEventId(lastEventId);
|
|
|
+ nextSinceEventId = lastEventId;
|
|
|
}
|
|
|
|
|
|
- if (messagesRes.ok) {
|
|
|
- const json = (await messagesRes.json()) as unknown;
|
|
|
- const root = isRecord(json) ? json : {};
|
|
|
- const list = Array.isArray(root.messages) ? (root.messages as Message[]) : [];
|
|
|
- console.log("%c [ list ]-149", "font-size:13px; background:pink; color:#bf2c9f;", list);
|
|
|
-
|
|
|
- const filtered = list.filter((message) => (message as { status?: string }).status !== "abandoned");
|
|
|
- const nextMessages = [...filtered].sort(messageComparator);
|
|
|
-
|
|
|
- const { availableData: finalMessages, invalidBranches: invalidBranchesTemp } = processRetryLogic(nextMessages);
|
|
|
-
|
|
|
- // Update max sequence
|
|
|
- const maxSeq = finalMessages.reduce((max, msg) => {
|
|
|
- const seq = typeof msg.sequence === "number" ? msg.sequence : -1;
|
|
|
- return Math.max(max, seq);
|
|
|
- }, 0);
|
|
|
- maxSequenceRef.current = maxSeq;
|
|
|
-
|
|
|
- setMessages(finalMessages);
|
|
|
- setInvalidBranches(invalidBranchesTemp);
|
|
|
- const grouped: Record<string, Message[]> = {};
|
|
|
- finalMessages.forEach((message) => {
|
|
|
- const groupKey = typeof message.goal_id === "string" && message.goal_id ? message.goal_id : "START";
|
|
|
- if (!grouped[groupKey]) grouped[groupKey] = [];
|
|
|
- grouped[groupKey].push(message);
|
|
|
- });
|
|
|
- Object.keys(grouped).forEach((key) => {
|
|
|
- grouped[key].sort(messageComparator);
|
|
|
+ if (goalList.length > 0) {
|
|
|
+ setGoals((prev) => {
|
|
|
+ const mergedFlat = goalList.map((ng) => {
|
|
|
+ const existing = prev.find((p) => p.id === ng.id);
|
|
|
+ if (!existing) return ng;
|
|
|
+ const merged: Goal = { ...existing, ...ng };
|
|
|
+ if (existing.sub_trace_ids && !merged.sub_trace_ids) {
|
|
|
+ merged.sub_trace_ids = existing.sub_trace_ids;
|
|
|
+ }
|
|
|
+ if (existing.agent_call_mode && !merged.agent_call_mode) {
|
|
|
+ merged.agent_call_mode = existing.agent_call_mode;
|
|
|
+ }
|
|
|
+ if (existing.knowledge && !merged.knowledge) {
|
|
|
+ merged.knowledge = existing.knowledge;
|
|
|
+ }
|
|
|
+ return merged;
|
|
|
+ });
|
|
|
+ return buildSubGoals(mergedFlat);
|
|
|
});
|
|
|
- setMsgGroups(grouped);
|
|
|
+ }
|
|
|
|
|
|
- if (grouped.START && grouped.START.length > 0) {
|
|
|
- setGoals((prev) => {
|
|
|
- if (prev.some((g) => g.id === "START")) return prev;
|
|
|
- const startGoal: Goal = {
|
|
|
- id: "START",
|
|
|
- description: "START",
|
|
|
- status: "completed",
|
|
|
- created_at: "",
|
|
|
- };
|
|
|
- return [startGoal, ...prev];
|
|
|
- });
|
|
|
- }
|
|
|
+ const messagesRoot = isRecord(messagesJson) ? messagesJson : {};
|
|
|
+ const list = Array.isArray(messagesRoot.messages) ? (messagesRoot.messages as Message[]) : [];
|
|
|
+ console.log("%c [ list ]-149", "font-size:13px; background:pink; color:#bf2c9f;", list);
|
|
|
+
|
|
|
+ const filtered = list.filter((message) => (message as { status?: string }).status !== "abandoned");
|
|
|
+ const nextMessages = [...filtered].sort(messageComparator);
|
|
|
+
|
|
|
+ const { availableData: finalMessages, invalidBranches: invalidBranchesTemp } = processRetryLogic(nextMessages);
|
|
|
+
|
|
|
+ const maxSeq = finalMessages.reduce((max, msg) => {
|
|
|
+ const seq = typeof msg.sequence === "number" ? msg.sequence : -1;
|
|
|
+ return Math.max(max, seq);
|
|
|
+ }, 0);
|
|
|
+ maxSequenceRef.current = maxSeq;
|
|
|
+
|
|
|
+ setMessages(finalMessages);
|
|
|
+ setInvalidBranches(invalidBranchesTemp);
|
|
|
+ const grouped: Record<string, Message[]> = {};
|
|
|
+ finalMessages.forEach((message) => {
|
|
|
+ const groupKey = typeof message.goal_id === "string" && message.goal_id ? message.goal_id : "START";
|
|
|
+ if (!grouped[groupKey]) grouped[groupKey] = [];
|
|
|
+ grouped[groupKey].push(message);
|
|
|
+ });
|
|
|
+ Object.keys(grouped).forEach((key) => {
|
|
|
+ grouped[key].sort(messageComparator);
|
|
|
+ });
|
|
|
+ setMsgGroups(grouped);
|
|
|
+
|
|
|
+ if (grouped.START && grouped.START.length > 0) {
|
|
|
+ setGoals((prev) => {
|
|
|
+ if (prev.some((g) => g.id === "START")) return prev;
|
|
|
+ const startGoal: Goal = {
|
|
|
+ id: "START",
|
|
|
+ description: "START",
|
|
|
+ status: "completed",
|
|
|
+ created_at: "",
|
|
|
+ };
|
|
|
+ return [startGoal, ...prev];
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
// REST 请求完成后,允许建立 WebSocket 连接
|
|
|
@@ -199,6 +193,7 @@ export const useFlowChartData = (traceId: string | null, refreshTrigger?: number
|
|
|
} finally {
|
|
|
restReloadingRef.current = false;
|
|
|
setReloading(false);
|
|
|
+ setReadyToConnect(true);
|
|
|
}
|
|
|
return nextSinceEventId;
|
|
|
}, [messageComparator, traceId]);
|
|
|
@@ -263,7 +258,24 @@ export const useFlowChartData = (traceId: string | null, refreshTrigger?: number
|
|
|
(typeof raw.current_event_id === "number" ? raw.current_event_id : undefined);
|
|
|
if (typeof currentEventId === "number") {
|
|
|
currentEventIdRef.current = Math.max(currentEventIdRef.current, currentEventId);
|
|
|
+ setSinceEventId(currentEventId);
|
|
|
}
|
|
|
+
|
|
|
+ const goalTree = isRecord(data.goal_tree)
|
|
|
+ ? data.goal_tree
|
|
|
+ : isRecord(raw.goal_tree)
|
|
|
+ ? raw.goal_tree
|
|
|
+ : undefined;
|
|
|
+ if (goalTree && Array.isArray(goalTree.goals)) {
|
|
|
+ setGoals((prev) => {
|
|
|
+ if (prev.length > 0) return prev;
|
|
|
+ return buildSubGoals(goalTree.goals as Goal[]);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (event === "pong") {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
@@ -332,7 +344,12 @@ export const useFlowChartData = (traceId: string | null, refreshTrigger?: number
|
|
|
(typeof data.goal_id === "string" ? data.goal_id : undefined) ||
|
|
|
(isRecord(data.goal) && typeof data.goal.id === "string" ? data.goal.id : undefined) ||
|
|
|
(typeof raw.goal_id === "string" ? raw.goal_id : undefined);
|
|
|
- const updates = isRecord(data.updates) ? data.updates : isRecord(raw.updates) ? raw.updates : {};
|
|
|
+ const updates =
|
|
|
+ (isRecord(data.updates) ? data.updates : undefined) ||
|
|
|
+ (isRecord(raw.updates) ? raw.updates : undefined) ||
|
|
|
+ (isRecord(data.patch) ? data.patch : undefined) ||
|
|
|
+ (isRecord(raw.patch) ? raw.patch : undefined) ||
|
|
|
+ {};
|
|
|
if (!goalId) return;
|
|
|
setGoals((prev: Goal[]) =>
|
|
|
prev.map((g: Goal) => {
|