First Release of Claw3D (#11)
Co-authored-by: iamlukethedev <iamlukethedev@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,218 @@
|
||||
import { createElement } from "react";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import { cleanup, fireEvent, render, screen, waitFor } from "@testing-library/react";
|
||||
|
||||
import type { AgentState } from "@/features/agents/state/store";
|
||||
import { AgentBrainPanel } from "@/features/agents/components/AgentInspectPanels";
|
||||
import type { GatewayClient } from "@/lib/gateway/GatewayClient";
|
||||
|
||||
const createAgent = (agentId: string, name: string, sessionKey: string): AgentState => ({
|
||||
agentId,
|
||||
name,
|
||||
sessionKey,
|
||||
status: "idle",
|
||||
sessionCreated: true,
|
||||
awaitingUserInput: false,
|
||||
hasUnseenActivity: false,
|
||||
outputLines: [],
|
||||
lastResult: null,
|
||||
lastDiff: null,
|
||||
runId: null,
|
||||
runStartedAt: null,
|
||||
streamText: null,
|
||||
thinkingTrace: null,
|
||||
latestOverride: null,
|
||||
latestOverrideKind: null,
|
||||
lastAssistantMessageAt: null,
|
||||
lastActivityAt: null,
|
||||
latestPreview: null,
|
||||
lastUserMessage: null,
|
||||
draft: "",
|
||||
sessionSettingsSynced: true,
|
||||
historyLoadedAt: null,
|
||||
historyFetchLimit: null,
|
||||
historyFetchedCount: null,
|
||||
historyMaybeTruncated: false,
|
||||
toolCallingEnabled: true,
|
||||
showThinkingTraces: true,
|
||||
model: null,
|
||||
thinkingLevel: null,
|
||||
avatarSeed: `seed-${agentId}`,
|
||||
avatarUrl: null,
|
||||
});
|
||||
|
||||
const createMockClient = () => {
|
||||
const filesByAgent: Record<string, Record<string, string>> = {
|
||||
"agent-1": {
|
||||
"AGENTS.md": "alpha agents",
|
||||
"SOUL.md": "# SOUL.md - Who You Are\n\n## Core Truths\n\nBe useful.",
|
||||
"IDENTITY.md": "# IDENTITY.md - Who Am I?\n\n- Name: Alpha\n- Creature: droid\n- Vibe: calm\n- Emoji: 🤖\n",
|
||||
"USER.md": "# USER.md - About Your Human\n\n- Name: George\n- What to call them: GP\n\n## Context\n\nBuilding Claw3D.",
|
||||
"TOOLS.md": "tool notes",
|
||||
"HEARTBEAT.md": "heartbeat notes",
|
||||
"MEMORY.md": "durable memory",
|
||||
},
|
||||
"agent-2": {
|
||||
"AGENTS.md": "beta agents",
|
||||
},
|
||||
};
|
||||
|
||||
const calls: Array<{ method: string; params: unknown }> = [];
|
||||
|
||||
const client = {
|
||||
call: vi.fn(async (method: string, params: unknown) => {
|
||||
calls.push({ method, params });
|
||||
if (method === "agents.files.get") {
|
||||
const record = params && typeof params === "object" ? (params as Record<string, unknown>) : {};
|
||||
const agentId = typeof record.agentId === "string" ? record.agentId : "";
|
||||
const name = typeof record.name === "string" ? record.name : "";
|
||||
const content = filesByAgent[agentId]?.[name];
|
||||
if (typeof content !== "string") {
|
||||
return { file: { name, missing: true } };
|
||||
}
|
||||
return { file: { name, missing: false, content } };
|
||||
}
|
||||
if (method === "agents.files.set") {
|
||||
const record = params && typeof params === "object" ? (params as Record<string, unknown>) : {};
|
||||
const agentId = typeof record.agentId === "string" ? record.agentId : "";
|
||||
const name = typeof record.name === "string" ? record.name : "";
|
||||
const content = typeof record.content === "string" ? record.content : "";
|
||||
if (!filesByAgent[agentId]) {
|
||||
filesByAgent[agentId] = {};
|
||||
}
|
||||
filesByAgent[agentId][name] = content;
|
||||
return { ok: true };
|
||||
}
|
||||
return {};
|
||||
}),
|
||||
} as unknown as GatewayClient;
|
||||
|
||||
return { client, calls, filesByAgent };
|
||||
};
|
||||
|
||||
describe("AgentBrainPanel", () => {
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
});
|
||||
|
||||
it("renders_behavior_sections_and_loads_agent_files", async () => {
|
||||
const { client } = createMockClient();
|
||||
const agents = [
|
||||
createAgent("agent-1", "Alpha", "session-1"),
|
||||
createAgent("agent-2", "Beta", "session-2"),
|
||||
];
|
||||
|
||||
render(
|
||||
createElement(AgentBrainPanel, {
|
||||
client,
|
||||
agents,
|
||||
selectedAgentId: "agent-1",
|
||||
})
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole("heading", { name: "Persona" })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
expect(screen.getByRole("heading", { name: "Directives" })).toBeInTheDocument();
|
||||
expect(screen.getByRole("heading", { name: "Context" })).toBeInTheDocument();
|
||||
expect(screen.getByRole("heading", { name: "Identity" })).toBeInTheDocument();
|
||||
expect(screen.getByLabelText("Directives")).toHaveValue("alpha agents");
|
||||
expect(screen.getByLabelText("Persona")).toHaveValue(
|
||||
"# SOUL.md - Who You Are\n\n## Core Truths\n\nBe useful."
|
||||
);
|
||||
expect(screen.getByLabelText("Name")).toHaveValue("Alpha");
|
||||
});
|
||||
|
||||
it("shows_actionable_message_when_session_key_missing", async () => {
|
||||
const { client } = createMockClient();
|
||||
const agents = [createAgent("", "Alpha", "session-1")];
|
||||
|
||||
render(
|
||||
createElement(AgentBrainPanel, {
|
||||
client,
|
||||
agents,
|
||||
selectedAgentId: "",
|
||||
})
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText("Agent ID is missing for this agent.")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it("saves_updated_behavior_files", async () => {
|
||||
const { client, calls, filesByAgent } = createMockClient();
|
||||
const agents = [createAgent("agent-1", "Alpha", "session-1")];
|
||||
|
||||
render(
|
||||
createElement(AgentBrainPanel, {
|
||||
client,
|
||||
agents,
|
||||
selectedAgentId: "agent-1",
|
||||
})
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByLabelText("Directives")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
fireEvent.change(screen.getByLabelText("Directives"), {
|
||||
target: { value: "alpha directives updated" },
|
||||
});
|
||||
|
||||
const saveButton = screen.getByRole("button", { name: "Save" });
|
||||
expect(saveButton).not.toBeDisabled();
|
||||
fireEvent.click(saveButton);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(calls.some((entry) => entry.method === "agents.files.set")).toBe(true);
|
||||
});
|
||||
expect(filesByAgent["agent-1"]["AGENTS.md"]).toBe("alpha directives updated");
|
||||
});
|
||||
|
||||
it("discards_unsaved_changes_without_writing_files", async () => {
|
||||
const { client, calls } = createMockClient();
|
||||
const agents = [createAgent("agent-1", "Alpha", "session-1")];
|
||||
|
||||
render(
|
||||
createElement(AgentBrainPanel, {
|
||||
client,
|
||||
agents,
|
||||
selectedAgentId: "agent-1",
|
||||
})
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByLabelText("Name")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
fireEvent.change(screen.getByLabelText("Name"), {
|
||||
target: { value: "Alpha Prime" },
|
||||
});
|
||||
expect(screen.getByLabelText("Name")).toHaveValue("Alpha Prime");
|
||||
|
||||
fireEvent.click(screen.getByRole("button", { name: "Discard" }));
|
||||
expect(screen.getByLabelText("Name")).toHaveValue("Alpha");
|
||||
expect(calls.some((entry) => entry.method === "agents.files.set")).toBe(false);
|
||||
});
|
||||
|
||||
it("does_not_render_name_editor_in_personality_panel", async () => {
|
||||
const { client } = createMockClient();
|
||||
const agents = [createAgent("agent-1", "Alpha", "session-1")];
|
||||
|
||||
render(
|
||||
createElement(AgentBrainPanel, {
|
||||
client,
|
||||
agents,
|
||||
selectedAgentId: "agent-1",
|
||||
})
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole("heading", { name: "Persona" })).toBeInTheDocument();
|
||||
});
|
||||
expect(screen.queryByLabelText("Agent name")).not.toBeInTheDocument();
|
||||
expect(screen.queryByRole("button", { name: "Update Name" })).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user