feat(roundtable): 入库门控——未挂载入库技能则不显示入库按钮、也不执行入库

- 门控改为「是否挂载了入库相关技能」:按 name/name_zh/description 含 `ingest` 或「入库」
  识别任意启用的入库相关技能,不写死示例技能名(真实入库技能改名也能自动识别;
  知识库检索类技能不误命中)。
- 操作层加保险:runIngest 在 ingestAvailableRef 为假时直接 no-op,未挂载技能/非深链
  即使被触发也不执行任何入库动作。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
fengxiangdebaoziandClaude Opus 4.8 committed 2026-06-18 17:05:53 +08:00
1 parent 19028ba627
commit 85cca36ddb
2 files changed
+22 -3

No files matched your search

@@ -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<boolean> {
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;
}
@@ -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;