import fs from "node:fs"; import { createTestPluginApi } from "openclaw/plugin-sdk/plugin-test-api"; import { describe, expect, it, vi } from "vitest"; vi.mock("./harness.js", async (importOriginal) => { const actual = await importOriginal(); return { ...actual, createCopilotAgentHarness: vi.fn(actual.createCopilotAgentHarness), }; }); import { createCopilotAgentHarness } from "./harness.js"; import plugin from "./index.js"; function loadManifest(): Record { return JSON.parse( fs.readFileSync(new URL("./openclaw.plugin.json", import.meta.url), "utf8"), ) as Record; } function registerWithPluginConfig(pluginConfig: Record | undefined) { const registerAgentHarness = vi.fn(); const sessionStore = { register: vi.fn(), lookup: vi.fn(), delete: vi.fn(), }; const openSyncKeyedStore = vi.fn(() => sessionStore); plugin.register( createTestPluginApi({ id: "copilot", name: "GitHub Copilot agent runtime", source: "test", config: {}, pluginConfig, runtime: { state: { openSyncKeyedStore } } as never, registerAgentHarness, }), ); const harness = registerAgentHarness.mock.calls.at(0)?.at(0) as { id: string; label: string; supports(ctx: { provider: string; modelId?: string; requestedRuntime?: string; }): { supported: true; priority?: number } | { supported: false; reason?: string }; }; return { registerAgentHarness, harness, openSyncKeyedStore, sessionStore }; } describe("copilot plugin", () => { it("is opt-in by default and only declares an agent harness activation", () => { const manifest = loadManifest(); const activation = manifest.activation as Record; expect(manifest.enabledByDefault).toBeUndefined(); expect(activation.onStartup).toBe(false); expect(activation.onAgentHarnesses).toEqual(["copilot"]); expect(manifest.providers).toBeUndefined(); expect(typeof manifest.version).toBe("string"); expect(manifest.version).not.toBe(""); }); it("registers exactly one copilot agent harness and nothing else", () => { const registerAgentHarness = vi.fn(); const registerProvider = vi.fn(); const registerModelCatalogProvider = vi.fn(); const registerMediaUnderstandingProvider = vi.fn(); const registerMigrationProvider = vi.fn(); const registerCommand = vi.fn(); const registerNodeHostCommand = vi.fn(); const registerNodeInvokePolicy = vi.fn(); const on = vi.fn(); const onConversationBindingResolved = vi.fn(); plugin.register( createTestPluginApi({ id: "copilot", name: "GitHub Copilot agent runtime", source: "test", config: {}, pluginConfig: {}, runtime: { state: { openSyncKeyedStore: vi.fn(() => ({})) } } as never, registerAgentHarness, registerProvider, registerModelCatalogProvider, registerMediaUnderstandingProvider, registerMigrationProvider, registerCommand, registerNodeHostCommand, registerNodeInvokePolicy, on, onConversationBindingResolved, }), ); expect(registerAgentHarness).toHaveBeenCalledTimes(1); expect(registerAgentHarness).toHaveBeenCalledWith( expect.objectContaining({ id: "copilot", label: "GitHub Copilot agent runtime" }), ); expect(registerProvider).not.toHaveBeenCalled(); expect(registerModelCatalogProvider).not.toHaveBeenCalled(); expect(registerMediaUnderstandingProvider).not.toHaveBeenCalled(); expect(registerMigrationProvider).not.toHaveBeenCalled(); expect(registerCommand).not.toHaveBeenCalled(); expect(registerNodeHostCommand).not.toHaveBeenCalled(); expect(registerNodeInvokePolicy).not.toHaveBeenCalled(); expect(on).not.toHaveBeenCalled(); expect(onConversationBindingResolved).not.toHaveBeenCalled(); }); it("registers a harness hard-bound to the canonical github-copilot provider", () => { const { harness } = registerWithPluginConfig({}); expect( harness.supports({ provider: "github-copilot", modelId: "gpt-4.1", requestedRuntime: "copilot", }), ).toEqual({ supported: true, priority: 100 }); expect( harness.supports({ provider: "anthropic", modelId: "claude-sonnet-4.5", requestedRuntime: "copilot", }), ).toEqual({ supported: false, reason: "provider is not one of: github-copilot", }); }); it("passes through a valid pool idle TTL and ignores malformed values", () => { const createHarness = vi.mocked(createCopilotAgentHarness); createHarness.mockClear(); registerWithPluginConfig({ pool: { idleTtlMs: 2500 } }); registerWithPluginConfig({ pool: { idleTtlMs: 0 } }); expect(createHarness).toHaveBeenNthCalledWith( 1, expect.objectContaining({ poolOptions: { idleTtlMs: 2500 } }), ); expect(createHarness.mock.calls[1]?.[0]).not.toHaveProperty("poolOptions"); }); it("opens the durable Copilot SDK session binding store", () => { const createHarness = vi.mocked(createCopilotAgentHarness); createHarness.mockClear(); const { openSyncKeyedStore, sessionStore } = registerWithPluginConfig({}); expect(openSyncKeyedStore).toHaveBeenCalledWith({ namespace: "sdk-sessions", maxEntries: 5000, defaultTtlMs: 90 * 24 * 60 * 60 * 1000, }); expect(createHarness).toHaveBeenCalledWith(expect.objectContaining({ sessionStore })); }); });