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

248 lines
7.7 KiB
TypeScript

import { act, renderHook } from "@testing-library/react";
import {
createAgentSessionEngine,
normalizeAgentActivitySession,
selectEngineSessionSettingsUpdate
} from "@tutti-os/agent-activity-core";
import { describe, expect, it, vi } from "vitest";
import { createTestEngineCommandPort } from "../../../shared/testing/createTestAgentSessionEngine";
import { useAgentGUISessionEngineState } from "./useAgentGUISessionEngineState";
describe("useAgentGUISessionEngineState", () => {
it("shows an optimistic session selection then silently restores canonical settings on failure", () => {
const sessionEngine = createAgentSessionEngine({
clock: { nowUnixMs: () => 1 },
commandPort: createTestEngineCommandPort({
execute: vi.fn(() => new Promise(() => undefined))
}),
identity: { origin: "test", workspaceId: "workspace-1" },
scheduler: { schedule: () => ({ cancel() {} }) }
});
sessionEngine.dispatch({
type: "session/snapshotReceived",
sessions: [
normalizeAgentActivitySession({
activeTurnId: null,
agentSessionId: "session-1",
agentTargetId: "local:opencode",
cwd: "/workspace",
latestTurnInteractions: [],
pendingInteractions: [],
provider: "opencode",
settings: { permissionModeId: "ask" },
title: "Session 1",
workspaceId: "workspace-1"
})
]
});
const rendered = renderHook(() =>
useAgentGUISessionEngineState({
activeConversationId: "session-1",
sessionEngine
})
);
act(() => {
sessionEngine.dispatch({
agentSessionId: "session-1",
commandId: "settings-1",
settings: { permissionModeId: "full-access" },
type: "session/settingsUpdateRequested",
workspaceId: "workspace-1"
});
});
expect(
rendered.result.current.activeCanonicalComposerSettings.permissionModeId
).toBe("full-access");
act(() => {
sessionEngine.dispatch({
commandId: "settings-1",
commandType: "session/updateSettings",
correlationId: "session-1",
errorCode: "settings_require_new_session",
errorMessage: "requires a new session",
outcome: "failed",
type: "engine/commandResult"
});
});
expect(
rendered.result.current.activeCanonicalComposerSettings.permissionModeId
).toBe("ask");
expect(rendered.result.current.activeEngineError).toBeNull();
});
it("keeps the latest queued settings visible while the session runtime reconnects", () => {
const sessionEngine = createAgentSessionEngine({
clock: { nowUnixMs: () => 1 },
commandPort: createTestEngineCommandPort({
execute: vi.fn(() => new Promise(() => undefined))
}),
identity: { origin: "test", workspaceId: "workspace-1" },
scheduler: { schedule: () => ({ cancel() {} }) }
});
const session = (settings: { model: string; planMode: boolean }) =>
normalizeAgentActivitySession({
activeTurnId: null,
agentSessionId: "session-1",
cwd: "/workspace",
latestTurnInteractions: [],
pendingInteractions: [],
provider: "codex",
settings,
title: "Session 1",
workspaceId: "workspace-1"
});
sessionEngine.dispatch({
type: "session/snapshotReceived",
sessions: [session({ model: "model-canonical", planMode: false })]
});
const rendered = renderHook(() =>
useAgentGUISessionEngineState({
activeConversationId: "session-1",
sessionEngine
})
);
act(() => {
sessionEngine.dispatch({
agentSessionId: "session-1",
commandId: "settings-1",
settings: { model: "model-first" },
type: "session/settingsUpdateRequested",
workspaceId: "workspace-1"
});
sessionEngine.dispatch({
agentSessionId: "session-1",
commandId: "settings-2",
settings: { model: "model-latest", planMode: true },
type: "session/settingsUpdateRequested",
workspaceId: "workspace-1"
});
sessionEngine.dispatch({
type: "session/runtimeAvailabilityChanged",
agentSessionId: "session-1",
availability: {
state: "blocked",
reason: "transport_reconnecting"
}
});
sessionEngine.dispatch({
commandId: "settings-1",
commandType: "session/updateSettings",
correlationId: "session-1",
outcome: "succeeded",
type: "engine/commandResult",
value: {
agentSessionId: "session-1",
session: session({ model: "model-first", planMode: false })
}
});
});
expect(
selectEngineSessionSettingsUpdate(
sessionEngine.getSnapshot(),
"session-1"
)?.status
).toBe("waitingForRuntime");
expect(
rendered.result.current.activeCanonicalComposerSettings
).toMatchObject({ model: "model-latest", planMode: true });
act(() => {
sessionEngine.dispatch({
type: "session/runtimeAvailabilityChanged",
agentSessionId: "session-1",
availability: { state: "available" }
});
});
expect(
selectEngineSessionSettingsUpdate(
sessionEngine.getSnapshot(),
"session-1"
)?.status
).toBe("inFlight");
expect(
rendered.result.current.activeCanonicalComposerSettings
).toMatchObject({ model: "model-latest", planMode: true });
act(() => {
sessionEngine.dispatch({
commandId: "settings-2",
commandType: "session/updateSettings",
correlationId: "session-1",
outcome: "succeeded",
type: "engine/commandResult",
value: {
agentSessionId: "session-1",
session: session({ model: "model-latest", planMode: true })
}
});
});
expect(
selectEngineSessionSettingsUpdate(
sessionEngine.getSnapshot(),
"session-1"
)?.status
).toBe("idle");
expect(
rendered.result.current.activeCanonicalComposerSettings
).toMatchObject({ model: "model-latest", planMode: true });
});
it("observes runtime availability for the selected session only", () => {
const sessionEngine = createAgentSessionEngine({
clock: { nowUnixMs: () => 1 },
commandPort: createTestEngineCommandPort({
execute: vi.fn(() => new Promise(() => undefined))
}),
identity: { origin: "test", workspaceId: "workspace-1" },
scheduler: { schedule: () => ({ cancel() {} }) }
});
sessionEngine.dispatch({
type: "session/snapshotReceived",
sessions: ["session-1", "session-2"].map((agentSessionId) =>
normalizeAgentActivitySession({
activeTurnId: null,
agentSessionId,
cwd: "/workspace",
latestTurnInteractions: [],
pendingInteractions: [],
provider: "codex",
title: "Session 1",
workspaceId: "workspace-1"
})
)
});
const rendered = renderHook(
({ activeConversationId }) =>
useAgentGUISessionEngineState({
activeConversationId,
sessionEngine
}),
{ initialProps: { activeConversationId: "session-1" } }
);
act(() => {
sessionEngine.dispatch({
type: "session/runtimeAvailabilityChanged",
agentSessionId: "session-1",
availability: {
state: "blocked",
reason: "transport_reconnecting"
}
});
});
expect(rendered.result.current.activeEngineRuntimeAvailability).toEqual({
state: "blocked",
reason: "transport_reconnecting"
});
rendered.rerender({ activeConversationId: "session-2" });
expect(rendered.result.current.activeEngineRuntimeAvailability).toEqual({
state: "available"
});
});
});