diff --git a/frontend-web/src/roundtable-planning/api/ingest.ts b/frontend-web/src/roundtable-planning/api/ingest.ts index c0cc44ed..9f89a8ed 100644 --- a/frontend-web/src/roundtable-planning/api/ingest.ts +++ b/frontend-web/src/roundtable-planning/api/ingest.ts @@ -7,14 +7,31 @@ */ import { loadSkills } from "@/core/skills/api"; -/** 入库技能名(示例/真实共用同一名字,方便无缝替换)。 */ +/** 示例入库技能名(真实技能可改名;门控按「入库相关」关键字判断,不写死此名)。 */ export const INGEST_SKILL_NAME = "knowledge-base-ingest"; -/** 入库技能是否存在且启用。失败回退 false(不弹入库询问)。 */ +/** + * 是否为「入库相关」技能:按 name / name_zh / description 含 `ingest` 或「入库」判断。 + * 这样示例技能(knowledge-base-ingest)与**后续改了名的真实入库技能**都能识别; + * 而知识库**检索**类技能(如 knowledge-base-search「知识库检索」)不含「入库」/`ingest`,不会误命中。 + */ +export function isIngestRelatedSkill(s: { + name?: string; + name_zh?: string | null; + description?: string; +}): boolean { + const hay = `${s.name ?? ""} ${s.name_zh ?? ""} ${s.description ?? ""}`.toLowerCase(); + return hay.includes("ingest") || hay.includes("入库"); +} + +/** + * 是否**挂载了**可用的入库相关技能(存在且启用)。失败回退 false。 + * 为 false 时第三步不显示入库按钮、不触发任何入库操作。 + */ export async function isIngestSkillAvailable(): Promise { try { const skills = await loadSkills(); - return skills.some((s) => s.name === INGEST_SKILL_NAME && s.enabled); + return skills.some((s) => s.enabled && isIngestRelatedSkill(s)); } catch { return false; } diff --git a/frontend-web/src/roundtable-planning/hooks/useStep3Summary.ts b/frontend-web/src/roundtable-planning/hooks/useStep3Summary.ts index 9535d910..c5f2af36 100644 --- a/frontend-web/src/roundtable-planning/hooks/useStep3Summary.ts +++ b/frontend-web/src/roundtable-planning/hooks/useStep3Summary.ts @@ -1253,6 +1253,8 @@ export function useStep3Summary( */ const runIngest = useCallback( async (opts?: { note?: string }) => { + // 未挂载入库技能(或非深链模式)→ 不执行任何入库操作。 + if (!ingestAvailableRef.current) return; setPendingIngestClarification(null); setIngestStatus("running"); const myRun = ++ingestRunRef.current;