Skip to content

Commit cc51164

Browse files
committed
fix(knowledge): 优化导入任务轮询逻辑与失败信息展示
- 添加函数判断所有文档是否达到终止状态,防止服务器无限保持运行状态 - 修改失败信息函数,展示失败和成功文档详情,方便用户了解整体情况 - 调整轮询任务完成条件,新增所有文档终止状态判断,提升轮询准确性 - 改进轮询状态显示,增加失败文档数量与总计信息,清晰反馈任务进展
1 parent 2d5c49b commit cc51164

1 file changed

Lines changed: 51 additions & 11 deletions

File tree

  • packages/commands/src/commands/knowledge

packages/commands/src/commands/knowledge/shared.ts

Lines changed: 51 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -74,17 +74,42 @@ export function failedImportDocs(response: RagIndexJobStatusResponse): RagIndexJ
7474
);
7575
}
7676

77-
/** Per-document failure summary: server message passed through verbatim + per-document detail */
77+
/**
78+
* Whether every document has reached a terminal state (FINISH or *FAILED).
79+
* Used to stop polling before ingestion_status becomes COMPLETED — the server
80+
* may leave the job on RUNNING indefinitely even after all documents finish.
81+
*/
82+
function allDocsTerminal(response: RagIndexJobStatusResponse): boolean {
83+
const rows = response.data?.rows ?? [];
84+
if (rows.length === 0) return false;
85+
const totalCount = response.data?.total_count;
86+
if (typeof totalCount === "number" && rows.length < totalCount) return false;
87+
return rows.every((doc) => {
88+
const code = doc.code ?? doc.status ?? "";
89+
return code === "FINISH" || code.includes("FAILED");
90+
});
91+
}
92+
93+
/** Per-document failure summary: lists both failed and succeeded documents so the user knows the full picture. */
7894
export function importJobFailureMessage(
7995
response: RagIndexJobStatusResponse,
8096
fallbackMessage: string,
8197
): string {
82-
const detail = failedImportDocs(response)
98+
const rows = response.data?.rows ?? [];
99+
const failed = failedImportDocs(response);
100+
const failedIds = new Set(failed.map((doc) => doc.doc_id));
101+
const succeeded = rows.filter((doc) => !failedIds.has(doc.doc_id));
102+
103+
const failedDetail = failed
83104
.map((doc) => `${doc.doc_name ?? doc.doc_id ?? "?"}: ${doc.message ?? doc.code ?? "unknown"}`)
84105
.join("; ");
85-
const base =
86-
typeof response.message === "string" && response.message ? response.message : fallbackMessage;
87-
return detail ? `${base} (${detail})` : base;
106+
const succeededDetail = succeeded.map((doc) => doc.doc_name ?? doc.doc_id ?? "?").join(", ");
107+
108+
const parts: string[] = [];
109+
if (failedDetail) parts.push(`failed: ${failedDetail}`);
110+
if (succeededDetail) parts.push(`succeeded: ${succeededDetail}`);
111+
112+
return parts.length > 0 ? `${fallbackMessage} (${parts.join("; ")})` : fallbackMessage;
88113
}
89114

90115
/** Build the index_job/status query string (both index_id and job_id are required) */
@@ -96,10 +121,13 @@ export function importJobStatusUrl(workspaceId: string, indexId: string, jobId:
96121
}
97122

98123
/**
99-
* Poll the import job until the overall state is COMPLETED.
100-
* The overall state has no FAILED value, so isFailed is always false — failures
101-
* are determined by the caller after return via `failedImportDocs` (semantics:
102-
* the job finished, but some documents failed to parse).
124+
* Poll the import job until the overall state is COMPLETED or every document
125+
* has reached a terminal state (FINISH or FAILED). The overall state has no
126+
* FAILED value, so isFailed is always false — failures are determined by the
127+
* caller after return via `failedImportDocs`. The server may leave
128+
* ingestion_status on RUNNING indefinitely after documents finish, so checking
129+
* rows[] mid-poll avoids a misleading timeout; callers re-check failedImportDocs
130+
* after return, keeping the error path uniform.
103131
*/
104132
export async function pollImportJob(
105133
client: Client,
@@ -110,9 +138,21 @@ export async function pollImportJob(
110138
url: options.statusUrl,
111139
intervalSec: options.intervalSec,
112140
timeoutSec: settings.timeout,
113-
isComplete: (data) => importJobStatus(data) === "COMPLETED",
141+
isComplete: (data) => {
142+
const response = data as RagIndexJobStatusResponse;
143+
return importJobStatus(response) === "COMPLETED" || allDocsTerminal(response);
144+
},
114145
isFailed: () => false,
115-
getStatus: (data) => importJobStatus(data),
146+
getStatus: (data) => {
147+
const response = data as RagIndexJobStatusResponse;
148+
const status = importJobStatus(response);
149+
const failedCount = failedImportDocs(response).length;
150+
const total = response.data?.total_count;
151+
if (typeof total === "number" && total > 0) {
152+
return `${status} (${failedCount}/${total} failed)`;
153+
}
154+
return failedCount > 0 ? `${status} (${failedCount} failed)` : status;
155+
},
116156
});
117157
}
118158

0 commit comments

Comments
 (0)