test: add tests for council config schema, prompt content, and config injection
This commit is contained in:
@@ -0,0 +1,26 @@
|
|||||||
|
import { describe, expect, it } from "bun:test"
|
||||||
|
import { createAthenaAgent } from "./agent"
|
||||||
|
|
||||||
|
describe("Athena prompt config injection placeholders", () => {
|
||||||
|
const athenaConfig = createAthenaAgent("anthropic/claude-opus-4-6")
|
||||||
|
|
||||||
|
describe("#given the Athena agent prompt", () => {
|
||||||
|
describe("#when checking for runtime injection placeholders", () => {
|
||||||
|
it("#then contains RETRY_ON_FAIL placeholder", () => {
|
||||||
|
expect(athenaConfig.prompt).toContain("{RETRY_ON_FAIL}")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("#then contains STUCK_THRESHOLD_SECONDS placeholder", () => {
|
||||||
|
expect(athenaConfig.prompt).toContain("{STUCK_THRESHOLD_SECONDS}")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("#then contains quorum reference", () => {
|
||||||
|
expect(athenaConfig.prompt).toContain("quorum")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("#then contains timeout reference with 30000", () => {
|
||||||
|
expect(athenaConfig.prompt).toContain("30000")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import { describe, expect, it } from "bun:test"
|
||||||
|
import { COUNCIL_MEMBER_PROMPT } from "./council-member-agent"
|
||||||
|
|
||||||
|
describe("COUNCIL_MEMBER_PROMPT", () => {
|
||||||
|
describe("#given the prompt constant", () => {
|
||||||
|
describe("#when checking for required tag instructions", () => {
|
||||||
|
it("#then contains COUNCIL_MEMBER_RESPONSE tag name", () => {
|
||||||
|
expect(COUNCIL_MEMBER_PROMPT).toContain("COUNCIL_MEMBER_RESPONSE")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("#then contains Response Format section header", () => {
|
||||||
|
expect(COUNCIL_MEMBER_PROMPT).toContain("Response Format")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("#then contains opening tag example", () => {
|
||||||
|
expect(COUNCIL_MEMBER_PROMPT).toContain("<COUNCIL_MEMBER_RESPONSE>")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("#then contains closing tag example", () => {
|
||||||
|
expect(COUNCIL_MEMBER_PROMPT).toContain("</COUNCIL_MEMBER_RESPONSE>")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -9,6 +9,10 @@ describe("council-member-agents", () => {
|
|||||||
{ model: "openai/gpt-5.3-codex", name: "GPT" },
|
{ model: "openai/gpt-5.3-codex", name: "GPT" },
|
||||||
{ model: "anthropic/claude-opus-4-6", name: "gpt" },
|
{ model: "anthropic/claude-opus-4-6", name: "gpt" },
|
||||||
],
|
],
|
||||||
|
retry_on_fail: 0,
|
||||||
|
retry_failed_if_others_finished: false,
|
||||||
|
cancel_retrying_on_quorum: true,
|
||||||
|
stuck_threshold_seconds: 120,
|
||||||
}
|
}
|
||||||
//#when
|
//#when
|
||||||
const result = registerCouncilMemberAgents(config)
|
const result = registerCouncilMemberAgents(config)
|
||||||
@@ -24,6 +28,10 @@ describe("council-member-agents", () => {
|
|||||||
{ model: "openai/gpt-5.3-codex", name: "GPT" },
|
{ model: "openai/gpt-5.3-codex", name: "GPT" },
|
||||||
{ model: "anthropic/claude-opus-4-6", name: "Claude" },
|
{ model: "anthropic/claude-opus-4-6", name: "Claude" },
|
||||||
],
|
],
|
||||||
|
retry_on_fail: 0,
|
||||||
|
retry_failed_if_others_finished: false,
|
||||||
|
cancel_retrying_on_quorum: true,
|
||||||
|
stuck_threshold_seconds: 120,
|
||||||
}
|
}
|
||||||
//#when
|
//#when
|
||||||
const result = registerCouncilMemberAgents(config)
|
const result = registerCouncilMemberAgents(config)
|
||||||
@@ -40,6 +48,10 @@ describe("council-member-agents", () => {
|
|||||||
{ model: "openai/gpt-5.3-codex", name: "GPT Codex" },
|
{ model: "openai/gpt-5.3-codex", name: "GPT Codex" },
|
||||||
{ model: "openai/gpt-5.3-codex", name: "Codex GPT" },
|
{ model: "openai/gpt-5.3-codex", name: "Codex GPT" },
|
||||||
],
|
],
|
||||||
|
retry_on_fail: 0,
|
||||||
|
retry_failed_if_others_finished: false,
|
||||||
|
cancel_retrying_on_quorum: true,
|
||||||
|
stuck_threshold_seconds: 120,
|
||||||
}
|
}
|
||||||
//#when
|
//#when
|
||||||
const result = registerCouncilMemberAgents(config)
|
const result = registerCouncilMemberAgents(config)
|
||||||
@@ -56,6 +68,10 @@ describe("council-member-agents", () => {
|
|||||||
{ model: "openai/gpt-5.3-codex", name: "GPT" },
|
{ model: "openai/gpt-5.3-codex", name: "GPT" },
|
||||||
{ model: "invalid-no-slash", name: "Invalid" },
|
{ model: "invalid-no-slash", name: "Invalid" },
|
||||||
],
|
],
|
||||||
|
retry_on_fail: 0,
|
||||||
|
retry_failed_if_others_finished: false,
|
||||||
|
cancel_retrying_on_quorum: true,
|
||||||
|
stuck_threshold_seconds: 120,
|
||||||
}
|
}
|
||||||
//#when
|
//#when
|
||||||
const result = registerCouncilMemberAgents(config)
|
const result = registerCouncilMemberAgents(config)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { describe, expect, test } from "bun:test"
|
import { describe, expect, it, test } from "bun:test"
|
||||||
import { z } from "zod"
|
import { z } from "zod"
|
||||||
import { AthenaConfigSchema, CouncilConfigSchema, CouncilMemberSchema } from "./athena"
|
import { AthenaConfigSchema, CouncilConfigSchema, CouncilMemberSchema } from "./athena"
|
||||||
|
|
||||||
@@ -429,3 +429,104 @@ describe("AthenaConfigSchema", () => {
|
|||||||
expect(result.success).toBe(false)
|
expect(result.success).toBe(false)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("CouncilConfigSchema — resilience fields", () => {
|
||||||
|
const validMembers = [
|
||||||
|
{ model: "openai/gpt-5.3-codex", name: "member-a" },
|
||||||
|
{ model: "anthropic/claude-opus-4-6", name: "member-b" },
|
||||||
|
]
|
||||||
|
|
||||||
|
describe("#given minimal config with only members", () => {
|
||||||
|
describe("#when parsed", () => {
|
||||||
|
it("#then applies default retry_on_fail of 0", () => {
|
||||||
|
const result = CouncilConfigSchema.safeParse({ members: validMembers })
|
||||||
|
expect(result.success).toBe(true)
|
||||||
|
if (result.success) {
|
||||||
|
expect(result.data.retry_on_fail).toBe(0)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it("#then applies default retry_failed_if_others_finished of false", () => {
|
||||||
|
const result = CouncilConfigSchema.safeParse({ members: validMembers })
|
||||||
|
expect(result.success).toBe(true)
|
||||||
|
if (result.success) {
|
||||||
|
expect(result.data.retry_failed_if_others_finished).toBe(false)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it("#then applies default cancel_retrying_on_quorum of true", () => {
|
||||||
|
const result = CouncilConfigSchema.safeParse({ members: validMembers })
|
||||||
|
expect(result.success).toBe(true)
|
||||||
|
if (result.success) {
|
||||||
|
expect(result.data.cancel_retrying_on_quorum).toBe(true)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it("#then applies default stuck_threshold_seconds of 120", () => {
|
||||||
|
const result = CouncilConfigSchema.safeParse({ members: validMembers })
|
||||||
|
expect(result.success).toBe(true)
|
||||||
|
if (result.success) {
|
||||||
|
expect(result.data.stuck_threshold_seconds).toBe(120)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("#given config with all resilience fields set", () => {
|
||||||
|
describe("#when parsed", () => {
|
||||||
|
it("#then uses provided values instead of defaults", () => {
|
||||||
|
const config = {
|
||||||
|
members: validMembers,
|
||||||
|
retry_on_fail: 3,
|
||||||
|
retry_failed_if_others_finished: true,
|
||||||
|
cancel_retrying_on_quorum: false,
|
||||||
|
stuck_threshold_seconds: 60,
|
||||||
|
}
|
||||||
|
const result = CouncilConfigSchema.safeParse(config)
|
||||||
|
expect(result.success).toBe(true)
|
||||||
|
if (result.success) {
|
||||||
|
expect(result.data.retry_on_fail).toBe(3)
|
||||||
|
expect(result.data.retry_failed_if_others_finished).toBe(true)
|
||||||
|
expect(result.data.cancel_retrying_on_quorum).toBe(false)
|
||||||
|
expect(result.data.stuck_threshold_seconds).toBe(60)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("#given retry_on_fail below minimum", () => {
|
||||||
|
describe("#when parsed with -1", () => {
|
||||||
|
it("#then fails validation", () => {
|
||||||
|
const result = CouncilConfigSchema.safeParse({ members: validMembers, retry_on_fail: -1 })
|
||||||
|
expect(result.success).toBe(false)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("#given retry_on_fail above maximum", () => {
|
||||||
|
describe("#when parsed with 6", () => {
|
||||||
|
it("#then fails validation", () => {
|
||||||
|
const result = CouncilConfigSchema.safeParse({ members: validMembers, retry_on_fail: 6 })
|
||||||
|
expect(result.success).toBe(false)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("#given stuck_threshold_seconds below minimum", () => {
|
||||||
|
describe("#when parsed with 10", () => {
|
||||||
|
it("#then fails validation", () => {
|
||||||
|
const result = CouncilConfigSchema.safeParse({ members: validMembers, stuck_threshold_seconds: 10 })
|
||||||
|
expect(result.success).toBe(false)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("#given backward-compatible config with only members", () => {
|
||||||
|
describe("#when parsed", () => {
|
||||||
|
it("#then succeeds without errors — new fields are optional", () => {
|
||||||
|
const result = CouncilConfigSchema.safeParse({ members: validMembers })
|
||||||
|
expect(result.success).toBe(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user