summaryrefslogtreecommitdiffhomepage
path: root/packages/api/tests/agent-manager.test.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/api/tests/agent-manager.test.ts')
-rw-r--r--packages/api/tests/agent-manager.test.ts113
1 files changed, 113 insertions, 0 deletions
diff --git a/packages/api/tests/agent-manager.test.ts b/packages/api/tests/agent-manager.test.ts
new file mode 100644
index 0000000..17b0bff
--- /dev/null
+++ b/packages/api/tests/agent-manager.test.ts
@@ -0,0 +1,113 @@
+import type { AgentEvent } from "@dispatch/core";
+import { describe, expect, it, vi } from "vitest";
+
+// Mock @dispatch/core's Agent to avoid real LLM calls
+vi.mock("@dispatch/core", async () => {
+ const actual = await vi.importActual<typeof import("@dispatch/core")>("@dispatch/core");
+ return {
+ ...actual,
+ Agent: class MockAgent {
+ status = "idle";
+ messages: unknown[] = [];
+ async *run(_message: string) {
+ yield { type: "status", status: "running" } as const;
+ await new Promise<void>((r) => setTimeout(r, 10));
+ yield { type: "text-delta", delta: "Hello " } as const;
+ yield { type: "text-delta", delta: "world" } as const;
+ yield {
+ type: "done",
+ message: { role: "assistant", content: "Hello world" },
+ } as const;
+ yield { type: "status", status: "idle" } as const;
+ }
+ },
+ };
+});
+
+// Import after mock is defined (Vitest hoists vi.mock automatically)
+const { AgentManager } = await import("../src/agent-manager.js");
+
+describe("AgentManager", () => {
+ it("initial status is idle", () => {
+ const manager = new AgentManager();
+ expect(manager.getStatus()).toBe("idle");
+ });
+
+ it("initial messageCount is 0", () => {
+ const manager = new AgentManager();
+ expect(manager.getMessageCount()).toBe(0);
+ });
+
+ it("event listeners receive events during processMessage", async () => {
+ const manager = new AgentManager();
+ const events: AgentEvent[] = [];
+ manager.onEvent((event) => {
+ events.push(event);
+ });
+
+ await manager.processMessage("test");
+
+ expect(events.length).toBeGreaterThan(0);
+ expect(events[0]).toEqual({ type: "status", status: "running" });
+
+ const lastEvent = events[events.length - 1];
+ expect(lastEvent).toEqual({ type: "status", status: "idle" });
+
+ const doneEvent = events.find((e) => e.type === "done");
+ expect(doneEvent).toBeDefined();
+ });
+
+ it("emits text-delta events during processMessage", async () => {
+ const manager = new AgentManager();
+ const events: AgentEvent[] = [];
+ manager.onEvent((event) => {
+ events.push(event);
+ });
+
+ await manager.processMessage("hello");
+
+ const textDeltas = events.filter((e) => e.type === "text-delta");
+ expect(textDeltas.length).toBeGreaterThan(0);
+ });
+
+ it("messageCount increments after processMessage", async () => {
+ const manager = new AgentManager();
+ await manager.processMessage("hello");
+ expect(manager.getMessageCount()).toBe(1);
+ await manager.processMessage("world");
+ expect(manager.getMessageCount()).toBe(2);
+ });
+
+ it("status returns to idle after processMessage completes", async () => {
+ const manager = new AgentManager();
+ await manager.processMessage("test");
+ expect(manager.getStatus()).toBe("idle");
+ });
+
+ it("unsubscribe removes listener", async () => {
+ const manager = new AgentManager();
+ const events: AgentEvent[] = [];
+ const unsubscribe = manager.onEvent((event) => {
+ events.push(event);
+ });
+
+ unsubscribe();
+ await manager.processMessage("test");
+
+ expect(events.length).toBe(0);
+ });
+
+ it("multiple listeners all receive events", async () => {
+ const manager = new AgentManager();
+ const listener1 = vi.fn();
+ const listener2 = vi.fn();
+
+ manager.onEvent(listener1);
+ manager.onEvent(listener2);
+
+ await manager.processMessage("test");
+
+ expect(listener1).toHaveBeenCalled();
+ expect(listener2).toHaveBeenCalled();
+ });
+});