139 lines
4.1 KiB
TypeScript
139 lines
4.1 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import {
|
|
CLIENT_SLASH_COMMANDS,
|
|
buildDraftAgentSetup,
|
|
resolveClientSlashCommand,
|
|
} from "@/client-slash-commands";
|
|
import type { Agent } from "@/stores/session-store";
|
|
|
|
function createAgent(overrides: Partial<Agent> = {}): Agent {
|
|
const now = new Date("2026-05-15T00:00:00.000Z");
|
|
return {
|
|
serverId: "server-1",
|
|
id: "agent-1",
|
|
provider: "codex",
|
|
status: "idle",
|
|
createdAt: now,
|
|
updatedAt: now,
|
|
lastUserMessageAt: now,
|
|
lastActivityAt: now,
|
|
capabilities: {
|
|
supportsStreaming: true,
|
|
supportsSessionPersistence: true,
|
|
supportsDynamicModes: true,
|
|
supportsMcpServers: false,
|
|
supportsReasoningStream: false,
|
|
supportsToolInvocations: true,
|
|
},
|
|
currentModeId: "mode-current",
|
|
availableModes: [],
|
|
pendingPermissions: [],
|
|
persistence: null,
|
|
runtimeInfo: {
|
|
provider: "codex",
|
|
sessionId: "session-1",
|
|
model: "runtime-model",
|
|
modeId: "runtime-mode",
|
|
thinkingOptionId: "runtime-thinking",
|
|
},
|
|
title: "Agent",
|
|
cwd: "/repo",
|
|
model: "agent-model",
|
|
thinkingOptionId: "think-hard",
|
|
features: [
|
|
{ type: "toggle", id: "web-search", label: "Web search", value: true },
|
|
{
|
|
type: "select",
|
|
id: "effort",
|
|
label: "Effort",
|
|
value: "high",
|
|
options: [{ id: "high", label: "High" }],
|
|
},
|
|
],
|
|
parentAgentId: null,
|
|
labels: {},
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
describe("resolveClientSlashCommand", () => {
|
|
it("declares the exact canonical client commands with their aliases", () => {
|
|
expect(
|
|
CLIENT_SLASH_COMMANDS.map((command) => [
|
|
command.name,
|
|
[...command.aliases],
|
|
command.execution,
|
|
]),
|
|
).toEqual([
|
|
["exit", ["quit", "q"], "immediate"],
|
|
["clear", ["new"], "immediate"],
|
|
]);
|
|
});
|
|
|
|
it("resolves canonical names and aliases after trimming", () => {
|
|
expect(resolveClientSlashCommand({ text: " /quit ", hasAttachments: false })).toMatchObject({
|
|
name: "exit",
|
|
kind: "archive-agent",
|
|
execution: "immediate",
|
|
});
|
|
expect(resolveClientSlashCommand({ text: "/exit", hasAttachments: false })).toMatchObject({
|
|
name: "exit",
|
|
kind: "archive-agent",
|
|
});
|
|
expect(resolveClientSlashCommand({ text: "/q", hasAttachments: false })).toMatchObject({
|
|
name: "exit",
|
|
kind: "archive-agent",
|
|
});
|
|
expect(resolveClientSlashCommand({ text: "/clear", hasAttachments: false })).toMatchObject({
|
|
name: "clear",
|
|
kind: "replace-agent-with-draft",
|
|
});
|
|
expect(resolveClientSlashCommand({ text: "/new", hasAttachments: false })).toMatchObject({
|
|
name: "clear",
|
|
kind: "replace-agent-with-draft",
|
|
});
|
|
});
|
|
|
|
it("leaves provider commands, arguments, ordinary messages, and attachment submits alone", () => {
|
|
expect(resolveClientSlashCommand({ text: "/clear now", hasAttachments: false })).toBeNull();
|
|
expect(resolveClientSlashCommand({ text: "/quit now", hasAttachments: false })).toBeNull();
|
|
expect(
|
|
resolveClientSlashCommand({ text: "/provider-command", hasAttachments: false }),
|
|
).toBeNull();
|
|
expect(resolveClientSlashCommand({ text: "hello /quit", hasAttachments: false })).toBeNull();
|
|
expect(resolveClientSlashCommand({ text: "/quit", hasAttachments: true })).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe("buildDraftAgentSetup", () => {
|
|
it("builds draft setup from the active agent snapshot", () => {
|
|
expect(buildDraftAgentSetup(createAgent())).toEqual({
|
|
provider: "codex",
|
|
cwd: "/repo",
|
|
modeId: "mode-current",
|
|
model: "agent-model",
|
|
thinkingOptionId: "think-hard",
|
|
featureValues: {
|
|
"web-search": true,
|
|
effort: "high",
|
|
},
|
|
});
|
|
});
|
|
|
|
it("falls back to runtime model setup when top-level fields are absent", () => {
|
|
expect(
|
|
buildDraftAgentSetup(
|
|
createAgent({
|
|
currentModeId: null,
|
|
model: null,
|
|
thinkingOptionId: null,
|
|
}),
|
|
),
|
|
).toMatchObject({
|
|
modeId: "runtime-mode",
|
|
model: "runtime-model",
|
|
thinkingOptionId: "runtime-thinking",
|
|
});
|
|
});
|
|
});
|