mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-09-20 19:46:16 +00:00
* feat(knowledge): integrate RAGFlow retrieval and management * test(knowledge): cover merged listing tool * feat(knowledge): add per-message retrieval scope * chore(docs): remove unrelated document * docs(knowledge): add interaction screenshots * feat(knowledge): simplify scope selector trigger * docs(knowledge): refresh selector screenshot * feat(knowledge): defer standalone management * docs(knowledge): show chat-only scope UI * fix(knowledge): honor scope on clarification replies * fix(knowledge): harden scoped replay validation * docs(knowledge): clarify replay scope precedence * fix(knowledge): keep provider settings on tools * fix(config): preserve tools-only knowledge settings * fix(knowledge): submit custom assistant identity * refactor(knowledge): trim PR scope changes * fix(knowledge): sanitize document scope display * feat(knowledge): enable scope selection in main chat * fix(knowledge): emphasize active scope icon without button frame * fix(knowledge): close context scrubbing and refresh e2e checks * fix(knowledge): preserve idempotent canonical retries * fix(knowledge): accept promptless conversation runs * style(knowledge): format backend regression tests * chore(knowledge): trim PR scope and fix frontend format * fix(knowledge): remove shared-scope notice * fix(knowledge): remove scope persistence notice * docs(knowledge): include main chat in catalog scope * fix(knowledge): preserve scope recovery and upgrades * fix(config): preserve LightRAG knowledge upgrades --------- Co-authored-by: foreleven <for-eleven@hotmail.com>
217 lines
7.2 KiB
TypeScript
217 lines
7.2 KiB
TypeScript
import { expect, test } from "@playwright/test";
|
|
|
|
import { handleRunStream, mockLangGraphAPI } from "./utils/mock-api";
|
|
|
|
test.describe("custom-agent knowledge scope", () => {
|
|
test("selects one file and sends one immutable scope snapshot", async ({
|
|
page,
|
|
}) => {
|
|
mockLangGraphAPI(page, {
|
|
agents: [
|
|
{
|
|
name: "researcher",
|
|
description: "Research agent",
|
|
tool_groups: ["knowledge"],
|
|
},
|
|
],
|
|
features: { knowledgeScopeSelectionEnabled: true },
|
|
});
|
|
await page.route("**/api/knowledge/retrieval-catalog/datasets?*", (route) =>
|
|
route.fulfill({
|
|
status: 200,
|
|
contentType: "application/json",
|
|
body: JSON.stringify({
|
|
items: [{ id: "dataset-1", name: "Policies", selectable: true }],
|
|
page: 1,
|
|
page_size: 100,
|
|
total: 1,
|
|
}),
|
|
}),
|
|
);
|
|
await page.route(
|
|
"**/api/knowledge/retrieval-catalog/datasets/dataset-1/documents?*",
|
|
(route) =>
|
|
route.fulfill({
|
|
status: 200,
|
|
contentType: "application/json",
|
|
body: JSON.stringify({
|
|
items: [
|
|
{ id: "doc-1", name: "Leave.pdf", selectable: true },
|
|
{ id: "doc-2", name: "Parsing.pdf", selectable: false },
|
|
],
|
|
page: 1,
|
|
page_size: 100,
|
|
total: 2,
|
|
}),
|
|
}),
|
|
);
|
|
let streamBody: Record<string, unknown> | undefined;
|
|
await page.route("**/api/langgraph/threads/*/runs/stream", (route) => {
|
|
streamBody = route.request().postDataJSON() as Record<string, unknown>;
|
|
return handleRunStream(route);
|
|
});
|
|
|
|
await page.goto("/workspace/agents/researcher/chats/new");
|
|
await expect(page.getByRole("link", { name: "Knowledge" })).toHaveCount(0);
|
|
const trigger = page.getByTestId("knowledge-scope-trigger");
|
|
await expect(trigger).toHaveText("");
|
|
await expect(trigger).toHaveAttribute("aria-pressed", "true");
|
|
await expect(trigger).toHaveClass(/text-foreground/);
|
|
await expect(trigger).not.toHaveClass(/bg-primary\/10/);
|
|
|
|
await trigger.click();
|
|
await page.getByLabel("Off").check();
|
|
await page.getByRole("button", { name: "Apply" }).click();
|
|
await expect(trigger).toHaveAttribute("aria-pressed", "false");
|
|
await expect(trigger).toHaveAttribute("aria-label", "Knowledge · Off");
|
|
await expect(trigger).not.toHaveClass(/bg-primary\/10/);
|
|
|
|
await trigger.click();
|
|
await page.getByLabel("Selected knowledge bases").check();
|
|
await page.getByLabel("Policies").check();
|
|
await page.getByRole("button", { name: "Files" }).click();
|
|
await page.getByLabel("Selected files").check();
|
|
await page.getByLabel("Leave.pdf").check();
|
|
await expect(page.getByLabel("Parsing.pdf")).toBeDisabled();
|
|
await page.getByRole("button", { name: "Apply" }).click();
|
|
await expect(trigger).toHaveAttribute("aria-pressed", "true");
|
|
await expect(trigger).toHaveClass(/text-foreground/);
|
|
await expect(trigger).not.toHaveClass(/bg-primary\/10/);
|
|
|
|
await page
|
|
.getByPlaceholder(/how can i assist you/i)
|
|
.fill("Find the policy");
|
|
await page.getByRole("button", { name: "Submit" }).click();
|
|
await expect.poll(() => streamBody).toBeDefined();
|
|
|
|
expect(streamBody).toMatchObject({
|
|
assistant_id: "researcher",
|
|
input: {
|
|
messages: [
|
|
{
|
|
type: "human",
|
|
additional_kwargs: {
|
|
knowledge_scope: {
|
|
version: 1,
|
|
mode: "selected",
|
|
dataset_ids: ["dataset-1"],
|
|
document_filters: [
|
|
{ dataset_id: "dataset-1", document_ids: ["doc-1"] },
|
|
],
|
|
display: {
|
|
datasets: [
|
|
{
|
|
id: "dataset-1",
|
|
name: "Policies",
|
|
documents: [{ id: "doc-1", name: "Leave.pdf" }],
|
|
},
|
|
],
|
|
},
|
|
},
|
|
},
|
|
},
|
|
],
|
|
},
|
|
});
|
|
});
|
|
|
|
test("main chat uses the selector and sends the lead-agent scope", async ({
|
|
page,
|
|
}) => {
|
|
mockLangGraphAPI(page, {
|
|
features: { knowledgeScopeSelectionEnabled: true },
|
|
});
|
|
await page.route("**/api/knowledge/retrieval-catalog/datasets?*", (route) =>
|
|
route.fulfill({
|
|
status: 200,
|
|
contentType: "application/json",
|
|
body: JSON.stringify({
|
|
items: [{ id: "dataset-1", name: "Policies", selectable: true }],
|
|
page: 1,
|
|
page_size: 100,
|
|
total: 1,
|
|
}),
|
|
}),
|
|
);
|
|
await page.route(
|
|
"**/api/knowledge/retrieval-catalog/datasets/dataset-1/documents?*",
|
|
(route) =>
|
|
route.fulfill({
|
|
status: 200,
|
|
contentType: "application/json",
|
|
body: JSON.stringify({
|
|
items: [{ id: "doc-1", name: "Leave.pdf", selectable: true }],
|
|
page: 1,
|
|
page_size: 100,
|
|
total: 1,
|
|
}),
|
|
}),
|
|
);
|
|
let streamBody: Record<string, unknown> | undefined;
|
|
await page.route("**/api/langgraph/threads/*/runs/stream", (route) => {
|
|
streamBody = route.request().postDataJSON() as Record<string, unknown>;
|
|
return handleRunStream(route);
|
|
});
|
|
|
|
await page.goto("/workspace/chats/new");
|
|
|
|
await expect(page.getByPlaceholder(/how can i assist you/i)).toBeVisible();
|
|
const trigger = page.getByTestId("knowledge-scope-trigger");
|
|
await expect(trigger).toHaveText("");
|
|
await expect(trigger).toHaveAttribute("aria-pressed", "true");
|
|
await trigger.click();
|
|
await page.getByLabel("Selected knowledge bases").check();
|
|
await page.getByLabel("Policies").check();
|
|
await page.getByRole("button", { name: "Files" }).click();
|
|
await page.getByLabel("Selected files").check();
|
|
await page.getByLabel("Leave.pdf").check();
|
|
await page.getByRole("button", { name: "Apply" }).click();
|
|
|
|
await page
|
|
.getByPlaceholder(/how can i assist you/i)
|
|
.fill("Find the policy");
|
|
await page.getByRole("button", { name: "Submit" }).click();
|
|
await expect.poll(() => streamBody).toBeDefined();
|
|
|
|
expect(streamBody).toMatchObject({
|
|
assistant_id: "lead_agent",
|
|
input: {
|
|
messages: [
|
|
{
|
|
type: "human",
|
|
additional_kwargs: {
|
|
knowledge_scope: {
|
|
version: 1,
|
|
mode: "selected",
|
|
dataset_ids: ["dataset-1"],
|
|
document_filters: [
|
|
{ dataset_id: "dataset-1", document_ids: ["doc-1"] },
|
|
],
|
|
},
|
|
},
|
|
},
|
|
],
|
|
},
|
|
});
|
|
});
|
|
|
|
test("main chat hides the selector when configuration disables it", async ({
|
|
page,
|
|
}) => {
|
|
let catalogRequests = 0;
|
|
mockLangGraphAPI(page, {
|
|
features: { knowledgeScopeSelectionEnabled: false },
|
|
});
|
|
await page.route("**/api/knowledge/retrieval-catalog/**", (route) => {
|
|
catalogRequests += 1;
|
|
return route.abort();
|
|
});
|
|
|
|
await page.goto("/workspace/chats/new");
|
|
|
|
await expect(page.getByPlaceholder(/how can i assist you/i)).toBeVisible();
|
|
await expect(page.getByTestId("knowledge-scope-trigger")).toHaveCount(0);
|
|
expect(catalogRequests).toBe(0);
|
|
});
|
|
});
|