|
@@ -1,227 +1,225 @@
|
|
|
-import { describe, expect, test } from "bun:test";
|
|
|
|
|
-import { formatCouncillorPrompt, formatCouncillorResults } from "./council";
|
|
|
|
|
|
|
+import { describe, expect, test } from 'bun:test';
|
|
|
|
|
+import { formatCouncillorPrompt, formatCouncillorResults } from './council';
|
|
|
|
|
|
|
|
-describe("formatCouncillorResults", () => {
|
|
|
|
|
|
|
+describe('formatCouncillorResults', () => {
|
|
|
const originalPrompt =
|
|
const originalPrompt =
|
|
|
- "What is the best way to implement a REST API in TypeScript?";
|
|
|
|
|
|
|
+ 'What is the best way to implement a REST API in TypeScript?';
|
|
|
|
|
|
|
|
- test("formats completed councillor results correctly", () => {
|
|
|
|
|
|
|
+ test('formats completed councillor results correctly', () => {
|
|
|
const councillorResults = [
|
|
const councillorResults = [
|
|
|
{
|
|
{
|
|
|
- name: "alpha",
|
|
|
|
|
- model: "anthropic/claude-opus-4-6",
|
|
|
|
|
- status: "completed",
|
|
|
|
|
- result: "Use Express.js with TypeScript interfaces for type safety.",
|
|
|
|
|
|
|
+ name: 'alpha',
|
|
|
|
|
+ model: 'anthropic/claude-opus-4-6',
|
|
|
|
|
+ status: 'completed',
|
|
|
|
|
+ result: 'Use Express.js with TypeScript interfaces for type safety.',
|
|
|
},
|
|
},
|
|
|
{
|
|
{
|
|
|
- name: "beta",
|
|
|
|
|
- model: "openai/gpt-5.5",
|
|
|
|
|
- status: "completed",
|
|
|
|
|
|
|
+ name: 'beta',
|
|
|
|
|
+ model: 'openai/gpt-5.5',
|
|
|
|
|
+ status: 'completed',
|
|
|
result:
|
|
result:
|
|
|
- "Consider Fastify for better performance and built-in type validation.",
|
|
|
|
|
|
|
+ 'Consider Fastify for better performance and built-in type validation.',
|
|
|
},
|
|
},
|
|
|
];
|
|
];
|
|
|
|
|
|
|
|
const formatted = formatCouncillorResults(
|
|
const formatted = formatCouncillorResults(
|
|
|
originalPrompt,
|
|
originalPrompt,
|
|
|
- councillorResults
|
|
|
|
|
|
|
+ councillorResults,
|
|
|
);
|
|
);
|
|
|
|
|
|
|
|
- expect(formatted).toContain("**Original Prompt**:");
|
|
|
|
|
|
|
+ expect(formatted).toContain('**Original Prompt**:');
|
|
|
expect(formatted).toContain(originalPrompt);
|
|
expect(formatted).toContain(originalPrompt);
|
|
|
- expect(formatted).toContain("**alpha** (claude-opus-4-6):");
|
|
|
|
|
- expect(formatted).toContain("**beta** (gpt-5.5):");
|
|
|
|
|
|
|
+ expect(formatted).toContain('**alpha** (claude-opus-4-6):');
|
|
|
|
|
+ expect(formatted).toContain('**beta** (gpt-5.5):');
|
|
|
expect(formatted).toContain(
|
|
expect(formatted).toContain(
|
|
|
- "Use Express.js with TypeScript interfaces for type safety."
|
|
|
|
|
|
|
+ 'Use Express.js with TypeScript interfaces for type safety.',
|
|
|
);
|
|
);
|
|
|
expect(formatted).toContain(
|
|
expect(formatted).toContain(
|
|
|
- "Consider Fastify for better performance and built-in type validation."
|
|
|
|
|
|
|
+ 'Consider Fastify for better performance and built-in type validation.',
|
|
|
);
|
|
);
|
|
|
- expect(formatted).toContain("**Councillor Responses**:");
|
|
|
|
|
|
|
+ expect(formatted).toContain('**Councillor Responses**:');
|
|
|
expect(formatted).toContain(
|
|
expect(formatted).toContain(
|
|
|
- "Produce the required final response: include a synthesized Council Response"
|
|
|
|
|
|
|
+ 'You MUST follow the Synthesis Process steps before producing output',
|
|
|
);
|
|
);
|
|
|
expect(formatted).toContain(
|
|
expect(formatted).toContain(
|
|
|
- "consensus confidence rating of unanimous, majority, or split."
|
|
|
|
|
|
|
+ 'consensus confidence rating (unanimous, majority, or split)',
|
|
|
);
|
|
);
|
|
|
- expect(formatted).not.toContain("**Failed/Timed-out Councillors**:");
|
|
|
|
|
|
|
+ expect(formatted).not.toContain('**Failed/Timed-out Councillors**:');
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
- test("includes failed councillors section when some fail", () => {
|
|
|
|
|
|
|
+ test('includes failed councillors section when some fail', () => {
|
|
|
const councillorResults = [
|
|
const councillorResults = [
|
|
|
{
|
|
{
|
|
|
- name: "alpha",
|
|
|
|
|
- model: "anthropic/claude-opus-4-6",
|
|
|
|
|
- status: "completed",
|
|
|
|
|
- result: "Use Express.js with TypeScript interfaces for type safety.",
|
|
|
|
|
|
|
+ name: 'alpha',
|
|
|
|
|
+ model: 'anthropic/claude-opus-4-6',
|
|
|
|
|
+ status: 'completed',
|
|
|
|
|
+ result: 'Use Express.js with TypeScript interfaces for type safety.',
|
|
|
},
|
|
},
|
|
|
{
|
|
{
|
|
|
- name: "beta",
|
|
|
|
|
- model: "openai/gpt-5.5",
|
|
|
|
|
- status: "timed_out",
|
|
|
|
|
- error: "Request timed out after 180000ms",
|
|
|
|
|
|
|
+ name: 'beta',
|
|
|
|
|
+ model: 'openai/gpt-5.5',
|
|
|
|
|
+ status: 'timed_out',
|
|
|
|
|
+ error: 'Request timed out after 180000ms',
|
|
|
},
|
|
},
|
|
|
{
|
|
{
|
|
|
- name: "gamma",
|
|
|
|
|
- model: "google/gemini-pro",
|
|
|
|
|
- status: "failed",
|
|
|
|
|
- error: "Provider returned empty response",
|
|
|
|
|
|
|
+ name: 'gamma',
|
|
|
|
|
+ model: 'google/gemini-pro',
|
|
|
|
|
+ status: 'failed',
|
|
|
|
|
+ error: 'Provider returned empty response',
|
|
|
},
|
|
},
|
|
|
];
|
|
];
|
|
|
|
|
|
|
|
const formatted = formatCouncillorResults(
|
|
const formatted = formatCouncillorResults(
|
|
|
originalPrompt,
|
|
originalPrompt,
|
|
|
- councillorResults
|
|
|
|
|
|
|
+ councillorResults,
|
|
|
);
|
|
);
|
|
|
|
|
|
|
|
- expect(formatted).toContain("**Councillor Responses**:");
|
|
|
|
|
- expect(formatted).toContain("**alpha** (claude-opus-4-6):");
|
|
|
|
|
|
|
+ expect(formatted).toContain('**Councillor Responses**:');
|
|
|
|
|
+ expect(formatted).toContain('**alpha** (claude-opus-4-6):');
|
|
|
expect(formatted).toContain(
|
|
expect(formatted).toContain(
|
|
|
- "Use Express.js with TypeScript interfaces for type safety."
|
|
|
|
|
|
|
+ 'Use Express.js with TypeScript interfaces for type safety.',
|
|
|
);
|
|
);
|
|
|
- expect(formatted).toContain("**Failed/Timed-out Councillors**:");
|
|
|
|
|
|
|
+ expect(formatted).toContain('**Failed/Timed-out Councillors**:');
|
|
|
expect(formatted).toContain(
|
|
expect(formatted).toContain(
|
|
|
- "**beta**: timed_out — Request timed out after 180000ms"
|
|
|
|
|
|
|
+ '**beta**: timed_out — Request timed out after 180000ms',
|
|
|
);
|
|
);
|
|
|
expect(formatted).toContain(
|
|
expect(formatted).toContain(
|
|
|
- "**gamma**: failed — Provider returned empty response"
|
|
|
|
|
|
|
+ '**gamma**: failed — Provider returned empty response',
|
|
|
);
|
|
);
|
|
|
- expect(formatted).not.toContain("**beta** (gpt-5.5):");
|
|
|
|
|
- expect(formatted).not.toContain("**gamma** (gemini-pro):");
|
|
|
|
|
|
|
+ expect(formatted).not.toContain('**beta** (gpt-5.5):');
|
|
|
|
|
+ expect(formatted).not.toContain('**gamma** (gemini-pro):');
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
- test("returns fallback message when all councillors fail", () => {
|
|
|
|
|
|
|
+ test('returns fallback message when all councillors fail', () => {
|
|
|
const councillorResults = [
|
|
const councillorResults = [
|
|
|
{
|
|
{
|
|
|
- name: "alpha",
|
|
|
|
|
- model: "anthropic/claude-opus-4-6",
|
|
|
|
|
- status: "timeout",
|
|
|
|
|
- error: "Request timed out",
|
|
|
|
|
|
|
+ name: 'alpha',
|
|
|
|
|
+ model: 'anthropic/claude-opus-4-6',
|
|
|
|
|
+ status: 'timeout',
|
|
|
|
|
+ error: 'Request timed out',
|
|
|
},
|
|
},
|
|
|
{
|
|
{
|
|
|
- name: "beta",
|
|
|
|
|
- model: "openai/gpt-5.5",
|
|
|
|
|
- status: "error",
|
|
|
|
|
- error: "Provider error",
|
|
|
|
|
|
|
+ name: 'beta',
|
|
|
|
|
+ model: 'openai/gpt-5.5',
|
|
|
|
|
+ status: 'error',
|
|
|
|
|
+ error: 'Provider error',
|
|
|
},
|
|
},
|
|
|
];
|
|
];
|
|
|
|
|
|
|
|
const formatted = formatCouncillorResults(
|
|
const formatted = formatCouncillorResults(
|
|
|
originalPrompt,
|
|
originalPrompt,
|
|
|
- councillorResults
|
|
|
|
|
|
|
+ councillorResults,
|
|
|
);
|
|
);
|
|
|
|
|
|
|
|
- expect(formatted).toContain("**Original Prompt**:");
|
|
|
|
|
|
|
+ expect(formatted).toContain('**Original Prompt**:');
|
|
|
expect(formatted).toContain(originalPrompt);
|
|
expect(formatted).toContain(originalPrompt);
|
|
|
- expect(formatted).toContain("**Councillor Responses**:");
|
|
|
|
|
- expect(formatted).toContain("All councillors failed to produce output:");
|
|
|
|
|
- expect(formatted).toContain("**alpha** (claude-opus-4-6):");
|
|
|
|
|
- expect(formatted).toContain("**beta** (gpt-5.5):");
|
|
|
|
|
- expect(formatted).toContain("Request timed out");
|
|
|
|
|
- expect(formatted).toContain("Provider error");
|
|
|
|
|
|
|
+ expect(formatted).toContain('**Councillor Responses**:');
|
|
|
|
|
+ expect(formatted).toContain('All councillors failed to produce output:');
|
|
|
|
|
+ expect(formatted).toContain('**alpha** (claude-opus-4-6):');
|
|
|
|
|
+ expect(formatted).toContain('**beta** (gpt-5.5):');
|
|
|
|
|
+ expect(formatted).toContain('Request timed out');
|
|
|
|
|
+ expect(formatted).toContain('Provider error');
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
- test("handles councillors with result but completed status", () => {
|
|
|
|
|
|
|
+ test('handles councillors with result but completed status', () => {
|
|
|
const councillorResults = [
|
|
const councillorResults = [
|
|
|
{
|
|
{
|
|
|
- name: "alpha",
|
|
|
|
|
- model: "anthropic/claude-opus-4-6",
|
|
|
|
|
- status: "completed",
|
|
|
|
|
- result: "Valid response",
|
|
|
|
|
|
|
+ name: 'alpha',
|
|
|
|
|
+ model: 'anthropic/claude-opus-4-6',
|
|
|
|
|
+ status: 'completed',
|
|
|
|
|
+ result: 'Valid response',
|
|
|
},
|
|
},
|
|
|
{
|
|
{
|
|
|
- name: "beta",
|
|
|
|
|
- model: "openai/gpt-5.5",
|
|
|
|
|
- status: "completed",
|
|
|
|
|
- result: "Another valid response",
|
|
|
|
|
|
|
+ name: 'beta',
|
|
|
|
|
+ model: 'openai/gpt-5.5',
|
|
|
|
|
+ status: 'completed',
|
|
|
|
|
+ result: 'Another valid response',
|
|
|
},
|
|
},
|
|
|
];
|
|
];
|
|
|
|
|
|
|
|
const formatted = formatCouncillorResults(
|
|
const formatted = formatCouncillorResults(
|
|
|
originalPrompt,
|
|
originalPrompt,
|
|
|
- councillorResults
|
|
|
|
|
|
|
+ councillorResults,
|
|
|
);
|
|
);
|
|
|
|
|
|
|
|
- expect(formatted).toContain("**alpha** (claude-opus-4-6):");
|
|
|
|
|
- expect(formatted).toContain("Valid response");
|
|
|
|
|
- expect(formatted).toContain("**beta** (gpt-5.5):");
|
|
|
|
|
- expect(formatted).toContain("Another valid response");
|
|
|
|
|
- expect(formatted).toContain(
|
|
|
|
|
- "preserve each individual councillor response in Councillor Details"
|
|
|
|
|
- );
|
|
|
|
|
|
|
+ expect(formatted).toContain('**alpha** (claude-opus-4-6):');
|
|
|
|
|
+ expect(formatted).toContain('Valid response');
|
|
|
|
|
+ expect(formatted).toContain('**beta** (gpt-5.5):');
|
|
|
|
|
+ expect(formatted).toContain('Another valid response');
|
|
|
|
|
+ expect(formatted).toContain('review each councillor response individually');
|
|
|
});
|
|
});
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
-describe("formatCouncillorPrompt", () => {
|
|
|
|
|
- const userPrompt = "How do I implement async/await in TypeScript?";
|
|
|
|
|
|
|
+describe('formatCouncillorPrompt', () => {
|
|
|
|
|
+ const userPrompt = 'How do I implement async/await in TypeScript?';
|
|
|
|
|
|
|
|
- test("returns user prompt unchanged when no councillor prompt is provided", () => {
|
|
|
|
|
|
|
+ test('returns user prompt unchanged when no councillor prompt is provided', () => {
|
|
|
const formatted = formatCouncillorPrompt(userPrompt);
|
|
const formatted = formatCouncillorPrompt(userPrompt);
|
|
|
expect(formatted).toBe(userPrompt);
|
|
expect(formatted).toBe(userPrompt);
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
- test("prepends councillor prompt with separator when provided", () => {
|
|
|
|
|
|
|
+ test('prepends councillor prompt with separator when provided', () => {
|
|
|
const councillorPrompt =
|
|
const councillorPrompt =
|
|
|
- "You are a TypeScript expert. Focus on practical examples.";
|
|
|
|
|
|
|
+ 'You are a TypeScript expert. Focus on practical examples.';
|
|
|
const formatted = formatCouncillorPrompt(userPrompt, councillorPrompt);
|
|
const formatted = formatCouncillorPrompt(userPrompt, councillorPrompt);
|
|
|
|
|
|
|
|
expect(formatted).toContain(councillorPrompt);
|
|
expect(formatted).toContain(councillorPrompt);
|
|
|
expect(formatted).toContain(userPrompt);
|
|
expect(formatted).toContain(userPrompt);
|
|
|
- expect(formatted).toContain("---");
|
|
|
|
|
|
|
+ expect(formatted).toContain('---');
|
|
|
expect(formatted).toMatch(
|
|
expect(formatted).toMatch(
|
|
|
new RegExp(
|
|
new RegExp(
|
|
|
`^${councillorPrompt.replace(
|
|
`^${councillorPrompt.replace(
|
|
|
/[.*+?^${}()|[\]\\]/g,
|
|
/[.*+?^${}()|[\]\\]/g,
|
|
|
- "\\$&"
|
|
|
|
|
- )}\\n\\n---\\n\\n${userPrompt.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}$`
|
|
|
|
|
- )
|
|
|
|
|
|
|
+ '\\$&',
|
|
|
|
|
+ )}\\n\\n---\\n\\n${userPrompt.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}$`,
|
|
|
|
|
+ ),
|
|
|
);
|
|
);
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
- test("handles multiline councillor prompt", () => {
|
|
|
|
|
|
|
+ test('handles multiline councillor prompt', () => {
|
|
|
const councillorPrompt =
|
|
const councillorPrompt =
|
|
|
- "You are an expert.\nFocus on clarity.\nProvide code examples.";
|
|
|
|
|
|
|
+ 'You are an expert.\nFocus on clarity.\nProvide code examples.';
|
|
|
const formatted = formatCouncillorPrompt(userPrompt, councillorPrompt);
|
|
const formatted = formatCouncillorPrompt(userPrompt, councillorPrompt);
|
|
|
|
|
|
|
|
expect(formatted).toContain(councillorPrompt);
|
|
expect(formatted).toContain(councillorPrompt);
|
|
|
expect(formatted).toContain(userPrompt);
|
|
expect(formatted).toContain(userPrompt);
|
|
|
- expect(formatted).toContain("---");
|
|
|
|
|
|
|
+ expect(formatted).toContain('---');
|
|
|
expect(formatted).toMatch(
|
|
expect(formatted).toMatch(
|
|
|
new RegExp(
|
|
new RegExp(
|
|
|
`^${councillorPrompt.replace(
|
|
`^${councillorPrompt.replace(
|
|
|
/[.*+?^${}()|[\]\\]/g,
|
|
/[.*+?^${}()|[\]\\]/g,
|
|
|
- "\\$&"
|
|
|
|
|
- )}\\n\\n---\\n\\n${userPrompt.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}$`
|
|
|
|
|
- )
|
|
|
|
|
|
|
+ '\\$&',
|
|
|
|
|
+ )}\\n\\n---\\n\\n${userPrompt.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}$`,
|
|
|
|
|
+ ),
|
|
|
);
|
|
);
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
- test("handles empty councillor prompt", () => {
|
|
|
|
|
- const formatted = formatCouncillorPrompt(userPrompt, "");
|
|
|
|
|
|
|
+ test('handles empty councillor prompt', () => {
|
|
|
|
|
+ const formatted = formatCouncillorPrompt(userPrompt, '');
|
|
|
expect(formatted).toBe(userPrompt);
|
|
expect(formatted).toBe(userPrompt);
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
- test("handles multiline user prompt with councillor prompt", () => {
|
|
|
|
|
- const councillorPrompt = "You are an expert.";
|
|
|
|
|
- const multilineUserPrompt = "Line 1\nLine 2\nLine 3";
|
|
|
|
|
|
|
+ test('handles multiline user prompt with councillor prompt', () => {
|
|
|
|
|
+ const councillorPrompt = 'You are an expert.';
|
|
|
|
|
+ const multilineUserPrompt = 'Line 1\nLine 2\nLine 3';
|
|
|
const formatted = formatCouncillorPrompt(
|
|
const formatted = formatCouncillorPrompt(
|
|
|
multilineUserPrompt,
|
|
multilineUserPrompt,
|
|
|
- councillorPrompt
|
|
|
|
|
|
|
+ councillorPrompt,
|
|
|
);
|
|
);
|
|
|
|
|
|
|
|
expect(formatted).toContain(councillorPrompt);
|
|
expect(formatted).toContain(councillorPrompt);
|
|
|
expect(formatted).toContain(multilineUserPrompt);
|
|
expect(formatted).toContain(multilineUserPrompt);
|
|
|
- expect(formatted).toContain("---");
|
|
|
|
|
|
|
+ expect(formatted).toContain('---');
|
|
|
expect(formatted).toMatch(
|
|
expect(formatted).toMatch(
|
|
|
new RegExp(
|
|
new RegExp(
|
|
|
`^${councillorPrompt.replace(
|
|
`^${councillorPrompt.replace(
|
|
|
/[.*+?^${}()|[\]\\]/g,
|
|
/[.*+?^${}()|[\]\\]/g,
|
|
|
- "\\$&"
|
|
|
|
|
|
|
+ '\\$&',
|
|
|
)}\\n\\n---\\n\\n${multilineUserPrompt.replace(
|
|
)}\\n\\n---\\n\\n${multilineUserPrompt.replace(
|
|
|
/[.*+?^${}()|[\]\\]/g,
|
|
/[.*+?^${}()|[\]\\]/g,
|
|
|
- "\\$&"
|
|
|
|
|
- )}$`
|
|
|
|
|
- )
|
|
|
|
|
|
|
+ '\\$&',
|
|
|
|
|
+ )}$`,
|
|
|
|
|
+ ),
|
|
|
);
|
|
);
|
|
|
});
|
|
});
|
|
|
});
|
|
});
|