Files
tutti/packages/agent/gui/agent-gui/agentGuiNode/view/agentGUIDetailModelHelpers.spec.ts
agent-radar 2ed3415fb7
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
2026-09-01 20:17:27 +08:00

305 lines
8.5 KiB
TypeScript

import { describe, expect, it } from "vitest";
import {
buildAgentConversationHandoffPrompt,
handoffProjectPathForConversation,
isAgentGUIHomeStatusNoticeVisible,
resolveAgentGUITuttiStopTargets,
resolveAgentGUIInteractionDisabledReason,
resolveAgentGUIHomeNoticeChrome,
resolveAgentGUIStopControl,
shouldShowAgentGUIStopButton
} from "./agentGUIDetailModelHelpers.ts";
describe("buildAgentConversationHandoffPrompt", () => {
it("delegates the active conversation to the canonical session handoff draft", () => {
expect(
buildAgentConversationHandoffPrompt({
activeConversation: {
id: "session-1",
agentTargetId: "local:claude-code",
provider: "claude-code",
title: "Session 1",
titleFallback: null,
status: "completed",
cwd: "/workspace/project-a",
updatedAtUnixMs: 1
},
currentUserId: "user-1",
labels: { untitledConversationTitle: "Untitled conversation" },
selectedAgentTarget: {
targetId: "local:claude-code",
agentTargetId: "local:claude-code",
label: "Claude Code",
provider: "claude-code",
ref: {
kind: "agent-directory",
provider: "claude-code",
agentTargetId: "local:claude-code"
}
},
uiLanguage: "en",
workspaceId: "room-1"
})
).toBe(
"[@Session 1](mention://agent-session/session-1?agentTargetId=local%3Aclaude-code&workspaceId=room-1) "
);
});
});
describe("shouldShowAgentGUIStopButton", () => {
const idle = {
hasPendingApproval: false,
hasPendingInteractivePrompt: false,
isAuthBlocked: false,
isCancelPending: false,
isConversationBusy: false,
isCreatingConversation: false,
hasPendingSubmitStopTarget: false,
isInterrupting: false,
isSubmitting: false,
isUnavailable: false
};
it("allows immediate stop while a new conversation is still activating", () => {
expect(
shouldShowAgentGUIStopButton({
...idle,
isCreatingConversation: true,
isSubmitting: true
})
).toBe(true);
});
it("keeps ordinary submission races hidden when there is no stoppable work", () => {
expect(shouldShowAgentGUIStopButton({ ...idle, isSubmitting: true })).toBe(
false
);
});
it("shows Stop when Activity Core has an exact pending-submit target", () => {
expect(
shouldShowAgentGUIStopButton({
...idle,
hasPendingSubmitStopTarget: true,
isSubmitting: true
})
).toBe(true);
});
it("keeps authentication and availability gates authoritative", () => {
expect(
shouldShowAgentGUIStopButton({
...idle,
isAuthBlocked: true,
isCreatingConversation: true
})
).toBe(false);
});
});
describe("resolveAgentGUIInteractionDisabledReason", () => {
it("uses the approval reason for approval prompts", () => {
expect(
resolveAgentGUIInteractionDisabledReason({
promptKind: "approval",
approvalReason: "The shared Agent owner is offline",
interactivePromptReason: "The shared Agent caller is offline"
})
).toBe("The shared Agent owner is offline");
});
it("uses the interactive prompt reason for non-approval prompts", () => {
expect(
resolveAgentGUIInteractionDisabledReason({
promptKind: "ask-user",
approvalReason: "The shared Agent owner is offline",
interactivePromptReason: "The shared Agent caller is offline"
})
).toBe("The shared Agent caller is offline");
});
it("does not expose a reason when there is no active prompt", () => {
expect(
resolveAgentGUIInteractionDisabledReason({
promptKind: null,
approvalReason: "The shared Agent owner is offline",
interactivePromptReason: "The shared Agent caller is offline"
})
).toBeNull();
});
});
describe("resolveAgentGUITuttiStopTargets", () => {
it("stops only the Issue cascade when aggregate work outlives the source Turn", () => {
expect(
resolveAgentGUITuttiStopTargets({
executionActive: true,
sourceHasStoppableWork: false
})
).toEqual({ stopExecution: true, stopSession: false });
});
it("stops both the Issue cascade and a live source Turn", () => {
expect(
resolveAgentGUITuttiStopTargets({
executionActive: true,
sourceHasStoppableWork: true
})
).toEqual({ stopExecution: true, stopSession: true });
});
it("preserves ordinary Session stop outside Tutti execution", () => {
expect(
resolveAgentGUITuttiStopTargets({
executionActive: false,
sourceHasStoppableWork: false
})
).toEqual({ stopExecution: false, stopSession: true });
});
});
describe("Home status presentation", () => {
it.each([
"agent-sharing-revoked",
"transport-connecting",
"transport-unavailable"
] as const)(
"gives %s recovery chrome priority over other bottom-dock notices",
(kind) => {
expect(
isAgentGUIHomeStatusNoticeVisible({
kind,
message: "Connection unavailable",
canRetry: false
})
).toBe(true);
}
);
it("does not hide existing chrome while reconnecting is still delayed", () => {
expect(isAgentGUIHomeStatusNoticeVisible(null)).toBe(false);
expect(
isAgentGUIHomeStatusNoticeVisible({
kind: "failed",
message: "Existing failure",
canRetry: false
})
).toBe(false);
});
it.each(["transport-connecting", "transport-unavailable"] as const)(
"keeps the pending prompt visible for interaction-scoped %s chrome",
(kind) => {
expect(
isAgentGUIHomeStatusNoticeVisible({
kind,
message: "Connection unavailable",
canRetry: false,
interactionScoped: true
})
).toBe(false);
}
);
it("projects target connection chrome onto the empty Home composer", () => {
const inlineNoticeChrome = {
auth: null,
approval: null,
recovery: {
kind: "failed" as const,
message: "Existing failure"
},
rawState: null
};
const sessionChrome = {
auth: null,
approval: null,
recovery: {
kind: "transport-connecting" as const,
message: "Connecting to device..."
},
rawState: null
};
expect(
resolveAgentGUIHomeNoticeChrome({
inlineNoticeChrome,
sessionChrome
})
).toBe(sessionChrome);
});
it("keeps ordinary Home notices when target connection chrome is absent", () => {
const inlineNoticeChrome = {
auth: null,
approval: null,
recovery: {
kind: "failed" as const,
message: "Existing failure"
},
rawState: null
};
expect(
resolveAgentGUIHomeNoticeChrome({
inlineNoticeChrome,
sessionChrome: {
auth: null,
approval: null,
recovery: null,
rawState: null
}
})
).toBe(inlineNoticeChrome);
});
it("keeps Stop actionable while submission commands are blocked", () => {
expect(
resolveAgentGUIStopControl({
hasPendingApproval: false,
hasPendingInteractivePrompt: false,
isAuthBlocked: false,
isCancelPending: false,
isConversationBusy: true,
isCreatingConversation: false,
hasPendingSubmitStopTarget: false,
isInterrupting: false,
isSubmitting: false,
isUnavailable: false
})
).toEqual({ disabled: false, visible: true });
});
});
describe("handoffProjectPathForConversation", () => {
it("keeps the canonical project path for the destination session", () => {
expect(
handoffProjectPathForConversation({
cwd: "/workspace/fallback",
project: { path: " /workspace/project-a " },
railSectionKey: "project:/workspace/project-a"
} as never)
).toBe("/workspace/project-a");
});
it("falls back to the source cwd when project metadata is unavailable", () => {
expect(
handoffProjectPathForConversation({
cwd: " /workspace/project-b ",
project: null,
railSectionKey: "project:/workspace/project-b"
} as never)
).toBe("/workspace/project-b");
});
it("omits the cwd when the source belongs to conversations", () => {
expect(
handoffProjectPathForConversation({
cwd: " /workspace/conversation ",
project: { path: " /workspace/stale-project " },
railSectionKey: " conversations "
} as never)
).toBeNull();
});
});