- Move all co-located *.test.* files into sibling __tests__/ directories so the
layout is consistent across packages (159 renames + content-rewrite moves).
Updates relative imports, vi.mock specifiers, and __dirname/import.meta.url
path resolutions where tests read fixtures from disk.
- Drop tracked tsc-emit alongside engine .ts sources (auth-storage/logger/
skill-resolver/context-limit-detector/pi.{js,d.ts,*.map}). These were
accidentally committed in a merge and the stale pi.js was masking a real
test-mock vs source mismatch (tests imported "../pi.js" and vite preferred
the stale build over pi.ts).
- Add packages/engine/.gitignore to block future src/*.{js,d.ts,map}.
- Refactor plugin pi-module seams (openclaw/paperclip/hermes) to ESM-import
createFnAgent / promptWithFallback / describeModel from @fusion/engine
instead of require()-ing packages/engine/src/pi.js. Adds @fusion/engine to
the two plugin package.jsons that were missing it; exports describeModel
from the engine public API.
- Fix engine test mocks now that they run against current pi.ts: add
ModelRegistry.create static to mocks in pi.test.ts and pi-create-fn-agent
.test.ts; switch three boundary-result toEqual assertions to toMatchObject
so the new content/isError fields don't trip exact-match comparison.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
593 lines
20 KiB
TypeScript
593 lines
20 KiB
TypeScript
import { describe, it, expect, beforeEach, vi, afterEach } from "vitest";
|
|
import {
|
|
startAgentGeneration,
|
|
generateAgentSpec,
|
|
getAgentGenerationSession,
|
|
cleanupAgentGenerationSession,
|
|
checkRateLimit,
|
|
getRateLimitResetTime,
|
|
parseGenerationResponse,
|
|
__resetAgentGenerationState,
|
|
__runAgentGenerationCleanupForTests,
|
|
RateLimitError,
|
|
SessionNotFoundError,
|
|
} from "../agent-generation.js";
|
|
import {
|
|
setDiagnosticsSink,
|
|
resetDiagnosticsSink,
|
|
type DiagnosticsContext,
|
|
type DiagnosticsLevel,
|
|
} from "../ai-session-diagnostics.js";
|
|
|
|
// Counter for unique IPs per test
|
|
let ipCounter = 0;
|
|
function getUniqueIp(): string {
|
|
return `127.0.0.${++ipCounter}`;
|
|
}
|
|
|
|
interface CapturedDiagnostic {
|
|
level: DiagnosticsLevel;
|
|
scope: string;
|
|
message: string;
|
|
context: DiagnosticsContext;
|
|
}
|
|
|
|
describe("agent-generation module", () => {
|
|
beforeEach(() => {
|
|
vi.useFakeTimers();
|
|
__resetAgentGenerationState();
|
|
});
|
|
|
|
afterEach(() => {
|
|
resetDiagnosticsSink();
|
|
vi.useRealTimers();
|
|
vi.restoreAllMocks();
|
|
});
|
|
|
|
describe("startAgentGeneration", () => {
|
|
it("creates a session with valid role description", async () => {
|
|
const mockIp = getUniqueIp();
|
|
const session = await startAgentGeneration(mockIp, "Senior frontend code reviewer");
|
|
|
|
expect(session.id).toBeDefined();
|
|
expect(typeof session.id).toBe("string");
|
|
expect(session.roleDescription).toBe("Senior frontend code reviewer");
|
|
expect(session.spec).toBeUndefined();
|
|
expect(session.createdAt).toBeInstanceOf(Date);
|
|
expect(session.updatedAt).toBeInstanceOf(Date);
|
|
});
|
|
|
|
it("does not expose IP in the public session", async () => {
|
|
const mockIp = getUniqueIp();
|
|
const session = await startAgentGeneration(mockIp, "Test role");
|
|
|
|
expect((session as unknown as Record<string, unknown>).ip).toBeUndefined();
|
|
});
|
|
|
|
it("enforces rate limiting", async () => {
|
|
const mockIp = getUniqueIp();
|
|
// Create max sessions (10 per hour)
|
|
for (let i = 0; i < 10; i++) {
|
|
await startAgentGeneration(mockIp, `Role ${i}`);
|
|
}
|
|
|
|
// 11th session should fail
|
|
await expect(startAgentGeneration(mockIp, "One more")).rejects.toThrow(RateLimitError);
|
|
});
|
|
|
|
it("allows new sessions after rate limit window expires", async () => {
|
|
const mockIp = getUniqueIp();
|
|
for (let i = 0; i < 10; i++) {
|
|
await startAgentGeneration(mockIp, `Role ${i}`);
|
|
}
|
|
|
|
// Advance time by 1 hour + 1 minute
|
|
vi.advanceTimersByTime(61 * 60 * 1000);
|
|
|
|
const session = await startAgentGeneration(mockIp, "New role after reset");
|
|
expect(session.id).toBeDefined();
|
|
});
|
|
|
|
it("generates different session IDs for each session", async () => {
|
|
const ip1 = getUniqueIp();
|
|
const ip2 = getUniqueIp();
|
|
const session1 = await startAgentGeneration(ip1, "Role 1");
|
|
const session2 = await startAgentGeneration(ip2, "Role 2");
|
|
|
|
expect(session1.id).not.toBe(session2.id);
|
|
});
|
|
|
|
it("rate limits independently per IP", async () => {
|
|
const ip1 = getUniqueIp();
|
|
const ip2 = getUniqueIp();
|
|
|
|
for (let i = 0; i < 10; i++) {
|
|
await startAgentGeneration(ip1, `Role ${i}`);
|
|
}
|
|
|
|
// ip2 should still work
|
|
const session = await startAgentGeneration(ip2, "Role from another IP");
|
|
expect(session.id).toBeDefined();
|
|
});
|
|
});
|
|
|
|
describe("generateAgentSpec", () => {
|
|
it("throws SessionNotFoundError for non-existent session", async () => {
|
|
await expect(
|
|
generateAgentSpec("non-existent-session-id", "/tmp")
|
|
).rejects.toThrow(SessionNotFoundError);
|
|
});
|
|
|
|
it("emits a nonfatal diagnostic when session dispose throws after successful generation", async () => {
|
|
vi.resetModules();
|
|
|
|
const diagnostics: CapturedDiagnostic[] = [];
|
|
const diagnosticsModule = await import("../ai-session-diagnostics.js");
|
|
diagnosticsModule.setDiagnosticsSink((level, scope, message, context) => {
|
|
diagnostics.push({ level, scope, message, context });
|
|
});
|
|
|
|
vi.doMock("@fusion/engine", () => ({
|
|
createFnAgent: vi.fn(async () => {
|
|
const messages: Array<{ role: string; content: string }> = [];
|
|
return {
|
|
session: {
|
|
state: { messages },
|
|
prompt: vi.fn(async () => {
|
|
messages.push({
|
|
role: "assistant",
|
|
content: JSON.stringify({
|
|
title: "Generated Agent",
|
|
icon: "🤖",
|
|
role: "custom",
|
|
description: "Generated description",
|
|
systemPrompt: "Generated prompt",
|
|
thinkingLevel: "low",
|
|
maxTurns: 12,
|
|
}),
|
|
});
|
|
}),
|
|
dispose: vi.fn(() => {
|
|
throw new Error("dispose failed");
|
|
}),
|
|
},
|
|
};
|
|
}),
|
|
}));
|
|
|
|
const agentGenerationModule = await import("../agent-generation.js");
|
|
const session = await agentGenerationModule.startAgentGeneration(getUniqueIp(), "Role requiring generation");
|
|
const spec = await agentGenerationModule.generateAgentSpec(session.id, "/tmp");
|
|
|
|
expect(spec).toMatchObject({
|
|
title: "Generated Agent",
|
|
role: "custom",
|
|
});
|
|
|
|
expect(diagnostics).toContainEqual(
|
|
expect.objectContaining({
|
|
level: "error",
|
|
scope: "agent-generation",
|
|
message: "Failed to dispose agent-generation session",
|
|
context: expect.objectContaining({
|
|
sessionId: session.id,
|
|
operation: "dispose-agent-session",
|
|
error: expect.objectContaining({
|
|
message: "dispose failed",
|
|
}),
|
|
}),
|
|
})
|
|
);
|
|
|
|
diagnosticsModule.resetDiagnosticsSink();
|
|
});
|
|
|
|
it("logs structured error diagnostics with sessionId and rethrows when AI generation fails", async () => {
|
|
vi.resetModules();
|
|
|
|
const generationFailure = new Error("engine failed to generate spec");
|
|
vi.doMock("@fusion/engine", () => ({
|
|
createFnAgent: vi.fn(async () => {
|
|
throw generationFailure;
|
|
}),
|
|
}));
|
|
|
|
const diagnostics: CapturedDiagnostic[] = [];
|
|
|
|
const diagnosticsModule = await import("../ai-session-diagnostics.js");
|
|
diagnosticsModule.setDiagnosticsSink((level, scope, message, context) => {
|
|
diagnostics.push({ level, scope, message, context });
|
|
});
|
|
|
|
const agentGenerationModule = await import("../agent-generation.js");
|
|
const session = await agentGenerationModule.startAgentGeneration(getUniqueIp(), "Role requiring AI spec");
|
|
|
|
await expect(agentGenerationModule.generateAgentSpec(session.id, "/tmp")).rejects.toThrow(generationFailure);
|
|
|
|
expect(diagnostics).toHaveLength(1);
|
|
expect(diagnostics[0]).toMatchObject({
|
|
level: "error",
|
|
scope: "agent-generation",
|
|
message: "AI generation failed for session",
|
|
context: expect.objectContaining({
|
|
sessionId: session.id,
|
|
operation: "generate-agent-spec",
|
|
error: expect.objectContaining({
|
|
message: "engine failed to generate spec",
|
|
}),
|
|
}),
|
|
});
|
|
|
|
diagnosticsModule.resetDiagnosticsSink();
|
|
});
|
|
});
|
|
|
|
describe("getAgentGenerationSession", () => {
|
|
it("returns session after creation", async () => {
|
|
const mockIp = getUniqueIp();
|
|
const created = await startAgentGeneration(mockIp, "Test role");
|
|
|
|
const retrieved = getAgentGenerationSession(created.id);
|
|
expect(retrieved).toBeDefined();
|
|
expect(retrieved!.id).toBe(created.id);
|
|
expect(retrieved!.roleDescription).toBe("Test role");
|
|
});
|
|
|
|
it("returns undefined for non-existent session", () => {
|
|
const result = getAgentGenerationSession("non-existent");
|
|
expect(result).toBeUndefined();
|
|
});
|
|
|
|
it("returns undefined after cleanup", async () => {
|
|
const mockIp = getUniqueIp();
|
|
const created = await startAgentGeneration(mockIp, "Test role");
|
|
|
|
cleanupAgentGenerationSession(created.id);
|
|
|
|
const result = getAgentGenerationSession(created.id);
|
|
expect(result).toBeUndefined();
|
|
});
|
|
});
|
|
|
|
describe("cleanupAgentGenerationSession", () => {
|
|
it("removes session", async () => {
|
|
const mockIp = getUniqueIp();
|
|
const created = await startAgentGeneration(mockIp, "Test role");
|
|
|
|
cleanupAgentGenerationSession(created.id);
|
|
|
|
expect(getAgentGenerationSession(created.id)).toBeUndefined();
|
|
});
|
|
|
|
it("is idempotent for non-existent session", () => {
|
|
expect(() => cleanupAgentGenerationSession("non-existent")).not.toThrow();
|
|
});
|
|
});
|
|
|
|
describe("checkRateLimit", () => {
|
|
beforeEach(() => {
|
|
__resetAgentGenerationState();
|
|
});
|
|
|
|
it("allows first request from new IP", () => {
|
|
expect(checkRateLimit("1.2.3.4")).toBe(true);
|
|
});
|
|
|
|
it("blocks after exceeding limit", () => {
|
|
for (let i = 0; i < 10; i++) {
|
|
checkRateLimit("1.2.3.4");
|
|
}
|
|
expect(checkRateLimit("1.2.3.4")).toBe(false);
|
|
});
|
|
|
|
it("allows requests after window expires", () => {
|
|
for (let i = 0; i < 10; i++) {
|
|
checkRateLimit("1.2.3.4");
|
|
}
|
|
|
|
vi.advanceTimersByTime(61 * 60 * 1000);
|
|
|
|
expect(checkRateLimit("1.2.3.4")).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe("getRateLimitResetTime", () => {
|
|
it("returns null for unknown IP", () => {
|
|
expect(getRateLimitResetTime("unknown")).toBeNull();
|
|
});
|
|
|
|
it("returns a date after first request", () => {
|
|
checkRateLimit("1.2.3.4");
|
|
const resetTime = getRateLimitResetTime("1.2.3.4");
|
|
|
|
expect(resetTime).toBeInstanceOf(Date);
|
|
expect(resetTime!.getTime()).toBeGreaterThan(Date.now());
|
|
});
|
|
});
|
|
|
|
describe("parseGenerationResponse", () => {
|
|
it("parses valid JSON response", () => {
|
|
const json = JSON.stringify({
|
|
title: "Senior Frontend Reviewer",
|
|
icon: "🔍",
|
|
role: "reviewer",
|
|
description: "Reviews frontend code for quality",
|
|
systemPrompt: "# Role\nYou are a senior frontend reviewer.",
|
|
thinkingLevel: "medium",
|
|
maxTurns: 25,
|
|
});
|
|
|
|
const spec = parseGenerationResponse(json);
|
|
|
|
expect(spec.title).toBe("Senior Frontend Reviewer");
|
|
expect(spec.icon).toBe("🔍");
|
|
expect(spec.role).toBe("reviewer");
|
|
expect(spec.description).toBe("Reviews frontend code for quality");
|
|
expect(spec.systemPrompt).toBe("# Role\nYou are a senior frontend reviewer.");
|
|
expect(spec.thinkingLevel).toBe("medium");
|
|
expect(spec.maxTurns).toBe(25);
|
|
});
|
|
|
|
it("parses JSON wrapped in markdown code block", () => {
|
|
const inner = JSON.stringify({
|
|
title: "Test Agent",
|
|
icon: "🤖",
|
|
role: "custom",
|
|
description: "A test agent",
|
|
systemPrompt: "Test prompt",
|
|
thinkingLevel: "off",
|
|
maxTurns: 10,
|
|
});
|
|
const wrapped = "```json\n" + inner + "\n```";
|
|
|
|
const spec = parseGenerationResponse(wrapped);
|
|
expect(spec.title).toBe("Test Agent");
|
|
});
|
|
|
|
it("parses JSON with surrounding text", () => {
|
|
const json = JSON.stringify({
|
|
title: "Test Agent",
|
|
icon: "🤖",
|
|
role: "custom",
|
|
description: "A test agent",
|
|
systemPrompt: "Test prompt",
|
|
thinkingLevel: "off",
|
|
maxTurns: 10,
|
|
});
|
|
const text = `Here is the specification:\n${json}\nHope this helps!`;
|
|
|
|
const spec = parseGenerationResponse(text);
|
|
expect(spec.title).toBe("Test Agent");
|
|
});
|
|
|
|
it("applies defaults for missing fields", () => {
|
|
const json = JSON.stringify({});
|
|
|
|
const spec = parseGenerationResponse(json);
|
|
|
|
expect(spec.title).toBe("Custom Agent");
|
|
expect(spec.icon).toBe("🤖");
|
|
expect(spec.role).toBe("custom");
|
|
expect(spec.description).toBe("");
|
|
expect(spec.systemPrompt).toBe("");
|
|
expect(spec.thinkingLevel).toBe("off");
|
|
expect(spec.maxTurns).toBe(1000);
|
|
});
|
|
|
|
it("truncates title to 60 characters", () => {
|
|
const longTitle = "A".repeat(100);
|
|
const json = JSON.stringify({
|
|
title: longTitle,
|
|
icon: "🤖",
|
|
role: "custom",
|
|
description: "test",
|
|
systemPrompt: "test",
|
|
thinkingLevel: "off",
|
|
maxTurns: 10,
|
|
});
|
|
|
|
const spec = parseGenerationResponse(json);
|
|
expect(spec.title.length).toBe(60);
|
|
});
|
|
|
|
it("clamps maxTurns to valid range", () => {
|
|
const json = JSON.stringify({
|
|
title: "Test",
|
|
maxTurns: 9999,
|
|
});
|
|
|
|
const spec = parseGenerationResponse(json);
|
|
expect(spec.maxTurns).toBe(2000);
|
|
|
|
const json2 = JSON.stringify({ title: "Test", maxTurns: -5 });
|
|
const spec2 = parseGenerationResponse(json2);
|
|
expect(spec2.maxTurns).toBe(1); // clamped to minimum
|
|
});
|
|
|
|
it("defaults invalid thinkingLevel to off", () => {
|
|
const json = JSON.stringify({
|
|
title: "Test",
|
|
thinkingLevel: "ultra",
|
|
});
|
|
|
|
const spec = parseGenerationResponse(json);
|
|
expect(spec.thinkingLevel).toBe("off");
|
|
});
|
|
|
|
it("repairs JSON with trailing commas", () => {
|
|
const broken = '{"title":"Test","icon":"X","role":"custom","description":"d","systemPrompt":"s","thinkingLevel":"off","maxTurns":10,}';
|
|
const spec = parseGenerationResponse(broken);
|
|
expect(spec.title).toBe("Test");
|
|
});
|
|
|
|
it("throws for non-JSON text", () => {
|
|
expect(() => parseGenerationResponse("Hello world, this is not JSON")).toThrow(
|
|
"AI returned no valid JSON"
|
|
);
|
|
});
|
|
|
|
it("throws for empty text", () => {
|
|
expect(() => parseGenerationResponse("")).toThrow("AI returned no valid JSON");
|
|
});
|
|
});
|
|
|
|
describe("TTL cleanup", () => {
|
|
it("sessions are retrievable within TTL", async () => {
|
|
const mockIp = getUniqueIp();
|
|
const session = await startAgentGeneration(mockIp, "Test role");
|
|
|
|
// Session should exist within TTL
|
|
expect(getAgentGenerationSession(session.id)).toBeDefined();
|
|
|
|
// Advance to just before TTL
|
|
vi.advanceTimersByTime(29 * 60 * 1000);
|
|
|
|
expect(getAgentGenerationSession(session.id)).toBeDefined();
|
|
});
|
|
|
|
it("session data is accessible after creation", async () => {
|
|
const mockIp = getUniqueIp();
|
|
const session = await startAgentGeneration(mockIp, "Security auditor role");
|
|
|
|
const retrieved = getAgentGenerationSession(session.id);
|
|
expect(retrieved).toBeDefined();
|
|
expect(retrieved!.roleDescription).toBe("Security auditor role");
|
|
});
|
|
|
|
it("emits one structured cleanup diagnostic when expired sessions and stale rate limits are removed", async () => {
|
|
const diagnostics: CapturedDiagnostic[] = [];
|
|
setDiagnosticsSink((level, scope, message, context) => {
|
|
diagnostics.push({ level, scope, message, context });
|
|
});
|
|
|
|
const staleIp = getUniqueIp();
|
|
const session = await startAgentGeneration(staleIp, "Temporary role");
|
|
checkRateLimit("192.168.0.99");
|
|
|
|
vi.setSystemTime(Date.now() + 61 * 60 * 1000);
|
|
__runAgentGenerationCleanupForTests();
|
|
|
|
expect(getAgentGenerationSession(session.id)).toBeUndefined();
|
|
expect(getRateLimitResetTime(staleIp)).toBeNull();
|
|
expect(getRateLimitResetTime("192.168.0.99")).toBeNull();
|
|
|
|
expect(diagnostics).toHaveLength(1);
|
|
expect(diagnostics[0]).toMatchObject({
|
|
level: "info",
|
|
scope: "agent-generation",
|
|
message: "Cleanup completed",
|
|
context: expect.objectContaining({
|
|
cleanedSessions: 1,
|
|
cleanedRateLimits: 2,
|
|
ttlMs: 30 * 60 * 1000,
|
|
rateLimitWindowMs: 60 * 60 * 1000,
|
|
operation: "cleanup-expired",
|
|
}),
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("prompt override support", () => {
|
|
// Mock createFnAgent to capture the systemPrompt passed to it
|
|
let capturedSystemPrompt: string | undefined;
|
|
|
|
beforeEach(async () => {
|
|
capturedSystemPrompt = undefined;
|
|
// Mock createFnAgent before tests run
|
|
vi.doMock("@fusion/engine", () => ({
|
|
createFnAgent: vi.fn(async (options: { cwd: string; systemPrompt: string; tools: string }) => {
|
|
capturedSystemPrompt = options.systemPrompt;
|
|
const messages: Array<{ role: string; content: string }> = [];
|
|
return {
|
|
session: {
|
|
state: { messages },
|
|
prompt: vi.fn(async () => {
|
|
messages.push({
|
|
role: "assistant",
|
|
content: JSON.stringify({ title: "Test Agent", description: "A test agent", systemPrompt: "Test prompt", tools: [], maxTurns: 10, tags: [] }),
|
|
});
|
|
}),
|
|
dispose: vi.fn(),
|
|
},
|
|
};
|
|
}),
|
|
}));
|
|
// Reset the module to pick up the mock
|
|
vi.resetModules();
|
|
});
|
|
|
|
afterEach(() => {
|
|
vi.restoreAllMocks();
|
|
vi.resetModules();
|
|
});
|
|
|
|
it("generates spec with default AGENT_GENERATION_SYSTEM_PROMPT when no overrides provided", async () => {
|
|
const { generateAgentSpec: genSpec, startAgentGeneration: startGen, AGENT_GENERATION_SYSTEM_PROMPT } = await import("../agent-generation.js");
|
|
|
|
const session = await startGen(getUniqueIp(), "Test role");
|
|
const spec = await genSpec(session.id, "/tmp");
|
|
|
|
// The spec should be empty since we mocked an empty response
|
|
expect(spec).toBeDefined();
|
|
// The system prompt should be EXACTLY the constant when no overrides
|
|
expect(capturedSystemPrompt).toBe(AGENT_GENERATION_SYSTEM_PROMPT);
|
|
});
|
|
|
|
it("generates spec with override system prompt when overrides provided", async () => {
|
|
const { generateAgentSpec: genSpec, startAgentGeneration: startGen } = await import("../agent-generation.js");
|
|
|
|
const customPrompt = "CUSTOM AGENT GENERATION PROMPT";
|
|
const overrides = { "agent-generation-system": customPrompt };
|
|
|
|
const session = await startGen(getUniqueIp(), "Test role");
|
|
const spec = await genSpec(session.id, "/tmp", overrides);
|
|
|
|
// The spec should be empty since we mocked an empty response
|
|
expect(spec).toBeDefined();
|
|
// The system prompt should be EXACTLY the custom override
|
|
expect(capturedSystemPrompt).toBe(customPrompt);
|
|
});
|
|
|
|
it("falls back to AGENT_GENERATION_SYSTEM_PROMPT constant when override key not recognized", async () => {
|
|
const { generateAgentSpec: genSpec, startAgentGeneration: startGen, AGENT_GENERATION_SYSTEM_PROMPT } = await import("../agent-generation.js");
|
|
|
|
// Provide an override with a non-existent key
|
|
const overrides = { "non-existent-key": "Some prompt" };
|
|
|
|
const session = await startGen(getUniqueIp(), "Test role");
|
|
const spec = await genSpec(session.id, "/tmp", overrides);
|
|
|
|
// Should fall back to EXACTLY the constant
|
|
expect(spec).toBeDefined();
|
|
expect(capturedSystemPrompt).toBe(AGENT_GENERATION_SYSTEM_PROMPT);
|
|
});
|
|
|
|
it("falls back to AGENT_GENERATION_SYSTEM_PROMPT constant when resolvePrompt returns empty", async () => {
|
|
const { generateAgentSpec: genSpec, startAgentGeneration: startGen, AGENT_GENERATION_SYSTEM_PROMPT } = await import("../agent-generation.js");
|
|
|
|
// Empty overrides should still get the default constant
|
|
const overrides = { "agent-generation-system": "" };
|
|
|
|
const session = await startGen(getUniqueIp(), "Test role");
|
|
const spec = await genSpec(session.id, "/tmp", overrides);
|
|
|
|
expect(spec).toBeDefined();
|
|
expect(capturedSystemPrompt).toBe(AGENT_GENERATION_SYSTEM_PROMPT);
|
|
});
|
|
|
|
it("uses EXACT override when override is a non-empty string", async () => {
|
|
const { generateAgentSpec: genSpec, startAgentGeneration: startGen } = await import("../agent-generation.js");
|
|
|
|
// Exact override string
|
|
const customPrompt = "EXACT CUSTOM PROMPT TEXT";
|
|
const overrides = { "agent-generation-system": customPrompt };
|
|
|
|
const session = await startGen(getUniqueIp(), "Test role");
|
|
const spec = await genSpec(session.id, "/tmp", overrides);
|
|
|
|
expect(spec).toBeDefined();
|
|
expect(capturedSystemPrompt).toBe(customPrompt);
|
|
});
|
|
});
|
|
});
|