Files
tutti/packages/agent/gui/agent-gui/agentGuiNode/controller/useAgentGUITuttiModeActivation.spec.tsx
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

269 lines
8.0 KiB
TypeScript

import { act, renderHook } from "@testing-library/react";
import {
createAgentSessionEngine,
normalizeAgentActivitySession,
selectEngineSession,
type EngineExternalCommand
} from "@tutti-os/agent-activity-core";
import { describe, expect, it, vi } from "vitest";
import { createTestEngineCommandPort } from "../../../shared/testing/createTestAgentSessionEngine";
import {
resolveAgentGUITuttiModeDraftKey,
useAgentGUITuttiModeActivation
} from "./useAgentGUITuttiModeActivation";
describe("useAgentGUITuttiModeActivation", () => {
it("stores the home slash choice in the engine-owned draft", () => {
const { engine } = createTestEngine();
const draftKey = resolveAgentGUITuttiModeDraftKey("node-1");
const { result } = renderHook(() =>
useAgentGUITuttiModeActivation({
activeConversationId: null,
draftKey,
engine,
workspaceId: "workspace-1"
})
);
act(() => result.current.setActive(true));
expect(result.current.active).toBe(true);
expect(
engine.getSnapshot().tuttiModeActivation.draftsByKey[draftKey]?.active
).toBe(true);
});
it("stores confirmed home preferences in the engine-owned Tutti draft", () => {
const { engine } = createTestEngine();
const draftKey = resolveAgentGUITuttiModeDraftKey("node-1");
const { result } = renderHook(() =>
useAgentGUITuttiModeActivation({
activeConversationId: null,
draftKey,
engine,
workspaceId: "workspace-1"
})
);
act(() => {
result.current.setEffect(73);
result.current.setSpeed(61);
});
expect(result.current.active).toBe(true);
expect(result.current.effect).toBe(73);
expect(result.current.speed).toBe(61);
expect(
engine.getSnapshot().tuttiModeActivation.draftsByKey[draftKey]
).toMatchObject({
active: true,
effect: 73,
speed: 61
});
});
it("updates an existing session through the engine command while preserving Plan", () => {
const { commands, engine } = createTestEngine();
engine.dispatch({
session: normalizeAgentActivitySession({
activeTurnId: null,
agentSessionId: "session-1",
cwd: "/workspace",
latestTurnInteractions: [],
pendingInteractions: [],
provider: "codex",
settings: { planMode: true },
title: "Session",
tuttiModeActivation: null,
updatedAtUnixMs: 1,
workspaceId: "workspace-1"
}),
type: "session/upserted"
});
const { result } = renderHook(() =>
useAgentGUITuttiModeActivation({
activeConversationId: "session-1",
draftKey: resolveAgentGUITuttiModeDraftKey("node-1"),
engine,
workspaceId: "workspace-1"
})
);
act(() => result.current.setActive(true));
expect(result.current.active).toBe(true);
expect(result.current.updatePending).toBe(true);
expect(commands).toHaveLength(1);
expect(commands[0]).toMatchObject({
agentSessionId: "session-1",
source: "slash_command",
status: "active",
type: "tuttiMode/update",
workspaceId: "workspace-1"
});
expect(
selectEngineSession(engine.getSnapshot(), "session-1")?.settings.planMode
).toBe(true);
});
it("surfaces a failed update and retries the original activation intent", () => {
const { commands, engine } = createTestEngine();
engine.dispatch({
session: normalizeAgentActivitySession({
activeTurnId: null,
agentSessionId: "session-1",
cwd: "/workspace",
latestTurnInteractions: [],
pendingInteractions: [],
provider: "codex",
settings: {},
title: "Session",
tuttiModeActivation: null,
updatedAtUnixMs: 1,
workspaceId: "workspace-1"
}),
type: "session/upserted"
});
const { result } = renderHook(() =>
useAgentGUITuttiModeActivation({
activeConversationId: "session-1",
draftKey: resolveAgentGUITuttiModeDraftKey("node-1"),
engine,
workspaceId: "workspace-1"
})
);
act(() => result.current.setActive(true));
const firstCommand = commands[0];
expect(firstCommand?.type).toBe("tuttiMode/update");
if (!firstCommand || firstCommand.type !== "tuttiMode/update") {
throw new Error("expected Tutti mode update command");
}
act(() => {
engine.dispatch({
commandId: firstCommand.commandId,
commandType: "tuttiMode/update",
errorCode: "transport_failed",
errorMessage: "network unavailable",
outcome: "failed",
type: "engine/commandResult"
});
});
expect(result.current.active).toBe(false);
expect(result.current.updateStatus).toBe("failed");
expect(result.current.errorMessage).toBe("network unavailable");
act(() => result.current.retry());
expect(commands).toHaveLength(2);
expect(commands[1]).toMatchObject({
source: "slash_command",
status: "active",
type: "tuttiMode/update"
});
});
it("unblocks retry when the update's owned reconcile fails", () => {
const { commands, engine } = createTestEngine();
engine.dispatch({
session: normalizeAgentActivitySession({
activeTurnId: null,
agentSessionId: "session-1",
cwd: "/workspace",
latestTurnInteractions: [],
pendingInteractions: [],
provider: "codex",
settings: {},
title: "Session",
tuttiModeActivation: {
agentSessionId: "session-1",
createdAtUnixMs: 1,
currentRevision: {
activationId: "activation-1",
createdAtUnixMs: 1,
effect: 50,
orchestrationIntensity: 50,
speed: 50,
revision: 1,
source: "slash_command",
status: "active"
},
id: "activation-1",
status: "active",
updatedAtUnixMs: 1,
workspaceId: "workspace-1"
},
updatedAtUnixMs: 1,
workspaceId: "workspace-1"
}),
type: "session/upserted"
});
const { result } = renderHook(() =>
useAgentGUITuttiModeActivation({
activeConversationId: "session-1",
draftKey: resolveAgentGUITuttiModeDraftKey("node-1"),
engine,
workspaceId: "workspace-1"
})
);
act(() => result.current.setActive(false));
const update = commands[0];
if (!update || update.type !== "tuttiMode/update") {
throw new Error("expected Tutti mode update command");
}
act(() => {
engine.dispatch({
commandId: update.commandId,
commandType: "tuttiMode/update",
outcome: "timedOut",
type: "engine/commandResult"
});
});
expect(result.current.updateStatus).toBe("uncertain");
expect(result.current.updatePending).toBe(true);
const reconcile = commands[1];
if (!reconcile || reconcile.type !== "session/reconcile") {
throw new Error("expected owned session reconcile command");
}
act(() => {
engine.dispatch({
commandId: reconcile.commandId,
commandType: "session/reconcile",
errorMessage: "reconcile failed",
outcome: "failed",
type: "engine/commandResult"
});
});
expect(result.current.updateStatus).toBe("failed");
expect(result.current.updatePending).toBe(false);
expect(result.current.active).toBe(true);
act(() => result.current.retry());
expect(commands[2]).toMatchObject({
source: "badge_remove",
status: "inactive",
type: "tuttiMode/update"
});
});
});
function createTestEngine() {
const commands: EngineExternalCommand[] = [];
const execute = vi.fn((command: EngineExternalCommand) => {
commands.push(command);
return new Promise<never>(() => {});
});
const engine = createAgentSessionEngine({
clock: { nowUnixMs: () => 1 },
commandPort: createTestEngineCommandPort({ execute }),
identity: { origin: "test", workspaceId: "workspace-1" },
scheduler: { schedule: () => ({ cancel() {} }) }
});
return { commands, engine };
}