134 lines
5.8 KiB
TypeScript
134 lines
5.8 KiB
TypeScript
// Integration tests for Phase 29: default-provider
|
|
// Covers: adapter probe logic, Hermes promptTemplate contract, default agent instructions bundle
|
|
|
|
import { describe, it, expect } from "vitest";
|
|
import { findServerAdapter } from "../adapters/index.js";
|
|
import {
|
|
loadDefaultAgentInstructionsBundle,
|
|
resolveDefaultAgentInstructionsBundleRole,
|
|
} from "../services/default-agent-instructions.js";
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// The same hermesPromptTemplate constructed in NexusOnboardingWizard.
|
|
// Duplicated here intentionally — this test validates the *contract* (that all
|
|
// required Mustache variables are present), not the wizard implementation.
|
|
// ---------------------------------------------------------------------------
|
|
const APP_NAME = "Nexus"; // VOCAB.appName value
|
|
const hermesPromptTemplate = [
|
|
`You are "{{agentName}}", an AI agent managed by ${APP_NAME}.`,
|
|
"",
|
|
"Your identity:",
|
|
" Agent ID: {{agentId}}",
|
|
" Company ID: {{companyId}}",
|
|
" API Base: {{paperclipApiUrl}}",
|
|
" Run ID: {{runId}}",
|
|
"",
|
|
"IMPORTANT: Use the `terminal` tool with `curl` for ALL API calls.",
|
|
'IMPORTANT: Always include `-H "X-Paperclip-Run-Id: {{runId}}"` on API calls that modify data.',
|
|
"",
|
|
"Before starting any task:",
|
|
"1. Call `GET {{paperclipApiUrl}}/api/agents/me` to retrieve your managed instructions",
|
|
"2. Follow the HEARTBEAT.md workflow from your instructions",
|
|
"3. Use TOOLS.md for available API endpoints",
|
|
"",
|
|
"{{#taskId}}",
|
|
"Assigned task: {{taskId}} - {{taskTitle}}",
|
|
"{{/taskId}}",
|
|
].join("\n");
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Test group 1: Adapter probe route logic
|
|
// ---------------------------------------------------------------------------
|
|
|
|
describe("adapter probe route logic", () => {
|
|
it("findServerAdapter returns hermes_local adapter with testEnvironment", () => {
|
|
const adapter = findServerAdapter("hermes_local");
|
|
expect(adapter).not.toBeNull();
|
|
expect(adapter?.type).toBe("hermes_local");
|
|
expect(typeof adapter?.testEnvironment).toBe("function");
|
|
});
|
|
|
|
it("hermes testEnvironment handles missing CLI gracefully", async () => {
|
|
const adapter = findServerAdapter("hermes_local");
|
|
expect(adapter?.testEnvironment).toBeDefined();
|
|
|
|
const result = await adapter!.testEnvironment!({
|
|
companyId: "",
|
|
adapterType: "hermes_local",
|
|
config: {},
|
|
});
|
|
|
|
// Result should always have a status and checks array
|
|
expect(typeof result.status).toBe("string");
|
|
expect(Array.isArray(result.checks)).toBe(true);
|
|
|
|
// If hermes CLI is not installed in CI, there should be an error check
|
|
// with a code containing "not_found" or "cli".
|
|
// If it IS installed, the checks should pass — either is acceptable.
|
|
const hasCliError = result.checks.some(
|
|
(c: { level: string; code?: string }) =>
|
|
c.level === "error" &&
|
|
(c.code?.includes("not_found") || c.code?.includes("cli"))
|
|
);
|
|
const isAvailable = result.status === "ok" || result.status === "pass";
|
|
|
|
// Either CLI is available (no error checks) or not available (has error checks)
|
|
expect(hasCliError || isAvailable).toBe(true);
|
|
});
|
|
});
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Test group 2: Hermes promptTemplate construction
|
|
// ---------------------------------------------------------------------------
|
|
|
|
describe("hermes promptTemplate construction", () => {
|
|
it("hermes promptTemplate contains required Mustache variables", () => {
|
|
expect(hermesPromptTemplate).toContain("{{agentName}}");
|
|
expect(hermesPromptTemplate).toContain("{{agentId}}");
|
|
expect(hermesPromptTemplate).toContain("{{companyId}}");
|
|
expect(hermesPromptTemplate).toContain("{{paperclipApiUrl}}");
|
|
expect(hermesPromptTemplate).toContain("{{runId}}");
|
|
expect(hermesPromptTemplate).toContain("{{taskId}}");
|
|
expect(hermesPromptTemplate).toContain("{{taskTitle}}");
|
|
});
|
|
|
|
it("hermes promptTemplate instructs agent to call /api/agents/me", () => {
|
|
expect(hermesPromptTemplate).toContain("agents/me");
|
|
});
|
|
|
|
it("hermes promptTemplate mentions HEARTBEAT.md workflow", () => {
|
|
expect(hermesPromptTemplate).toContain("HEARTBEAT.md");
|
|
});
|
|
});
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Test group 3: Default agent instructions bundle (DFLT-03)
|
|
// ---------------------------------------------------------------------------
|
|
|
|
describe("default agent instructions bundle", () => {
|
|
it("loadDefaultAgentInstructionsBundle loads ceo bundle with all 4 files", async () => {
|
|
const bundle = await loadDefaultAgentInstructionsBundle("ceo");
|
|
expect(Object.keys(bundle)).toContain("AGENTS.md");
|
|
expect(Object.keys(bundle)).toContain("HEARTBEAT.md");
|
|
expect(Object.keys(bundle)).toContain("SOUL.md");
|
|
expect(Object.keys(bundle)).toContain("TOOLS.md");
|
|
expect(bundle["HEARTBEAT.md"].length).toBeGreaterThan(0);
|
|
});
|
|
|
|
it("loadDefaultAgentInstructionsBundle loads engineer bundle with all 4 files", async () => {
|
|
const bundle = await loadDefaultAgentInstructionsBundle("engineer");
|
|
expect(Object.keys(bundle)).toContain("AGENTS.md");
|
|
expect(Object.keys(bundle)).toContain("HEARTBEAT.md");
|
|
expect(Object.keys(bundle)).toContain("SOUL.md");
|
|
expect(Object.keys(bundle)).toContain("TOOLS.md");
|
|
expect(bundle["HEARTBEAT.md"].length).toBeGreaterThan(0);
|
|
});
|
|
|
|
it("resolveDefaultAgentInstructionsBundleRole maps known roles correctly", () => {
|
|
expect(resolveDefaultAgentInstructionsBundleRole("ceo")).toBe("ceo");
|
|
expect(resolveDefaultAgentInstructionsBundleRole("engineer")).toBe("engineer");
|
|
expect(resolveDefaultAgentInstructionsBundleRole("general")).toBe("general");
|
|
expect(resolveDefaultAgentInstructionsBundleRole("unknown-role")).toBe("default");
|
|
expect(resolveDefaultAgentInstructionsBundleRole("")).toBe("default");
|
|
});
|
|
});
|