fix(agent): 抽屉开着时路由变化,新对话的上下文跟着页面换
浏览器前进后退或会话里的链接换了页面,抽屉里新对话仍挂着上一页的对象。 按路由推断的上下文随页面更新;页面按钮带进来的上下文、正在看的会话不动。 Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Cxwgnn2pbzQ7rXv3rq7fei
This commit is contained in:
1 parent
a87c2c19c4
commit
bbd7459935
3 files changed
+57
-1
No files matched your search
@@ -28,6 +28,7 @@ import {
|
||||
setAgentDrawerOpen,
|
||||
shortGoalTitle,
|
||||
showAgentRunInDrawer,
|
||||
syncAgentContextToPath,
|
||||
takeReturnFocus,
|
||||
toggleAgentDrawer,
|
||||
useAgentDrawer,
|
||||
@@ -104,6 +105,7 @@ export function AgentDrawer() {
|
||||
const content = useRef<HTMLDivElement>(null);
|
||||
// 记下最近的非智能体页面:会话页「在侧边打开」回到这里
|
||||
useEffect(() => noteAgentReturnPath(pathname, search), [pathname, search]);
|
||||
useEffect(() => syncAgentContextToPath(pathname), [pathname]);
|
||||
const name = useContextName(context);
|
||||
const mock = agentMockEnabled();
|
||||
// 目标前缀带名称和 ID:名称给人看,ID 给模型用
|
||||
|
||||
@@ -17,7 +17,19 @@ import {
|
||||
writeDraft,
|
||||
} from "./agent-nav.ts";
|
||||
import { CompactPager } from "./agent-session-list.tsx";
|
||||
import { agentReturnPath, isAgentPage, noteAgentReturnPath, outletKey, toggleAction } from "./agent-store.ts";
|
||||
import {
|
||||
agentReturnPath,
|
||||
clearAgentContext,
|
||||
isAgentPage,
|
||||
noteAgentReturnPath,
|
||||
openAgentDrawer,
|
||||
outletKey,
|
||||
setAgentDrawerOpen,
|
||||
showAgentRunInDrawer,
|
||||
syncAgentContextToPath,
|
||||
toggleAction,
|
||||
useAgentDrawer,
|
||||
} from "./agent-store.ts";
|
||||
import { cachedRunEvents, cacheRunEvents } from "./use-agent-stream.ts";
|
||||
|
||||
// 智能体页面切换的状态逻辑:整页重挂载 key、分栏与 URL、草稿、滚动策略、快捷键在智能体页面的行为。
|
||||
@@ -176,3 +188,33 @@ describe("会话页「在侧边打开」回到之前的页面", () => {
|
||||
expect(agentReturnPath()).toBe("/console/sites");
|
||||
});
|
||||
});
|
||||
|
||||
describe("抽屉开着时路由变化", () => {
|
||||
// useAgentDrawer 是 useSyncExternalStore,测试里直接读快照
|
||||
const snapshot = () => {
|
||||
let out: ReturnType<typeof useAgentDrawer> | null = null;
|
||||
const Probe = () => {
|
||||
out = useAgentDrawer();
|
||||
return null;
|
||||
};
|
||||
renderToStaticMarkup(createElement(Probe));
|
||||
return out as unknown as ReturnType<typeof useAgentDrawer>;
|
||||
};
|
||||
it("新对话的路由上下文跟着页面换", () => {
|
||||
openAgentDrawer({ label: "作品 aaaa", entityId: "aaaa", fromPath: true });
|
||||
syncAgentContextToPath("/console/sites/hdh");
|
||||
expect(snapshot().context).toMatchObject({ siteId: "hdh", fromPath: true });
|
||||
syncAgentContextToPath("/console/home");
|
||||
expect(snapshot().context).toBeNull();
|
||||
});
|
||||
it("页面按钮带的上下文、正在看的会话、抽屉关着时不动", () => {
|
||||
openAgentDrawer({ label: "作品:沙丘", entityId: "e1" });
|
||||
syncAgentContextToPath("/console/sites/hdh");
|
||||
expect(snapshot().context).toMatchObject({ entityId: "e1" });
|
||||
clearAgentContext();
|
||||
showAgentRunInDrawer("r1");
|
||||
syncAgentContextToPath("/console/sites/hdh");
|
||||
expect(snapshot().context).toBeNull();
|
||||
setAgentDrawerOpen(false);
|
||||
});
|
||||
});
|
||||
@@ -84,6 +84,18 @@ export function newAgentConversation() {
|
||||
emit();
|
||||
}
|
||||
|
||||
/**
|
||||
* 抽屉开着时路由变了(浏览器前进后退、会话里的链接):还在新对话、上下文是按路由推断的,就换成新页面的对象;
|
||||
* 页面按钮带进来的上下文、已经在看的会话不动。
|
||||
*/
|
||||
export function syncAgentContextToPath(pathname: string) {
|
||||
if (!state.open || state.runId || (state.context && !state.context.fromPath)) return;
|
||||
const next = contextFromPath(pathname);
|
||||
if (JSON.stringify(next) === JSON.stringify(state.context)) return;
|
||||
state = { ...state, context: next };
|
||||
emit();
|
||||
}
|
||||
|
||||
/** 去掉上下文(输入框上的名称标签 ×) */
|
||||
export function clearAgentContext() {
|
||||
state = { ...state, context: null };
|
||||
|
||||
Reference in new issue
Block a user