feat(chat): 优化分析过程与结果展示
Generic Container CI/CD / test-build-publish (push) Successful in 2m25s
Frontend CI/CD v2 / build-test-publish-and-deploy (push) Successful in 2m25s

This commit is contained in:
2026-08-26 18:05:03 +08:00
parent fee4fc6ce1
commit 0dad61ff1f
13 changed files with 1049 additions and 292 deletions
+104
View File
@@ -59,6 +59,35 @@ export type AgentTodoUpdate = {
createdAt: number;
};
export type AgentActivityStatus = "running" | "completed" | "error" | "cancelled";
export type AgentActivityAction = {
id: string;
tool: string;
title: string;
status: "running" | "completed" | "error";
target?: string;
error?: string;
startedAt: number;
endedAt?: number;
elapsedMs?: number;
elapsedSnapshotAt?: number;
durationMs?: number;
};
export type AgentActivity = {
id: string;
title: string;
reason: string;
status: AgentActivityStatus;
actions: AgentActivityAction[];
startedAt: number;
endedAt?: number;
elapsedMs?: number;
elapsedSnapshotAt?: number;
durationMs?: number;
};
export type StreamEvent =
| {
type: "state";
@@ -68,8 +97,16 @@ export type StreamEvent =
runStatus?: string;
}
| { type: "token"; sessionId: string; content: string }
| { type: "final_answer"; sessionId: string; content: string }
| { type: "done"; sessionId: string; totalDurationMs?: number }
| { type: "session_title"; sessionId: string; title: string }
| {
type: "activity_update";
sessionId: string;
activity: AgentActivity;
todos?: AgentTodoItem[];
todosCreatedAt?: number;
}
| {
type: "progress";
sessionId: string;
@@ -127,6 +164,8 @@ export type StreamEvent =
permission: string;
patterns: string[];
target?: string;
activityId?: string;
reason?: string;
always: string[];
tool?: {
messageID: string;
@@ -295,6 +334,47 @@ const normalizeTodos = (value: unknown): AgentTodoItem[] => {
}));
};
const normalizeActivityStatus = (value: unknown): AgentActivityStatus => {
if (value === "completed" || value === "error" || value === "cancelled") {
return value;
}
return "running";
};
const normalizeActivity = (value: unknown): AgentActivity | undefined => {
if (!isObjectRecord(value) || typeof value.id !== "string") return undefined;
const now = Date.now();
const actions: AgentActivityAction[] = Array.isArray(value.actions)
? value.actions.filter(isObjectRecord).map((action, index) => ({
id: typeof action.id === "string" ? action.id : `${value.id}-action-${index}`,
tool: typeof action.tool === "string" ? action.tool : "tool",
title: typeof action.title === "string" ? action.title : "执行操作",
status: action.status === "completed" || action.status === "error"
? action.status
: "running",
target: typeof action.target === "string" ? action.target : undefined,
error: typeof action.error === "string" ? action.error : undefined,
startedAt: typeof action.started_at === "number" ? action.started_at : now,
endedAt: typeof action.ended_at === "number" ? action.ended_at : undefined,
elapsedMs: typeof action.elapsed_ms === "number" ? action.elapsed_ms : undefined,
elapsedSnapshotAt: typeof action.elapsed_ms === "number" ? now : undefined,
durationMs: typeof action.duration_ms === "number" ? action.duration_ms : undefined,
}))
: [];
return {
id: value.id,
title: typeof value.title === "string" ? value.title : "正在处理",
reason: typeof value.reason === "string" ? value.reason : "",
status: normalizeActivityStatus(value.status),
actions,
startedAt: typeof value.started_at === "number" ? value.started_at : now,
endedAt: typeof value.ended_at === "number" ? value.ended_at : undefined,
elapsedMs: typeof value.elapsed_ms === "number" ? value.elapsed_ms : undefined,
elapsedSnapshotAt: typeof value.elapsed_ms === "number" ? now : undefined,
durationMs: typeof value.duration_ms === "number" ? value.duration_ms : undefined,
};
};
const emitParsedStreamEvent = (
event: string,
data: string,
@@ -327,6 +407,7 @@ const emitParsedStreamEvent = (
target?: string;
always?: unknown;
created_at?: number;
todos_created_at?: number;
reply?: PermissionReply;
questions?: unknown;
answers?: unknown;
@@ -335,6 +416,8 @@ const emitParsedStreamEvent = (
todos?: unknown;
reason?: string;
timeout_ms?: number;
activity?: unknown;
activity_id?: string;
};
if (event === "state") {
onEvent({
@@ -350,6 +433,12 @@ const emitParsedStreamEvent = (
sessionId: parsed.session_id ?? "",
content: parsed.content ?? "",
});
} else if (event === "final_answer") {
onEvent({
type: "final_answer",
sessionId: parsed.session_id ?? "",
content: parsed.content ?? "",
});
} else if (event === "progress") {
onEvent({
type: "progress",
@@ -364,6 +453,19 @@ const emitParsedStreamEvent = (
elapsedMs: parsed.elapsed_ms,
durationMs: parsed.duration_ms,
});
} else if (event === "activity_update") {
const activity = normalizeActivity(parsed.activity);
if (activity) {
onEvent({
type: "activity_update",
sessionId: parsed.session_id ?? "",
activity,
todos: Array.isArray(parsed.todos)
? normalizeTodos(parsed.todos)
: undefined,
todosCreatedAt: parsed.todos_created_at,
});
}
} else if (event === "done") {
onEvent({
type: "done",
@@ -429,6 +531,8 @@ const emitParsedStreamEvent = (
? parsed.patterns.filter((item): item is string => typeof item === "string")
: [],
target: typeof parsed.target === "string" ? parsed.target : undefined,
activityId: typeof parsed.activity_id === "string" ? parsed.activity_id : undefined,
reason: typeof parsed.reason === "string" ? parsed.reason : undefined,
always: Array.isArray(parsed.always)
? parsed.always.filter((item): item is string => typeof item === "string")
: [],