mirror of
https://github.com/modelstudioai/cli.git
synced 2026-09-14 19:49:23 +08:00
test(knowledge): 补全知识库相关命令参数并增加E2E测试覆盖
- 添加知识库列表、创建、删除及文件删除等命令路由 - 新增知识块、分类、文件相关参数的端到端测试,覆盖文件列表、分类列表、块新增更新及分页等功能 - 增加对知识文档状态上传、等待、轮询参数的实时测试及自清理逻辑 - 新增知识文档列表分页、过滤参数的E2E测试覆盖 - 扩展知识文档上传命令的轮询间隔参数测试,验证无错误 - 补充知识库删除命令的轮询间隔参数传递测试 - 增强知识库列表的分页、名称过滤测试用例 - 丰富知识服务命令的参数全覆盖测试,包括创建、更新、部署、删除及多版本描述等功能 - 添加知识检索命令的重新排序指令与过时参数的实时测试覆盖
This commit is contained in:
@@ -1498,6 +1498,358 @@ describe.skipIf(!isKbAdminE2EReady())(
|
||||
},
|
||||
);
|
||||
|
||||
// Live parameter coverage: file-list 4 params + category-list 2 params +
|
||||
// chunk add/update --content-file + chunk list --doc-id. All in one self-cleaning
|
||||
// chain to minimize API calls.
|
||||
describe.skipIf(!isKbAdminE2EReady())("e2e: chunk/category/file 参数补全 (live, 自清理)", () => {
|
||||
const workspaceId = process.env.BAILIAN_WORKSPACE_ID!;
|
||||
|
||||
test("file list(name/file-id/max-result/next-token) + category list(parent-id/collection-id) + chunk add/update --content-file + chunk list --doc-id", async () => {
|
||||
// ── setup: create category → upload file ──
|
||||
const categoryName = `e2e-param-${Date.now() % 100000000}`;
|
||||
const categoryAddRun = await runCommandE2e(KNOWLEDGE_CHUNK_CATEGORY_FILE_ROUTES, [
|
||||
"knowledge",
|
||||
"category",
|
||||
"add",
|
||||
"--name",
|
||||
categoryName,
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
"--quiet",
|
||||
]);
|
||||
expect(categoryAddRun.exitCode, categoryAddRun.stderr).toBe(0);
|
||||
const categoryId = categoryAddRun.stdout.trim();
|
||||
expect(categoryId).toMatch(/^cate_/);
|
||||
|
||||
const fixtureDir = mkdtempSync(join(tmpdir(), "param-e2e-"));
|
||||
const filePath = join(fixtureDir, `param-${Date.now()}.md`);
|
||||
writeFileSync(filePath, "# e2e param file\n");
|
||||
const uploadRun = await runCommandE2e(KNOWLEDGE_CHUNK_CATEGORY_FILE_ROUTES, [
|
||||
"knowledge",
|
||||
"doc",
|
||||
"upload",
|
||||
"--file",
|
||||
filePath,
|
||||
"--category-id",
|
||||
categoryId,
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
"--quiet",
|
||||
]);
|
||||
expect(uploadRun.exitCode, uploadRun.stderr).toBe(0);
|
||||
const fileId = uploadRun.stdout.trim();
|
||||
let indexId: string | undefined;
|
||||
|
||||
try {
|
||||
// ── P2: file list --name (模糊匹配) ──
|
||||
const fileListByNameRun = await runCommandE2e(KNOWLEDGE_CHUNK_CATEGORY_FILE_ROUTES, [
|
||||
"knowledge",
|
||||
"file",
|
||||
"list",
|
||||
"--category-id",
|
||||
categoryId,
|
||||
"--name",
|
||||
"param-",
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
"--quiet",
|
||||
]);
|
||||
expect(fileListByNameRun.exitCode, fileListByNameRun.stderr).toBe(0);
|
||||
expect(fileListByNameRun.stdout.trim().split("\n")).toContain(fileId);
|
||||
|
||||
// ── P2: file list --file-id ──
|
||||
const fileListByFileIdRun = await runCommandE2e(KNOWLEDGE_CHUNK_CATEGORY_FILE_ROUTES, [
|
||||
"knowledge",
|
||||
"file",
|
||||
"list",
|
||||
"--category-id",
|
||||
categoryId,
|
||||
"--file-id",
|
||||
fileId,
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
"--quiet",
|
||||
]);
|
||||
expect(fileListByFileIdRun.exitCode, fileListByFileIdRun.stderr).toBe(0);
|
||||
expect(fileListByFileIdRun.stdout.trim().split("\n")).toContain(fileId);
|
||||
|
||||
// ── P2: file list --max-result 1 ──
|
||||
const fileListMaxResultRun = await runCommandE2e(KNOWLEDGE_CHUNK_CATEGORY_FILE_ROUTES, [
|
||||
"knowledge",
|
||||
"file",
|
||||
"list",
|
||||
"--category-id",
|
||||
categoryId,
|
||||
"--max-result",
|
||||
"1",
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
"--quiet",
|
||||
]);
|
||||
expect(fileListMaxResultRun.exitCode, fileListMaxResultRun.stderr).toBe(0);
|
||||
const maxResultLines = fileListMaxResultRun.stdout.trim().split("\n").filter(Boolean);
|
||||
expect(maxResultLines.length).toBeLessThanOrEqual(1);
|
||||
|
||||
// ── P2: file list --next-token (if paginated) ──
|
||||
const fileListJsonRun = await runCommandE2e(KNOWLEDGE_CHUNK_CATEGORY_FILE_ROUTES, [
|
||||
"knowledge",
|
||||
"file",
|
||||
"list",
|
||||
"--category-id",
|
||||
categoryId,
|
||||
"--max-result",
|
||||
"1",
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
"--output",
|
||||
"json",
|
||||
]);
|
||||
expect(fileListJsonRun.exitCode, fileListJsonRun.stderr).toBe(0);
|
||||
const fileListData = parseStdoutJson<{
|
||||
data?: { nextToken?: string };
|
||||
}>(fileListJsonRun.stdout);
|
||||
const fileNextToken = fileListData.data?.nextToken;
|
||||
if (fileNextToken) {
|
||||
const fileListNextTokenRun = await runCommandE2e(KNOWLEDGE_CHUNK_CATEGORY_FILE_ROUTES, [
|
||||
"knowledge",
|
||||
"file",
|
||||
"list",
|
||||
"--category-id",
|
||||
categoryId,
|
||||
"--next-token",
|
||||
fileNextToken,
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
"--quiet",
|
||||
]);
|
||||
expect(fileListNextTokenRun.exitCode, fileListNextTokenRun.stderr).toBe(0);
|
||||
}
|
||||
|
||||
// ── P3: category list --parent-id (using existing categoryId) ──
|
||||
const listByParentRun = await runCommandE2e(KNOWLEDGE_CHUNK_CATEGORY_FILE_ROUTES, [
|
||||
"knowledge",
|
||||
"category",
|
||||
"list",
|
||||
"--parent-id",
|
||||
categoryId,
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
"--quiet",
|
||||
]);
|
||||
expect(listByParentRun.exitCode, listByParentRun.stderr).toBe(0);
|
||||
|
||||
// ── P3: category list --collection-id (no-error verification) ──
|
||||
const listByCollectionRun = await runCommandE2e(KNOWLEDGE_CHUNK_CATEGORY_FILE_ROUTES, [
|
||||
"knowledge",
|
||||
"category",
|
||||
"list",
|
||||
"--collection-id",
|
||||
"col_nonexistent_e2e",
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
"--quiet",
|
||||
]);
|
||||
expect(listByCollectionRun.exitCode, listByCollectionRun.stderr).toBe(0);
|
||||
|
||||
// ── create kb for chunk tests ──
|
||||
const kbCreateRun = await runCommandE2e(KNOWLEDGE_KB_DELETE_ROUTES, [
|
||||
"knowledge",
|
||||
"create",
|
||||
"--name",
|
||||
`e2e-pk-${Date.now() % 100000000}`.slice(0, 20),
|
||||
"--doc-id",
|
||||
fileId,
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
"--wait",
|
||||
"--quiet",
|
||||
]);
|
||||
expect(kbCreateRun.exitCode, kbCreateRun.stderr).toBe(0);
|
||||
indexId = kbCreateRun.stdout.trim().split("\n")[0]!;
|
||||
expect(indexId).toBeTruthy();
|
||||
|
||||
try {
|
||||
// ── P4: chunk add --content-file ──
|
||||
const chunkContentFile = join(fixtureDir, `chunk-${Date.now()}.txt`);
|
||||
const chunkMarker = `e2e chunk content file marker ${Date.now()}`;
|
||||
writeFileSync(chunkContentFile, chunkMarker);
|
||||
|
||||
const chunkAddFileRun = await runCommandE2e(KNOWLEDGE_CHUNK_CATEGORY_FILE_ROUTES, [
|
||||
"knowledge",
|
||||
"chunk",
|
||||
"add",
|
||||
"--index-id",
|
||||
indexId,
|
||||
"--doc-id",
|
||||
fileId,
|
||||
"--content-file",
|
||||
chunkContentFile,
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
]);
|
||||
expect(chunkAddFileRun.exitCode, chunkAddFileRun.stderr).toBe(0);
|
||||
|
||||
// chunk list read-back: verify content came from file
|
||||
const chunkListAfterAddRun = await runCommandE2e(KNOWLEDGE_CHUNK_CATEGORY_FILE_ROUTES, [
|
||||
"knowledge",
|
||||
"chunk",
|
||||
"list",
|
||||
"--index-id",
|
||||
indexId,
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
"--output",
|
||||
"json",
|
||||
]);
|
||||
expect(chunkListAfterAddRun.exitCode, chunkListAfterAddRun.stderr).toBe(0);
|
||||
const chunkListAfterAddData = parseStdoutJson<{
|
||||
data?: {
|
||||
nodes?: Array<{
|
||||
metadata?: { _id?: string; content?: string };
|
||||
text?: string;
|
||||
}>;
|
||||
};
|
||||
}>(chunkListAfterAddRun.stdout);
|
||||
const addedChunk = chunkListAfterAddData.data?.nodes?.find(
|
||||
(node) => (node.metadata?.content ?? node.text) === chunkMarker,
|
||||
);
|
||||
expect(addedChunk?.metadata?.content ?? addedChunk?.text).toBe(chunkMarker);
|
||||
const addedChunkId = addedChunk?.metadata?._id;
|
||||
expect(addedChunkId).toBeTruthy();
|
||||
|
||||
// ── P6: chunk list --doc-id ──
|
||||
const chunkListByDocRun = await runCommandE2e(KNOWLEDGE_CHUNK_CATEGORY_FILE_ROUTES, [
|
||||
"knowledge",
|
||||
"chunk",
|
||||
"list",
|
||||
"--index-id",
|
||||
indexId,
|
||||
"--doc-id",
|
||||
fileId,
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
"--output",
|
||||
"json",
|
||||
]);
|
||||
expect(chunkListByDocRun.exitCode, chunkListByDocRun.stderr).toBe(0);
|
||||
const chunkListByDocData = parseStdoutJson<{
|
||||
data?: {
|
||||
nodes?: Array<{
|
||||
metadata?: { doc_id?: string };
|
||||
}>;
|
||||
};
|
||||
}>(chunkListByDocRun.stdout);
|
||||
// All returned chunks should belong to the specified doc
|
||||
for (const node of chunkListByDocData.data?.nodes ?? []) {
|
||||
expect(node.metadata?.doc_id).toContain(fileId);
|
||||
}
|
||||
|
||||
// ── P4: chunk update --content-file ──
|
||||
if (addedChunkId) {
|
||||
const updateContentFile = join(fixtureDir, `chunk-update-${Date.now()}.txt`);
|
||||
const updateMarker = `e2e chunk update content file marker ${Date.now()}`;
|
||||
writeFileSync(updateContentFile, updateMarker);
|
||||
|
||||
const chunkUpdateFileRun = await runCommandE2e(KNOWLEDGE_CHUNK_CATEGORY_FILE_ROUTES, [
|
||||
"knowledge",
|
||||
"chunk",
|
||||
"update",
|
||||
"--index-id",
|
||||
indexId,
|
||||
"--chunk-id",
|
||||
addedChunkId,
|
||||
"--doc-id",
|
||||
fileId,
|
||||
"--content-file",
|
||||
updateContentFile,
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
]);
|
||||
expect(chunkUpdateFileRun.exitCode, chunkUpdateFileRun.stderr).toBe(0);
|
||||
|
||||
// chunk list read-back: verify content changed
|
||||
const chunkListAfterUpdateRun = await runCommandE2e(
|
||||
KNOWLEDGE_CHUNK_CATEGORY_FILE_ROUTES,
|
||||
[
|
||||
"knowledge",
|
||||
"chunk",
|
||||
"list",
|
||||
"--index-id",
|
||||
indexId,
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
"--output",
|
||||
"json",
|
||||
],
|
||||
);
|
||||
expect(chunkListAfterUpdateRun.exitCode, chunkListAfterUpdateRun.stderr).toBe(0);
|
||||
const chunkListAfterUpdateData = parseStdoutJson<{
|
||||
data?: {
|
||||
nodes?: Array<{
|
||||
metadata?: { _id?: string; content?: string };
|
||||
text?: string;
|
||||
}>;
|
||||
};
|
||||
}>(chunkListAfterUpdateRun.stdout);
|
||||
const updatedChunk = chunkListAfterUpdateData.data?.nodes?.find(
|
||||
(node) => node.metadata?._id === addedChunkId,
|
||||
);
|
||||
expect(updatedChunk?.metadata?.content ?? updatedChunk?.text).toBe(updateMarker);
|
||||
}
|
||||
} finally {
|
||||
// cleanup kb (retry for IndexStatusError)
|
||||
if (indexId) {
|
||||
let cleanupRun = await runCommandE2e(KNOWLEDGE_KB_DELETE_ROUTES, [
|
||||
"knowledge",
|
||||
"delete",
|
||||
"--index-id",
|
||||
indexId,
|
||||
"--yes",
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
]);
|
||||
for (let retry = 0; retry < 5 && cleanupRun.exitCode !== 0; retry++) {
|
||||
if (!cleanupRun.stderr.includes("IndexStatusError")) break;
|
||||
await new Promise((resolve) => setTimeout(resolve, 10_000));
|
||||
cleanupRun = await runCommandE2e(KNOWLEDGE_KB_DELETE_ROUTES, [
|
||||
"knowledge",
|
||||
"delete",
|
||||
"--index-id",
|
||||
indexId,
|
||||
"--yes",
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
// cleanup file + category
|
||||
await runCommandE2e(KNOWLEDGE_CHUNK_CATEGORY_FILE_ROUTES, [
|
||||
"knowledge",
|
||||
"file",
|
||||
"delete",
|
||||
"--file-id",
|
||||
fileId,
|
||||
"--yes",
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
]);
|
||||
await runCommandE2e(KNOWLEDGE_CHUNK_CATEGORY_FILE_ROUTES, [
|
||||
"knowledge",
|
||||
"category",
|
||||
"delete",
|
||||
"--category-id",
|
||||
categoryId,
|
||||
"--yes",
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
]);
|
||||
}
|
||||
// kb create --wait adds a full import phase — generous timeout
|
||||
}, 600_000);
|
||||
});
|
||||
|
||||
interface ChunkListNodes {
|
||||
data?: { nodes?: Array<{ metadata?: Record<string, unknown> }> };
|
||||
}
|
||||
@@ -1771,4 +2123,103 @@ describe.skipIf(!isOssImportE2EReady())("e2e: doc import-oss live (授权 bucket
|
||||
expect(customDetail.data.connectorName).toBe(connectorName);
|
||||
expect(customDetail.data.connectorType).toBe("FILE");
|
||||
}, 60_000);
|
||||
|
||||
test("import-oss --category-id --tag → file list + file get 读回验证", async () => {
|
||||
// P5: verify --category-id and --tag params land on the server via read-back
|
||||
const categoryName = `e2e-oss-cat-${Date.now() % 100000000}`;
|
||||
const categoryAddRun = await runCommandE2e(KNOWLEDGE_CHUNK_CATEGORY_FILE_ROUTES, [
|
||||
"knowledge",
|
||||
"category",
|
||||
"add",
|
||||
"--name",
|
||||
categoryName,
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
"--quiet",
|
||||
]);
|
||||
expect(categoryAddRun.exitCode, categoryAddRun.stderr).toBe(0);
|
||||
const categoryId = categoryAddRun.stdout.trim();
|
||||
expect(categoryId).toMatch(/^cate_/);
|
||||
|
||||
try {
|
||||
const importRun = await runCommandE2e(KNOWLEDGE_CHUNK_CATEGORY_FILE_ROUTES, [
|
||||
"knowledge",
|
||||
"doc",
|
||||
"import-oss",
|
||||
"--bucket",
|
||||
ossBucket,
|
||||
"--region",
|
||||
ossRegion,
|
||||
"--oss-key",
|
||||
ossKey,
|
||||
"--category-id",
|
||||
categoryId,
|
||||
"--tag",
|
||||
"e2e-oss-tag",
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
"--quiet",
|
||||
]);
|
||||
expect(importRun.exitCode, importRun.stderr).toBe(0);
|
||||
const fileId = importRun.stdout.trim();
|
||||
expect(fileId).toMatch(/^file_/);
|
||||
|
||||
try {
|
||||
// file list --category-id read-back: file is under the category
|
||||
const fileListRun = await runCommandE2e(KNOWLEDGE_CHUNK_CATEGORY_FILE_ROUTES, [
|
||||
"knowledge",
|
||||
"file",
|
||||
"list",
|
||||
"--category-id",
|
||||
categoryId,
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
"--quiet",
|
||||
]);
|
||||
expect(fileListRun.exitCode, fileListRun.stderr).toBe(0);
|
||||
expect(fileListRun.stdout.trim().split("\n")).toContain(fileId);
|
||||
|
||||
// file get read-back: tags contain "e2e-oss-tag"
|
||||
const fileGetRun = await runCommandE2e(KNOWLEDGE_CHUNK_CATEGORY_FILE_ROUTES, [
|
||||
"knowledge",
|
||||
"file",
|
||||
"get",
|
||||
"--file-id",
|
||||
fileId,
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
"--output",
|
||||
"json",
|
||||
]);
|
||||
expect(fileGetRun.exitCode, fileGetRun.stderr).toBe(0);
|
||||
const fileDetail = parseStdoutJson<{
|
||||
data: { category?: string; tags?: unknown };
|
||||
}>(fileGetRun.stdout);
|
||||
expect(fileDetail.data.category).toBe(categoryId);
|
||||
expect(JSON.stringify(fileDetail.data.tags ?? "")).toContain("e2e-oss-tag");
|
||||
} finally {
|
||||
await runCommandE2e(KNOWLEDGE_CHUNK_CATEGORY_FILE_ROUTES, [
|
||||
"knowledge",
|
||||
"file",
|
||||
"delete",
|
||||
"--file-id",
|
||||
fileId,
|
||||
"--yes",
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
]);
|
||||
}
|
||||
} finally {
|
||||
await runCommandE2e(KNOWLEDGE_CHUNK_CATEGORY_FILE_ROUTES, [
|
||||
"knowledge",
|
||||
"category",
|
||||
"delete",
|
||||
"--category-id",
|
||||
categoryId,
|
||||
"--yes",
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
]);
|
||||
}
|
||||
}, 120_000);
|
||||
});
|
||||
|
||||
@@ -93,5 +93,25 @@ describe.skipIf(!isKbAdminE2EReady())("e2e: knowledge doc list (live)", () => {
|
||||
expect(exitCode, stderr).toBe(0);
|
||||
const data = parseStdoutJson<{ code: string }>(stdout);
|
||||
expect(data.code).toBe("Success");
|
||||
|
||||
// P6: --page-number + --page-size
|
||||
const pagedRun = await runCommandE2e(KNOWLEDGE_DOC_LIST_ROUTES, [
|
||||
"knowledge",
|
||||
"doc",
|
||||
"list",
|
||||
"--index-id",
|
||||
firstIndexId,
|
||||
"--page-number",
|
||||
"1",
|
||||
"--page-size",
|
||||
"10",
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
"--output",
|
||||
"json",
|
||||
]);
|
||||
expect(pagedRun.exitCode, pagedRun.stderr).toBe(0);
|
||||
const pagedData = parseStdoutJson<{ code: string }>(pagedRun.stdout);
|
||||
expect(pagedData.code).toBe("Success");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import { mkdtempSync, writeFileSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { describe, expect, test } from "vite-plus/test";
|
||||
import { parseStdoutJson, runCommandE2e } from "../helpers.ts";
|
||||
import { isKbAdminE2EReady, parseStdoutJson, runCommandE2e } from "../helpers.ts";
|
||||
import { KNOWLEDGE_DOC_STATUS_ROUTES } from "../topic-routes.ts";
|
||||
|
||||
// Live coverage depends on a real job_id produced by doc upload; it is exercised
|
||||
@@ -93,3 +96,139 @@ describe("e2e: knowledge doc status", () => {
|
||||
expect(data.endpoint).toMatch(/page_size=50/);
|
||||
});
|
||||
});
|
||||
|
||||
// Live: --wait + --poll-interval on a real job_id produced by upload --index-id --wait
|
||||
describe.skipIf(!isKbAdminE2EReady())("e2e: knowledge doc status (live, 自清理)", () => {
|
||||
const workspaceId = process.env.BAILIAN_WORKSPACE_ID!;
|
||||
|
||||
test("status --wait --poll-interval → 返回 COMPLETED", async () => {
|
||||
const fixtureDir = mkdtempSync(join(tmpdir(), "doc-status-e2e-"));
|
||||
const filePathA = join(fixtureDir, `status-a-${Date.now()}.md`);
|
||||
writeFileSync(filePathA, "# doc status e2e fixture A\n");
|
||||
|
||||
// 1) Upload file A to data center
|
||||
const uploadRunA = await runCommandE2e(KNOWLEDGE_DOC_STATUS_ROUTES, [
|
||||
"knowledge",
|
||||
"doc",
|
||||
"upload",
|
||||
"--file",
|
||||
filePathA,
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
"--quiet",
|
||||
]);
|
||||
expect(uploadRunA.exitCode, uploadRunA.stderr).toBe(0);
|
||||
const fileIdA = uploadRunA.stdout.trim();
|
||||
expect(fileIdA).toMatch(/^file_/);
|
||||
|
||||
let indexId = "";
|
||||
let fileIdB = "";
|
||||
try {
|
||||
// 2) Create a throwaway base (gives us an index_id)
|
||||
const createRun = await runCommandE2e(KNOWLEDGE_DOC_STATUS_ROUTES, [
|
||||
"knowledge",
|
||||
"create",
|
||||
"--name",
|
||||
`e2e-st-${Date.now() % 100000000}`,
|
||||
"--doc-id",
|
||||
fileIdA,
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
"--wait",
|
||||
"--quiet",
|
||||
]);
|
||||
expect(createRun.exitCode, createRun.stderr).toBe(0);
|
||||
indexId = createRun.stdout.trim().split("\n")[0]!;
|
||||
expect(indexId).toBeTruthy();
|
||||
|
||||
// 3) Upload file B to the base (--index-id --wait --output json) → ingestion_id
|
||||
const filePathB = join(fixtureDir, `status-b-${Date.now()}.md`);
|
||||
writeFileSync(filePathB, "# doc status e2e fixture B\n");
|
||||
const uploadRunB = await runCommandE2e(KNOWLEDGE_DOC_STATUS_ROUTES, [
|
||||
"knowledge",
|
||||
"doc",
|
||||
"upload",
|
||||
"--file",
|
||||
filePathB,
|
||||
"--index-id",
|
||||
indexId,
|
||||
"--wait",
|
||||
"--poll-interval",
|
||||
"3",
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
"--output",
|
||||
"json",
|
||||
]);
|
||||
expect(uploadRunB.exitCode, uploadRunB.stderr).toBe(0);
|
||||
const importData = parseStdoutJson<{
|
||||
files: Array<{ fileId: string }>;
|
||||
ingestion_id?: string;
|
||||
final_status?: string;
|
||||
}>(uploadRunB.stdout);
|
||||
const jobId = importData.ingestion_id;
|
||||
expect(jobId).toBeTruthy();
|
||||
fileIdB = importData.files?.[0]?.fileId ?? "";
|
||||
|
||||
// 4) status --wait --poll-interval: verify COMPLETED
|
||||
// (upload --wait already ensured completion, so this should return immediately)
|
||||
const statusRun = await runCommandE2e(KNOWLEDGE_DOC_STATUS_ROUTES, [
|
||||
"knowledge",
|
||||
"doc",
|
||||
"status",
|
||||
"--index-id",
|
||||
indexId,
|
||||
"--job-id",
|
||||
jobId!,
|
||||
"--wait",
|
||||
"--poll-interval",
|
||||
"3",
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
"--output",
|
||||
"json",
|
||||
]);
|
||||
expect(statusRun.exitCode, statusRun.stderr).toBe(0);
|
||||
const statusData = parseStdoutJson<{
|
||||
data?: { final_status?: string };
|
||||
}>(statusRun.stdout);
|
||||
expect(statusData.data?.final_status).toBe("COMPLETED");
|
||||
} finally {
|
||||
// Cleanup base + data-center files
|
||||
if (fileIdB) {
|
||||
await runCommandE2e(KNOWLEDGE_DOC_STATUS_ROUTES, [
|
||||
"knowledge",
|
||||
"file",
|
||||
"delete",
|
||||
"--file-id",
|
||||
fileIdB,
|
||||
"--yes",
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
]);
|
||||
}
|
||||
if (indexId) {
|
||||
await runCommandE2e(KNOWLEDGE_DOC_STATUS_ROUTES, [
|
||||
"knowledge",
|
||||
"delete",
|
||||
"--index-id",
|
||||
indexId,
|
||||
"--yes",
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
]);
|
||||
}
|
||||
await runCommandE2e(KNOWLEDGE_DOC_STATUS_ROUTES, [
|
||||
"knowledge",
|
||||
"file",
|
||||
"delete",
|
||||
"--file-id",
|
||||
fileIdA,
|
||||
"--yes",
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
]);
|
||||
}
|
||||
// kb create --wait adds a full import phase — generous timeout
|
||||
}, 600_000);
|
||||
});
|
||||
|
||||
@@ -240,4 +240,57 @@ describe.skipIf(!isKbAdminE2EReady())("e2e: knowledge doc upload (live)", () =>
|
||||
expect(fileDeleteRun.exitCode, fileDeleteRun.stderr).toBe(0);
|
||||
}
|
||||
}, 120_000);
|
||||
|
||||
test("upload --index-id --wait --poll-interval 3 (不报错验证)", async () => {
|
||||
// P6: --poll-interval — local behavior param, verify no error
|
||||
// Grab a real index id from the workspace
|
||||
const listRun = await runCommandE2e(KNOWLEDGE_DOC_UPLOAD_ROUTES, [
|
||||
"knowledge",
|
||||
"list",
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
"--quiet",
|
||||
]);
|
||||
expect(listRun.exitCode, listRun.stderr).toBe(0);
|
||||
const indexId = listRun.stdout.trim().split("\n")[0];
|
||||
if (!indexId) return;
|
||||
|
||||
const pollFilePath = join(fixtureDir, `poll-${Date.now()}.md`);
|
||||
writeFileSync(pollFilePath, "# e2e poll interval fixture\n");
|
||||
const uploadRun = await runCommandE2e(KNOWLEDGE_DOC_UPLOAD_ROUTES, [
|
||||
"knowledge",
|
||||
"doc",
|
||||
"upload",
|
||||
"--file",
|
||||
pollFilePath,
|
||||
"--index-id",
|
||||
indexId,
|
||||
"--wait",
|
||||
"--poll-interval",
|
||||
"3",
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
"--output",
|
||||
"json",
|
||||
]);
|
||||
expect(uploadRun.exitCode, uploadRun.stderr).toBe(0);
|
||||
|
||||
// Cleanup the uploaded file
|
||||
const importData = parseStdoutJson<{
|
||||
files: Array<{ fileId: string }>;
|
||||
}>(uploadRun.stdout);
|
||||
const pollFileId = importData.files?.[0]?.fileId;
|
||||
if (pollFileId) {
|
||||
await runCommandE2e(KNOWLEDGE_DOC_UPLOAD_ROUTES, [
|
||||
"knowledge",
|
||||
"file",
|
||||
"delete",
|
||||
"--file-id",
|
||||
pollFileId,
|
||||
"--yes",
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
]);
|
||||
}
|
||||
}, 120_000);
|
||||
});
|
||||
|
||||
@@ -106,6 +106,8 @@ describe.skipIf(!isKbAdminE2EReady())("e2e: knowledge kb 写链路 (live, 自清
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
"--wait",
|
||||
"--poll-interval",
|
||||
"3",
|
||||
"--quiet",
|
||||
]);
|
||||
expect(createRun.exitCode, createRun.stderr).toBe(0);
|
||||
|
||||
@@ -124,4 +124,51 @@ describe.skipIf(!isKbAdminE2EReady())("e2e: knowledge kb list (live)", () => {
|
||||
const lines = quietRun.stdout.trim().split("\n").filter(Boolean);
|
||||
expect(lines.length).toBe(rows.length);
|
||||
});
|
||||
|
||||
test("--name 过滤 + --page-number/--page-size 分页", async () => {
|
||||
// P6: --name
|
||||
const jsonRun = await runCommandE2e(KNOWLEDGE_KB_LIST_ROUTES, [
|
||||
"knowledge",
|
||||
"list",
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
"--output",
|
||||
"json",
|
||||
]);
|
||||
expect(jsonRun.exitCode, jsonRun.stderr).toBe(0);
|
||||
const allRows = parseStdoutJson<KbListResponse>(jsonRun.stdout).data.rows;
|
||||
if (allRows.length === 0) return;
|
||||
|
||||
const firstName = allRows[0]!.name;
|
||||
const nameRun = await runCommandE2e(KNOWLEDGE_KB_LIST_ROUTES, [
|
||||
"knowledge",
|
||||
"list",
|
||||
"--name",
|
||||
firstName,
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
"--output",
|
||||
"json",
|
||||
]);
|
||||
expect(nameRun.exitCode, nameRun.stderr).toBe(0);
|
||||
const nameData = parseStdoutJson<KbListResponse>(nameRun.stdout);
|
||||
expect(nameData.data.rows.some((row) => row.name === firstName)).toBe(true);
|
||||
|
||||
// P6: --page-number + --page-size
|
||||
const pagedRun = await runCommandE2e(KNOWLEDGE_KB_LIST_ROUTES, [
|
||||
"knowledge",
|
||||
"list",
|
||||
"--page-number",
|
||||
"1",
|
||||
"--page-size",
|
||||
"1",
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
"--output",
|
||||
"json",
|
||||
]);
|
||||
expect(pagedRun.exitCode, pagedRun.stderr).toBe(0);
|
||||
const pagedData = parseStdoutJson<KbListResponse>(pagedRun.stdout);
|
||||
expect(pagedData.data.rows.length).toBeLessThanOrEqual(1);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -668,3 +668,356 @@ describe.skipIf(!isKbAdminE2EReady())("e2e: knowledge service 生命周期 (live
|
||||
}
|
||||
}, 300_000);
|
||||
});
|
||||
|
||||
// Live parameter coverage: every write parameter gets a read-back assertion
|
||||
// via `service get --output json`. Read-back fields are confirmed present in
|
||||
// the get response by the existing lifecycle test and printDetail().
|
||||
describe.skipIf(!isKbAdminE2EReady())("e2e: knowledge service 参数全覆盖 (live, 自清理)", () => {
|
||||
const workspaceId = process.env.BAILIAN_WORKSPACE_ID!;
|
||||
|
||||
test("create --description → update(name/model/policy×2/version-desc) → list(status×3/scene/name/index-id) → deploy → published update --version-desc → delete", async () => {
|
||||
const serviceName = `e2e-svc-param-${Date.now() % 100000000}`;
|
||||
let agentId: string | undefined;
|
||||
|
||||
try {
|
||||
// ── P6: service-create --description ──
|
||||
const createRun = await runCommandE2e(KNOWLEDGE_SERVICE_ROUTES, [
|
||||
"knowledge",
|
||||
"service",
|
||||
"create",
|
||||
"--name",
|
||||
serviceName,
|
||||
"--scene",
|
||||
"chat",
|
||||
"--description",
|
||||
"e2e param coverage",
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
"--quiet",
|
||||
]);
|
||||
expect(createRun.exitCode, createRun.stderr).toBe(0);
|
||||
agentId = createRun.stdout.trim().split("\n").pop()!;
|
||||
expect(agentId).toMatch(/^aid-/);
|
||||
|
||||
// get 读回验证 --description (agent_desc)
|
||||
const createGetRun = await runCommandE2e(KNOWLEDGE_SERVICE_ROUTES, [
|
||||
"knowledge",
|
||||
"service",
|
||||
"get",
|
||||
"--agent-id",
|
||||
agentId,
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
"--output",
|
||||
"json",
|
||||
]);
|
||||
expect(createGetRun.exitCode, createGetRun.stderr).toBe(0);
|
||||
const createGetData = parseStdoutJson<{
|
||||
data?: { agent_desc?: string };
|
||||
}>(createGetRun.stdout);
|
||||
expect(createGetData.data?.agent_desc).toBe("e2e param coverage");
|
||||
|
||||
// ── P1: list --status draft 验证新建 agent 可见 ──
|
||||
const listDraftRun = await runCommandE2e(KNOWLEDGE_SERVICE_ROUTES, [
|
||||
"knowledge",
|
||||
"service",
|
||||
"list",
|
||||
"--scene",
|
||||
"chat",
|
||||
"--status",
|
||||
"draft",
|
||||
"--agent-id",
|
||||
agentId,
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
"--quiet",
|
||||
]);
|
||||
expect(listDraftRun.exitCode, listDraftRun.stderr).toBe(0);
|
||||
expect(listDraftRun.stdout.trim().split("\n")).toContain(agentId);
|
||||
|
||||
// ── P1: list --scene search (live 合法值) ──
|
||||
const listSearchSceneRun = await runCommandE2e(KNOWLEDGE_SERVICE_ROUTES, [
|
||||
"knowledge",
|
||||
"service",
|
||||
"list",
|
||||
"--scene",
|
||||
"search",
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
"--quiet",
|
||||
]);
|
||||
expect(listSearchSceneRun.exitCode, listSearchSceneRun.stderr).toBe(0);
|
||||
|
||||
// ── P1: list --name 精确过滤 ──
|
||||
const listNameRun = await runCommandE2e(KNOWLEDGE_SERVICE_ROUTES, [
|
||||
"knowledge",
|
||||
"service",
|
||||
"list",
|
||||
"--scene",
|
||||
"chat",
|
||||
"--name",
|
||||
serviceName,
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
"--quiet",
|
||||
]);
|
||||
expect(listNameRun.exitCode, listNameRun.stderr).toBe(0);
|
||||
expect(listNameRun.stdout.trim().split("\n")).toContain(agentId);
|
||||
|
||||
// ── P1: list --index-id (不报错验证; 无 kb fixture) ──
|
||||
const listIndexIdRun = await runCommandE2e(KNOWLEDGE_SERVICE_ROUTES, [
|
||||
"knowledge",
|
||||
"service",
|
||||
"list",
|
||||
"--scene",
|
||||
"search",
|
||||
"--index-id",
|
||||
"idx_nonexistent_e2e",
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
"--quiet",
|
||||
]);
|
||||
expect(listIndexIdRun.exitCode, listIndexIdRun.stderr).toBe(0);
|
||||
|
||||
// ── P0 组1: update --name --version-desc --model → get 读回 3 个 scalar ──
|
||||
const newName = `${serviceName}-renamed`;
|
||||
const updateScalarRun = await runCommandE2e(KNOWLEDGE_SERVICE_ROUTES, [
|
||||
"knowledge",
|
||||
"service",
|
||||
"update",
|
||||
"--agent-id",
|
||||
agentId,
|
||||
"--name",
|
||||
newName,
|
||||
"--version-desc",
|
||||
"beta-v1",
|
||||
"--model",
|
||||
"qwen-plus",
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
]);
|
||||
expect(updateScalarRun.exitCode, updateScalarRun.stderr).toBe(0);
|
||||
|
||||
const scalarGetRun = await runCommandE2e(KNOWLEDGE_SERVICE_ROUTES, [
|
||||
"knowledge",
|
||||
"service",
|
||||
"get",
|
||||
"--agent-id",
|
||||
agentId,
|
||||
"--agent-version",
|
||||
"beta",
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
"--output",
|
||||
"json",
|
||||
]);
|
||||
expect(scalarGetRun.exitCode, scalarGetRun.stderr).toBe(0);
|
||||
const scalarGetData = parseStdoutJson<{
|
||||
data?: {
|
||||
agent_name?: string;
|
||||
agent_details?: Array<{
|
||||
agent_version_desc?: string;
|
||||
agent_config?: { agent_model?: string };
|
||||
}>;
|
||||
};
|
||||
}>(scalarGetRun.stdout);
|
||||
expect(scalarGetData.data?.agent_name).toBe(newName);
|
||||
expect(scalarGetData.data?.agent_details?.[0]?.agent_config?.agent_model).toBe("qwen-plus");
|
||||
expect(scalarGetData.data?.agent_details?.[0]?.agent_version_desc).toBe("beta-v1");
|
||||
|
||||
// ── P0 组2: update --policy turbo → get 读回 ──
|
||||
const updateTurboRun = await runCommandE2e(KNOWLEDGE_SERVICE_ROUTES, [
|
||||
"knowledge",
|
||||
"service",
|
||||
"update",
|
||||
"--agent-id",
|
||||
agentId,
|
||||
"--policy",
|
||||
"turbo",
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
]);
|
||||
expect(updateTurboRun.exitCode, updateTurboRun.stderr).toBe(0);
|
||||
|
||||
const turboGetRun = await runCommandE2e(KNOWLEDGE_SERVICE_ROUTES, [
|
||||
"knowledge",
|
||||
"service",
|
||||
"get",
|
||||
"--agent-id",
|
||||
agentId,
|
||||
"--agent-version",
|
||||
"beta",
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
"--output",
|
||||
"json",
|
||||
]);
|
||||
expect(turboGetRun.exitCode, turboGetRun.stderr).toBe(0);
|
||||
const turboData = parseStdoutJson<{
|
||||
data?: {
|
||||
agent_details?: Array<{
|
||||
agent_config?: { agent_policy?: string };
|
||||
}>;
|
||||
};
|
||||
}>(turboGetRun.stdout);
|
||||
expect(turboData.data?.agent_details?.[0]?.agent_config?.agent_policy).toBe("turbo");
|
||||
|
||||
// ── P0 组3: update --policy agentic → get 读回 ──
|
||||
// 注: --max-llm-calls 10 仅作为 agentic 切换的前置条件,不做读回验证
|
||||
const updateAgenticRun = await runCommandE2e(KNOWLEDGE_SERVICE_ROUTES, [
|
||||
"knowledge",
|
||||
"service",
|
||||
"update",
|
||||
"--agent-id",
|
||||
agentId,
|
||||
"--policy",
|
||||
"agentic",
|
||||
"--max-llm-calls",
|
||||
"10",
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
]);
|
||||
expect(updateAgenticRun.exitCode, updateAgenticRun.stderr).toBe(0);
|
||||
|
||||
const agenticGetRun = await runCommandE2e(KNOWLEDGE_SERVICE_ROUTES, [
|
||||
"knowledge",
|
||||
"service",
|
||||
"get",
|
||||
"--agent-id",
|
||||
agentId,
|
||||
"--agent-version",
|
||||
"beta",
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
"--output",
|
||||
"json",
|
||||
]);
|
||||
expect(agenticGetRun.exitCode, agenticGetRun.stderr).toBe(0);
|
||||
const agenticData = parseStdoutJson<{
|
||||
data?: {
|
||||
agent_details?: Array<{
|
||||
agent_config?: { agent_policy?: string };
|
||||
}>;
|
||||
};
|
||||
}>(agenticGetRun.stdout);
|
||||
expect(agenticData.data?.agent_details?.[0]?.agent_config?.agent_policy).toBe("agentic");
|
||||
|
||||
// ── deploy → P1: list --status deployed ──
|
||||
const deployRun = await runCommandE2e(KNOWLEDGE_SERVICE_ROUTES, [
|
||||
"knowledge",
|
||||
"service",
|
||||
"deploy",
|
||||
"--agent-id",
|
||||
agentId,
|
||||
"--yes",
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
"--quiet",
|
||||
]);
|
||||
expect(deployRun.exitCode, deployRun.stderr).toBe(0);
|
||||
|
||||
const listDeployedRun = await runCommandE2e(KNOWLEDGE_SERVICE_ROUTES, [
|
||||
"knowledge",
|
||||
"service",
|
||||
"list",
|
||||
"--scene",
|
||||
"chat",
|
||||
"--status",
|
||||
"deployed",
|
||||
"--agent-id",
|
||||
agentId,
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
"--quiet",
|
||||
]);
|
||||
expect(listDeployedRun.exitCode, listDeployedRun.stderr).toBe(0);
|
||||
expect(listDeployedRun.stdout.trim().split("\n")).toContain(agentId);
|
||||
|
||||
// ── P0 组4: update --agent-version 1 --version-desc (published version) ──
|
||||
const updatePublishedRun = await runCommandE2e(KNOWLEDGE_SERVICE_ROUTES, [
|
||||
"knowledge",
|
||||
"service",
|
||||
"update",
|
||||
"--agent-id",
|
||||
agentId,
|
||||
"--agent-version",
|
||||
"1",
|
||||
"--version-desc",
|
||||
"published-v1-desc",
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
]);
|
||||
expect(updatePublishedRun.exitCode, updatePublishedRun.stderr).toBe(0);
|
||||
|
||||
// get --agent-version 1 读回验证 --version-desc
|
||||
const publishedGetRun = await runCommandE2e(KNOWLEDGE_SERVICE_ROUTES, [
|
||||
"knowledge",
|
||||
"service",
|
||||
"get",
|
||||
"--agent-id",
|
||||
agentId,
|
||||
"--agent-version",
|
||||
"1",
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
"--output",
|
||||
"json",
|
||||
]);
|
||||
expect(publishedGetRun.exitCode, publishedGetRun.stderr).toBe(0);
|
||||
const publishedData = parseStdoutJson<{
|
||||
data?: {
|
||||
agent_details?: Array<{ agent_version_desc?: string }>;
|
||||
};
|
||||
}>(publishedGetRun.stdout);
|
||||
expect(publishedData.data?.agent_details?.[0]?.agent_version_desc).toBe("published-v1-desc");
|
||||
|
||||
// ── delete → P1: list --status deleted ──
|
||||
const deleteRun = await runCommandE2e(KNOWLEDGE_SERVICE_ROUTES, [
|
||||
"knowledge",
|
||||
"service",
|
||||
"delete",
|
||||
"--agent-id",
|
||||
agentId,
|
||||
"--yes",
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
]);
|
||||
expect(deleteRun.exitCode, deleteRun.stderr).toBe(0);
|
||||
|
||||
const listDeletedRun = await runCommandE2e(KNOWLEDGE_SERVICE_ROUTES, [
|
||||
"knowledge",
|
||||
"service",
|
||||
"list",
|
||||
"--scene",
|
||||
"chat",
|
||||
"--status",
|
||||
"deleted",
|
||||
"--agent-id",
|
||||
agentId,
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
"--quiet",
|
||||
]);
|
||||
expect(listDeletedRun.exitCode, listDeletedRun.stderr).toBe(0);
|
||||
// 软验证: deleted 状态下 agent 应出现在列表中;
|
||||
// 若服务端不返回 deleted 列表则仅验证不报错
|
||||
if (listDeletedRun.stdout.trim()) {
|
||||
expect(listDeletedRun.stdout.trim().split("\n")).toContain(agentId);
|
||||
}
|
||||
} finally {
|
||||
// 兜底清理
|
||||
if (agentId) {
|
||||
await runCommandE2e(KNOWLEDGE_SERVICE_ROUTES, [
|
||||
"knowledge",
|
||||
"service",
|
||||
"delete",
|
||||
"--agent-id",
|
||||
agentId,
|
||||
"--yes",
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}, 300_000);
|
||||
});
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
import { describe, expect, test } from "vite-plus/test";
|
||||
import { isDashScopeE2EReady, parseStdoutJson, runCommandE2e } from "../helpers.ts";
|
||||
import {
|
||||
isDashScopeE2EReady,
|
||||
isKbAdminE2EReady,
|
||||
parseStdoutJson,
|
||||
runCommandE2e,
|
||||
} from "../helpers.ts";
|
||||
import { KNOWLEDGE_ROUTES } from "../topic-routes.ts";
|
||||
|
||||
// ---- Types ----
|
||||
@@ -187,3 +192,57 @@ describe("e2e: knowledge retrieve dry-run", () => {
|
||||
expect(data.request?.rerank?.[0]?.rerank_instruct).toBe("按相关性排序");
|
||||
});
|
||||
});
|
||||
|
||||
// Live: --rerank-instruct and --top-k (deprecated) on a real index
|
||||
describe.skipIf(!isKbAdminE2EReady())("e2e: knowledge retrieve 参数补全 (live)", () => {
|
||||
const workspaceId = process.env.BAILIAN_WORKSPACE_ID!;
|
||||
|
||||
test("retrieve --rerank-instruct + --top-k (不报错验证)", async () => {
|
||||
// Grab a real index id from the workspace
|
||||
const listRun = await runCommandE2e(KNOWLEDGE_ROUTES, [
|
||||
"knowledge",
|
||||
"list",
|
||||
"--workspace-id",
|
||||
workspaceId,
|
||||
"--quiet",
|
||||
]);
|
||||
expect(listRun.exitCode, listRun.stderr).toBe(0);
|
||||
const indexId = listRun.stdout.trim().split("\n")[0];
|
||||
if (!indexId) return;
|
||||
|
||||
// P6: --rerank-instruct (live)
|
||||
const rerankInstructRun = await runCommandE2e(KNOWLEDGE_ROUTES, [
|
||||
"knowledge",
|
||||
"retrieve",
|
||||
"--index-id",
|
||||
indexId,
|
||||
"--query",
|
||||
"e2e test",
|
||||
"--rerank",
|
||||
"--rerank-model",
|
||||
"qwen3-rerank-hybrid",
|
||||
"--rerank-mode",
|
||||
"custom",
|
||||
"--rerank-instruct",
|
||||
"按相关性排序",
|
||||
"--output",
|
||||
"json",
|
||||
]);
|
||||
expect(rerankInstructRun.exitCode, rerankInstructRun.stderr).toBe(0);
|
||||
|
||||
// P6: --top-k (deprecated, verify still accepted)
|
||||
const topKRun = await runCommandE2e(KNOWLEDGE_ROUTES, [
|
||||
"knowledge",
|
||||
"retrieve",
|
||||
"--index-id",
|
||||
indexId,
|
||||
"--query",
|
||||
"e2e test",
|
||||
"--top-k",
|
||||
"10",
|
||||
"--output",
|
||||
"json",
|
||||
]);
|
||||
expect(topKRun.exitCode, topKRun.stderr).toBe(0);
|
||||
}, 60_000);
|
||||
});
|
||||
|
||||
@@ -39,6 +39,7 @@ export const KNOWLEDGE_ROUTES: E2eRouteExports = {
|
||||
"knowledge retrieve": "knowledgeRetrieve",
|
||||
"knowledge search": "knowledgeSearch",
|
||||
"knowledge chat": "knowledgeChat",
|
||||
"knowledge list": "knowledgeKbList", // live: grab a real index id for retrieve
|
||||
};
|
||||
|
||||
export const KNOWLEDGE_SEARCH_ROUTES: E2eRouteExports = {
|
||||
@@ -201,11 +202,16 @@ export const KNOWLEDGE_DOC_LIST_ROUTES: E2eRouteExports = {
|
||||
|
||||
export const KNOWLEDGE_DOC_STATUS_ROUTES: E2eRouteExports = {
|
||||
"knowledge doc status": "knowledgeDocStatus",
|
||||
"knowledge doc upload": "knowledgeDocUpload", // live: produce a real job_id
|
||||
"knowledge create": "knowledgeKbCreate", // live: create a throwaway base
|
||||
"knowledge delete": "knowledgeKbDelete", // live: cleanup the throwaway base
|
||||
"knowledge file delete": "knowledgeFileDelete", // live: cleanup data-center files
|
||||
};
|
||||
|
||||
export const KNOWLEDGE_DOC_UPLOAD_ROUTES: E2eRouteExports = {
|
||||
"knowledge doc upload": "knowledgeDocUpload",
|
||||
"knowledge file delete": "knowledgeFileDelete", // live cleanup of data-center files
|
||||
"knowledge list": "knowledgeKbList", // live: grab a real index id for --index-id --wait
|
||||
};
|
||||
|
||||
export const KNOWLEDGE_KB_CREATE_ROUTES: E2eRouteExports = {
|
||||
|
||||
Reference in New Issue
Block a user