Skip to content

Commit 1d98528

Browse files
committed
fix(knowledge): 修正文档上传接口请求的字段名为 docIds
- 将请求体中的 dataSource.fileIds 改为扁平结构的 docIds 字段 - 移除嵌套的 dataSource 对象,显式指定 sourceType 字段 - 更新相关单元测试以匹配新的请求参数格式和字段名称 - 在知识库删除测试中增加了导入结果和最终状态的断言,确保导入流程完整 - 新增校验导入文件在知识库文档列表中正确显示 - 调整测试中对请求体结构的断言逻辑以适配改动
1 parent 99a3dba commit 1d98528

3 files changed

Lines changed: 56 additions & 19 deletions

File tree

packages/commands/src/commands/knowledge/doc-upload.ts

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -149,10 +149,10 @@ export default defineCommand({
149149
endpoint: ragEndpoint(workspaceId, RAG_PATHS.indexJobCreate),
150150
request: {
151151
indexId: flags.indexId,
152-
// Gotcha (live-verified): job/create requires the nested dataSource shape;
153-
// the public docs' flat documentIds body returns Index.InvalidParameter.
154-
// Omitting sourceType would import the entire data center.
155-
dataSource: { sourceType: "DATA_CENTER_FILE", fileIds: ["<fileId>"] },
152+
// Live-verified: the field name is docIds (not documentIds as in the
153+
// public docs); omitting sourceType would import the entire data center.
154+
sourceType: "DATA_CENTER_FILE",
155+
docIds: ["<fileId>"],
156156
} as unknown,
157157
});
158158
}
@@ -259,11 +259,10 @@ export default defineCommand({
259259
method: "POST",
260260
body: {
261261
indexId: flags.indexId,
262-
// Live-verified shape: nested dataSource (the docs' flat documentIds is rejected)
263-
dataSource: {
264-
sourceType: "DATA_CENTER_FILE",
265-
fileIds: uploaded.map((item) => item.fileId),
266-
},
262+
// Live-verified: the field name is docIds (not documentIds as in the
263+
// public docs); omitting sourceType would import the entire data center.
264+
sourceType: "DATA_CENTER_FILE",
265+
docIds: uploaded.map((item) => item.fileId),
267266
},
268267
});
269268
ingestionId = job.data?.ingestionId;

packages/commands/tests/e2e/knowledge/knowledge-doc-upload.e2e.test.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ describe("e2e: knowledge doc upload", () => {
113113
expect(data.skipped).toEqual([]);
114114
});
115115

116-
test("--dry-run 带 --index-id 输出 4 步且 job 请求含显式 sourceType", async () => {
116+
test("--dry-run 带 --index-id 输出 4 步且 job 请求含扁平 docIds", async () => {
117117
const { stdout, stderr, exitCode } = await runCommandE2e(KNOWLEDGE_DOC_UPLOAD_ROUTES, [
118118
"knowledge",
119119
"doc",
@@ -135,13 +135,15 @@ describe("e2e: knowledge doc upload", () => {
135135
expect(data.steps).toHaveLength(4);
136136
const jobRequest = data.steps[3]!.request as {
137137
indexId?: string;
138-
dataSource?: { sourceType?: string; fileIds?: string[] };
138+
sourceType?: string;
139+
docIds?: string[];
139140
};
140-
// Live-verified gotcha: job/create requires the nested dataSource shape, and
141-
// omitting sourceType would import the entire data center
142-
expect(jobRequest.dataSource?.sourceType).toBe("DATA_CENTER_FILE");
141+
// Live-verified: the field name is docIds (not documentIds as in the
142+
// public docs); omitting sourceType would import the entire data center.
143+
expect(jobRequest.sourceType).toBe("DATA_CENTER_FILE");
144+
expect(jobRequest.docIds).toEqual(["<fileId>"]);
143145
expect(jobRequest.indexId).toBe("idx_test");
144-
expect(jobRequest).not.toHaveProperty("documentIds");
146+
expect(jobRequest).not.toHaveProperty("dataSource");
145147
});
146148

147149
test("--file <dir> dry-run 展开目录且 skipped 包含不支持的文件", async () => {

packages/commands/tests/e2e/knowledge/knowledge-kb-delete.e2e.test.ts

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// (import orchestration) → delete → list to verify removal.
33
import { mkdtempSync, writeFileSync } from "node:fs";
44
import { tmpdir } from "node:os";
5-
import { join } from "node:path";
5+
import { basename, join } from "node:path";
66
import { describe, expect, test } from "vite-plus/test";
77
import { isKbAdminE2EReady, parseStdoutJson, runCommandE2e } from "../helpers.ts";
88
import { deleteKbWithRetry } from "./journeys/journey-helpers.ts";
@@ -132,7 +132,9 @@ describe.skipIf(!isKbAdminE2EReady())("e2e: knowledge kb 写链路 (live, 自清
132132

133133
// 2.7) Live coverage of the upload → import orchestration (doc upload --index-id --wait):
134134
// the journeys always upload bare files and import via kb create, so this is the
135-
// only place the createImportJob step runs live
135+
// only place the createImportJob step runs live. Using --output json (not --quiet)
136+
// so we can assert final_status and ingestion_id — a regression in the job/create
137+
// request body (e.g. wrong field name) is caught by the server returning HTTP 400.
136138
const importFilePath = join(fixtureDir, `chain-import-${Date.now()}.md`);
137139
writeFileSync(importFilePath, "# kb chain e2e import fixture\n");
138140
const importUploadRun = await runCommandE2e(KNOWLEDGE_KB_DELETE_ROUTES, [
@@ -146,13 +148,47 @@ describe.skipIf(!isKbAdminE2EReady())("e2e: knowledge kb 写链路 (live, 自清
146148
"--wait",
147149
"--workspace-id",
148150
workspaceId,
149-
"--quiet",
151+
"--output",
152+
"json",
150153
]);
151154
expect(importUploadRun.exitCode, importUploadRun.stderr).toBe(0);
152-
const importedFileId = importUploadRun.stdout.trim();
155+
const importData = parseStdoutJson<{
156+
files: Array<{ fileId: string }>;
157+
ingestion_id?: string;
158+
final_status?: string;
159+
}>(importUploadRun.stdout);
160+
// These assertions verify the full pipeline completed: ingestion_id proves the
161+
// job was created, and final_status COMPLETED proves parsing finished successfully.
162+
expect(importData.ingestion_id).toBeTruthy();
163+
expect(importData.final_status).toBe("COMPLETED");
164+
const importedFileId = importData.files?.[0]?.fileId;
153165
expect(importedFileId).toMatch(/^file_/);
154166
fixtureFileIds.push(importedFileId);
155167

168+
// 2.8) Verify the imported file is actually visible in the KB — final_status
169+
// COMPLETED only proves the job finished; an independent doc list query
170+
// confirms the file was registered as a document in the index
171+
const importedFileName = basename(importFilePath);
172+
const docListRun = await runCommandE2e(KNOWLEDGE_KB_DELETE_ROUTES, [
173+
"knowledge",
174+
"doc",
175+
"list",
176+
"--index-id",
177+
indexId,
178+
"--workspace-id",
179+
workspaceId,
180+
"--output",
181+
"json",
182+
]);
183+
expect(docListRun.exitCode, docListRun.stderr).toBe(0);
184+
const docListData = parseStdoutJson<{
185+
data?: { rows?: Array<{ doc_name?: string; status?: string }> };
186+
}>(docListRun.stdout);
187+
const importedDoc = docListData.data?.rows?.find((row) =>
188+
row.doc_name?.includes(importedFileName),
189+
);
190+
expect(importedDoc, `expected doc list to contain file "${importedFileName}"`).toBeTruthy();
191+
156192
// 3) Delete the base (--yes non-interactive; deleteKbWithRetry retries on
157193
// IndexStatusError: readiness can lag briefly even after the import completes)
158194
const deleteRun = await deleteKbWithRetry(

0 commit comments

Comments
 (0)