fix: use custom event for training panel toggle, no more poll inference
SkillInsertDialog dispatches SKILL_TOGGLED_EVENT on user click. AssistantWorkspace listens for that event to set applied state. Completely eliminates poll-based state inference that caused flash. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -41,6 +41,8 @@ import { ClawSessionReplayProvider } from "@/lib/claw-session-replay";
|
||||
import { pushSessionUrl } from "@/lib/claw-session-url";
|
||||
import { cn } from "@/lib/utils";
|
||||
import {
|
||||
SKILL_TOGGLED_EVENT,
|
||||
type SkillToggledDetail,
|
||||
useAppliedTraining,
|
||||
useModelIterationEnabled,
|
||||
} from "@/lib/use-training-mode";
|
||||
@@ -329,31 +331,17 @@ function AssistantWorkspace() {
|
||||
closeActivityPanel();
|
||||
}, [showPipeline, closeActivityPanel]);
|
||||
|
||||
// Skill 开关联动 applied:只有用户在本次页面会话中「主动点击」开启 skill
|
||||
// 才展开面板。页面加载时 skill 已经是 enabled 的情况不自动展开(避免闪烁)。
|
||||
// 判断依据:skill.loading 从 true→false 是初始加载完成,之后 enabled 变化
|
||||
// 才是用户主动操作。
|
||||
const skillLoadedOnce = useRef(false);
|
||||
const prevSkillEnabled = useRef<boolean | null>(null);
|
||||
// 面板只通过用户在 SkillInsertDialog 里显式点击开/关 model-iteration 来控制。
|
||||
// 监听 SkillInsertDialog 发出的自定义事件,不再从 poll 状态变化推断。
|
||||
useEffect(() => {
|
||||
if (skill.loading) return;
|
||||
if (!skillLoadedOnce.current) {
|
||||
skillLoadedOnce.current = true;
|
||||
prevSkillEnabled.current = skill.enabled;
|
||||
// 初始加载:无条件清除 applied(清 localStorage 残留),面板只从用户点击打开
|
||||
if (applied) {
|
||||
setApplied(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
// 初始加载之后的变化 = 用户主动操作
|
||||
if (skill.enabled && !prevSkillEnabled.current) {
|
||||
setApplied(true);
|
||||
} else if (!skill.enabled && prevSkillEnabled.current) {
|
||||
setApplied(false);
|
||||
}
|
||||
prevSkillEnabled.current = skill.enabled;
|
||||
}, [skill.enabled, skill.loading, applied, setApplied]);
|
||||
const handler = (e: Event) => {
|
||||
const detail = (e as CustomEvent<SkillToggledDetail>).detail;
|
||||
if (detail.skill !== "model-iteration") return;
|
||||
setApplied(detail.enabled);
|
||||
};
|
||||
window.addEventListener(SKILL_TOGGLED_EVENT, handler);
|
||||
return () => window.removeEventListener(SKILL_TOGGLED_EVENT, handler);
|
||||
}, [setApplied]);
|
||||
|
||||
// 注意:用同一棵树 + 条件渲染,保证 <Thread /> 和 <ActivityPanel /> 在
|
||||
// pipeline 切换前后都保持挂载,否则它们会 remount,
|
||||
|
||||
@@ -93,6 +93,7 @@ import {
|
||||
} from "@/lib/claw-active-session";
|
||||
import { useClawSessionReplay } from "@/lib/claw-session-replay";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { dispatchSkillToggled } from "@/lib/use-training-mode";
|
||||
|
||||
type ComposerInsertEvent = CustomEvent<{ text: string }>;
|
||||
|
||||
@@ -1800,6 +1801,7 @@ function SkillInsertDialog() {
|
||||
);
|
||||
}
|
||||
setSkills(payload);
|
||||
dispatchSkillToggled({ skill: skill.name, enabled });
|
||||
setStatus(enabled ? `已启用 ${skill.name}` : `已停用 ${skill.name}`);
|
||||
} catch (err) {
|
||||
setSkills(previous);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
|
||||
export const SESSION_UPDATED_EVENT = "claw-session-updated";
|
||||
export const SKILL_TOGGLED_EVENT = "claw-skill-toggled";
|
||||
const APPLIED_STORAGE_PREFIX = "claw.training.applied:";
|
||||
|
||||
const MODEL_ITERATION_SKILL_NAMES = new Set(["model-iteration"]);
|
||||
@@ -158,6 +159,15 @@ export function dispatchSessionUpdated(detail: SessionUpdatedDetail) {
|
||||
);
|
||||
}
|
||||
|
||||
export type SkillToggledDetail = { skill: string; enabled: boolean };
|
||||
|
||||
export function dispatchSkillToggled(detail: SkillToggledDetail) {
|
||||
if (typeof window === "undefined") return;
|
||||
window.dispatchEvent(
|
||||
new CustomEvent<SkillToggledDetail>(SKILL_TOGGLED_EVENT, { detail }),
|
||||
);
|
||||
}
|
||||
|
||||
export function useTrainingMode(sessionId: string | null) {
|
||||
const [isTraining, setIsTraining] = useState(false);
|
||||
const [loaded, setLoaded] = useState(false);
|
||||
|
||||
Reference in New Issue
Block a user