

























@@ -160,6 +160,35 @@ function createSessionBindingCapabilities() {
160160};
161161}
162162163+type FocusTargetSessionParams = {
164+requesterKey?: string;
165+};
166+167+type SessionBindingBindInput = {
168+placement: "current" | "child";
169+targetKind: "session" | "agent";
170+targetSessionKey: string;
171+conversation: {
172+channel: string;
173+accountId: string;
174+conversationId: string;
175+parentConversationId?: string;
176+};
177+metadata?: Record<string, unknown>;
178+};
179+180+function firstFocusTargetSessionParams(): FocusTargetSessionParams {
181+const firstCall = hoisted.resolveFocusTargetSessionMock.mock.calls[0];
182+expect(firstCall).toBeDefined();
183+return firstCall[0] as FocusTargetSessionParams;
184+}
185+186+function firstSessionBindingBindInput(): SessionBindingBindInput {
187+const firstCall = hoisted.sessionBindingBindMock.mock.calls[0];
188+expect(firstCall).toBeDefined();
189+return firstCall[0] as SessionBindingBindInput;
190+}
191+163192function buildCommandParams(params?: {
164193cfg?: OpenClawConfig;
165194chatType?: string;
@@ -289,22 +318,13 @@ describe("focus actions", () => {
289318290319expect(result.reply?.text).toContain("bound this conversation");
291320expect(result.reply?.text).toContain("(acp)");
292-expect(hoisted.resolveFocusTargetSessionMock).toHaveBeenCalledWith(
293-expect.objectContaining({
294-requesterKey: "agent:main:main",
295-}),
296-);
297-expect(hoisted.sessionBindingBindMock).toHaveBeenCalledWith(
298-expect.objectContaining({
299-placement: "current",
300-targetKind: "session",
301-targetSessionKey: "agent:codex-acp:session-1",
302-conversation: expect.objectContaining({
303-channel: THREAD_CHANNEL,
304-conversationId: "thread-1",
305-}),
306-}),
307-);
321+expect(firstFocusTargetSessionParams().requesterKey).toBe("agent:main:main");
322+const bindInput = firstSessionBindingBindInput();
323+expect(bindInput.placement).toBe("current");
324+expect(bindInput.targetKind).toBe("session");
325+expect(bindInput.targetSessionKey).toBe("agent:codex-acp:session-1");
326+expect(bindInput.conversation.channel).toBe(THREAD_CHANNEL);
327+expect(bindInput.conversation.conversationId).toBe("thread-1");
308328});
309329310330it("rejects /focus from a leaf subagent", async () => {
@@ -342,15 +362,10 @@ describe("focus actions", () => {
342362const result = await handleSubagentsFocusAction(buildFocusContext());
343363344364expect(result.reply?.text).toContain("bound this conversation");
345-expect(hoisted.sessionBindingBindMock).toHaveBeenCalledWith(
346-expect.objectContaining({
347-placement: "current",
348-conversation: expect.objectContaining({
349-channel: TOPIC_CHANNEL,
350-conversationId: "-100200300:topic:77",
351-}),
352-}),
353-);
365+const bindInput = firstSessionBindingBindInput();
366+expect(bindInput.placement).toBe("current");
367+expect(bindInput.conversation.channel).toBe(TOPIC_CHANNEL);
368+expect(bindInput.conversation.conversationId).toBe("-100200300:topic:77");
354369});
355370356371it("creates a room-chat child thread from a top-level room when spawning is enabled", async () => {
@@ -377,15 +392,10 @@ describe("focus actions", () => {
377392);
378393379394expect(result.reply?.text).toContain("created child conversation thread-created and bound it");
380-expect(hoisted.sessionBindingBindMock).toHaveBeenCalledWith(
381-expect.objectContaining({
382-placement: "child",
383-conversation: expect.objectContaining({
384-channel: ROOM_CHANNEL,
385-conversationId: "!room:example.org",
386-}),
387-}),
388-);
395+const bindInput = firstSessionBindingBindInput();
396+expect(bindInput.placement).toBe("child");
397+expect(bindInput.conversation.channel).toBe(ROOM_CHANNEL);
398+expect(bindInput.conversation.conversationId).toBe("!room:example.org");
389399});
390400391401it("treats a room thread turn as the current thread", async () => {
@@ -400,16 +410,11 @@ describe("focus actions", () => {
400410const result = await handleSubagentsFocusAction(buildFocusContext());
401411402412expect(result.reply?.text).toContain("bound this conversation");
403-expect(hoisted.sessionBindingBindMock).toHaveBeenCalledWith(
404-expect.objectContaining({
405-placement: "current",
406-conversation: expect.objectContaining({
407-channel: ROOM_CHANNEL,
408-conversationId: "$root",
409-parentConversationId: "!room:example.org",
410-}),
411-}),
412-);
413+const bindInput = firstSessionBindingBindInput();
414+expect(bindInput.placement).toBe("current");
415+expect(bindInput.conversation.channel).toBe(ROOM_CHANNEL);
416+expect(bindInput.conversation.conversationId).toBe("$root");
417+expect(bindInput.conversation.parentConversationId).toBe("!room:example.org");
413418});
414419415420it("rejects room top-level thread creation when spawnSessions is disabled", async () => {
@@ -460,27 +465,11 @@ describe("focus actions", () => {
460465461466await handleSubagentsFocusAction(buildFocusContext());
462467463-expect(hoisted.sessionBindingBindMock).toHaveBeenCalledWith(
464-expect.objectContaining({
465-metadata: expect.objectContaining({
466-introText: expect.stringContaining("agent session id: codex-123"),
467-}),
468-}),
469-);
470-expect(hoisted.sessionBindingBindMock).toHaveBeenCalledWith(
471-expect.objectContaining({
472-metadata: expect.objectContaining({
473-introText: expect.stringContaining("acpx session id: acpx-456"),
474-}),
475-}),
476-);
477-expect(hoisted.sessionBindingBindMock).toHaveBeenCalledWith(
478-expect.objectContaining({
479-metadata: expect.objectContaining({
480-introText: expect.stringContaining("codex resume codex-123"),
481-}),
482-}),
483-);
468+const introText = firstSessionBindingBindInput().metadata?.introText;
469+expect(typeof introText).toBe("string");
470+expect(introText).toContain("agent session id: codex-123");
471+expect(introText).toContain("acpx session id: acpx-456");
472+expect(introText).toContain("codex resume codex-123");
484473});
485474486475it("rejects rebinding when another user owns the thread", async () => {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。