mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-08-13 08:18:57 +00:00
* docs: design frontend performance remediation * docs: plan frontend performance remediation * test(frontend): add route asset performance budgets * perf(nginx): compress textual responses safely * perf(frontend): lazy load case study media * perf(frontend): bound static demo file tracing * perf(frontend): restore static locale boundaries * perf(frontend): defer closed workspace panels * perf(frontend): split editors and deduplicate highlighting * perf(frontend): index incremental message derivation * perf(frontend): stabilize paged history cache policy * perf(frontend): bound streaming markdown renders * perf(frontend): virtualize message history * perf(frontend): bound and virtualize chat lists * perf(frontend): suspend inactive decorative animation * perf(browser): stream latest frames as binary * perf(artifacts): stream bounded text previews * docs: finalize performance runtime boundaries * style(backend): apply test formatting * fix(frontend): keep translation functions client-side * perf(frontend): defer decorative animation bundles * test(frontend): lock optimized route budgets * fix: harden frontend performance boundaries * test(frontend): update i18n provider fixture * fix(frontend): preserve sidebar pagination position * style(backend): format artifact range test
156 lines
5.0 KiB
TypeScript
156 lines
5.0 KiB
TypeScript
import type { Message } from "@langchain/langgraph-sdk";
|
|
import { describe, expect, it } from "@rstest/core";
|
|
|
|
import {
|
|
deriveAssistantTurnUsageState,
|
|
deriveStableMessageGroups,
|
|
} from "@/core/messages/derived-state";
|
|
import { getMessageGroups } from "@/core/messages/utils";
|
|
|
|
function message(type: Message["type"], id: string, content: string): Message {
|
|
return { type, id, content } as Message;
|
|
}
|
|
|
|
describe("incremental message derivation", () => {
|
|
it("reuses completed groups when only the streaming turn changes", () => {
|
|
const messages = Array.from({ length: 1_000 }, (_, turn) => [
|
|
message("human", `h-${turn}`, `question ${turn}`),
|
|
message("ai", `a-${turn}`, `answer ${turn}`),
|
|
]).flat();
|
|
const initial = deriveStableMessageGroups(messages, false, [], false);
|
|
const nextMessages = [
|
|
...messages.slice(0, -1),
|
|
message("ai", "a-999", "answer 999 streaming"),
|
|
];
|
|
|
|
const next = deriveStableMessageGroups(nextMessages, true, initial, false);
|
|
|
|
expect(next).toHaveLength(initial.length);
|
|
expect(next[0]).toBe(initial[0]);
|
|
expect(next.at(-3)).toBe(initial.at(-3));
|
|
expect(next.at(-1)).not.toBe(initial.at(-1));
|
|
});
|
|
|
|
it("does not reuse a historical group when a same-id message changes", () => {
|
|
const messages = [
|
|
message("human", "h-1", "question"),
|
|
message("ai", "a-1", "original answer"),
|
|
message("human", "h-2", "next question"),
|
|
];
|
|
const initial = deriveStableMessageGroups(messages, false, [], false);
|
|
const refreshed = deriveStableMessageGroups(
|
|
[messages[0]!, message("ai", "a-1", "corrected answer"), messages[2]!],
|
|
false,
|
|
initial,
|
|
false,
|
|
);
|
|
|
|
expect(refreshed[1]).not.toBe(initial[1]);
|
|
expect(refreshed[1]?.messages[0]?.content).toBe("corrected answer");
|
|
});
|
|
|
|
it("matches the reference grouping when older history is prepended during streaming", () => {
|
|
const currentTurn = [
|
|
message("human", "h-2", "current question"),
|
|
message("ai", "a-2", "streaming answer"),
|
|
];
|
|
const initial = deriveStableMessageGroups(currentTurn, true, [], false);
|
|
const withHistory = [
|
|
message("human", "h-1", "older question"),
|
|
message("ai", "a-1", "older answer"),
|
|
...currentTurn,
|
|
];
|
|
|
|
const derived = deriveStableMessageGroups(withHistory, true, initial, true);
|
|
|
|
expect(derived).toEqual(
|
|
getMessageGroups(withHistory, { isCurrentTurnLoading: true }),
|
|
);
|
|
expect(derived.map((group) => group.id)).toContain("h-1");
|
|
});
|
|
|
|
it("matches the reference grouping across append, tool, reconnect, and hidden-message updates", () => {
|
|
const toolCalling = {
|
|
...message("ai", "a-tool", ""),
|
|
tool_calls: [{ id: "call-1", name: "bash", args: {} }],
|
|
} as Message;
|
|
const toolResult = {
|
|
...message("tool", "tool-1", "done"),
|
|
name: "bash",
|
|
tool_call_id: "call-1",
|
|
} as Message;
|
|
const hidden = {
|
|
...message("ai", "summary-1", "hidden summary"),
|
|
name: "summary",
|
|
} as Message;
|
|
const states: Array<{ messages: Message[]; loading: boolean }> = [
|
|
{ messages: [message("human", "h-1", "question")], loading: true },
|
|
{
|
|
messages: [message("human", "h-1", "question"), toolCalling],
|
|
loading: true,
|
|
},
|
|
{
|
|
messages: [
|
|
message("human", "h-1", "question"),
|
|
toolCalling,
|
|
toolResult,
|
|
],
|
|
loading: true,
|
|
},
|
|
{
|
|
messages: [
|
|
message("human", "h-1", "question"),
|
|
{ ...toolCalling },
|
|
{ ...toolResult },
|
|
hidden,
|
|
message("ai", "a-final", "answer"),
|
|
],
|
|
loading: false,
|
|
},
|
|
];
|
|
|
|
let previousGroups: ReturnType<typeof getMessageGroups> = [];
|
|
let previousIsLoading = false;
|
|
for (const state of states) {
|
|
const derived = deriveStableMessageGroups(
|
|
state.messages,
|
|
state.loading,
|
|
previousGroups,
|
|
previousIsLoading,
|
|
);
|
|
expect(derived).toEqual(
|
|
getMessageGroups(state.messages, {
|
|
isCurrentTurnLoading: state.loading,
|
|
}),
|
|
);
|
|
previousGroups = derived;
|
|
previousIsLoading = state.loading;
|
|
}
|
|
});
|
|
|
|
it("reuses completed turn usage arrays on a tail-only update", () => {
|
|
const messages = [
|
|
message("human", "h-1", "one"),
|
|
message("ai", "a-1", "answer one"),
|
|
message("human", "h-2", "two"),
|
|
message("ai", "a-2", "answer two"),
|
|
];
|
|
const groups = deriveStableMessageGroups(messages, false, [], false);
|
|
const initial = deriveAssistantTurnUsageState(groups);
|
|
const nextMessages = [
|
|
...messages.slice(0, -1),
|
|
message("ai", "a-2", "answer two streaming"),
|
|
];
|
|
const nextGroups = deriveStableMessageGroups(
|
|
nextMessages,
|
|
true,
|
|
groups,
|
|
false,
|
|
);
|
|
const next = deriveAssistantTurnUsageState(nextGroups, initial);
|
|
|
|
expect(next.byGroupIndex[1]).toBe(initial.byGroupIndex[1]);
|
|
expect(next.byGroupIndex.at(-1)).not.toBe(initial.byGroupIndex.at(-1));
|
|
});
|
|
});
|