fix(team-mode): reject incomplete hyperplan teams
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -26,6 +26,17 @@ function createCategoryMember(name: string): Member {
|
||||
}
|
||||
}
|
||||
|
||||
function createHyperplanMember(name: string, category: string): Member {
|
||||
return {
|
||||
kind: "category",
|
||||
name,
|
||||
category,
|
||||
prompt: `perform the ${name} adversarial role`,
|
||||
backendType: "in-process",
|
||||
isActive: true,
|
||||
}
|
||||
}
|
||||
|
||||
function createBaseTeamSpec(): TeamSpec {
|
||||
return {
|
||||
version: 1,
|
||||
@@ -146,6 +157,48 @@ describe("team-registry validator", () => {
|
||||
expect(act).toThrow("Team 'validator-team' exceeds max 8 members.")
|
||||
})
|
||||
|
||||
test("rejects hyperplan teams that omit required adversarial categories", () => {
|
||||
// given
|
||||
const teamSpec: TeamSpec = {
|
||||
version: 1,
|
||||
name: "hyperplan",
|
||||
createdAt: 1,
|
||||
leadAgentId: "architect",
|
||||
members: [
|
||||
createHyperplanMember("researcher", "deep"),
|
||||
createHyperplanMember("architect", "ultrabrain"),
|
||||
],
|
||||
}
|
||||
|
||||
// when
|
||||
const act = () => validateSpec(teamSpec)
|
||||
|
||||
// then
|
||||
expect(act).toThrow("Hyperplan team must include category 'unspecified-low'.")
|
||||
})
|
||||
|
||||
test("accepts hyperplan teams with required adversarial categories and optional deep", () => {
|
||||
// given
|
||||
const teamSpec: TeamSpec = {
|
||||
version: 1,
|
||||
name: "hyperplan",
|
||||
createdAt: 1,
|
||||
leadAgentId: "architect",
|
||||
members: [
|
||||
createHyperplanMember("skeptic", "unspecified-low"),
|
||||
createHyperplanMember("validator", "unspecified-high"),
|
||||
createHyperplanMember("architect", "ultrabrain"),
|
||||
createHyperplanMember("creative", "artistry"),
|
||||
],
|
||||
}
|
||||
|
||||
// when
|
||||
const act = () => validateSpec(teamSpec)
|
||||
|
||||
// then
|
||||
expect(act).not.toThrow()
|
||||
})
|
||||
|
||||
test("rejects category prompts that collapse to empty text", () => {
|
||||
// given
|
||||
const member: Member = {
|
||||
|
||||
@@ -3,6 +3,12 @@ import { AGENT_ELIGIBILITY_REGISTRY } from "../types"
|
||||
import type { Member, TeamSpec } from "../types"
|
||||
|
||||
const MAX_TEAM_MEMBERS = 8
|
||||
const HYPERPLAN_REQUIRED_CATEGORIES = [
|
||||
"unspecified-low",
|
||||
"unspecified-high",
|
||||
"ultrabrain",
|
||||
"artistry",
|
||||
] as const
|
||||
const UNKNOWN_SUBAGENT_MESSAGE =
|
||||
"Unknown subagent_type '<name>'. Available ELIGIBLE agents: sisyphus, atlas, sisyphus-junior, hephaestus (if D-36 applied). Use delegate-task for read-only agents like oracle, librarian, explore, metis, momus, multimodal-looker."
|
||||
|
||||
@@ -56,6 +62,30 @@ export function validateSpec(spec: TeamSpec): void {
|
||||
"leadAgentId",
|
||||
)
|
||||
}
|
||||
|
||||
validateHyperplanComposition(spec)
|
||||
}
|
||||
|
||||
function validateHyperplanComposition(spec: TeamSpec): void {
|
||||
if (spec.name !== "hyperplan") {
|
||||
return
|
||||
}
|
||||
|
||||
const categories = new Set(
|
||||
spec.members
|
||||
.filter((member) => member.kind === "category")
|
||||
.map((member) => member.category),
|
||||
)
|
||||
|
||||
for (const category of HYPERPLAN_REQUIRED_CATEGORIES) {
|
||||
if (!categories.has(category)) {
|
||||
throw new TeamSpecValidationError(
|
||||
`Hyperplan team must include category '${category}'.`,
|
||||
"HYPERPLAN_REQUIRED_CATEGORY_MISSING",
|
||||
"members",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function validateMemberEligibility(member: Member): void {
|
||||
|
||||
Reference in New Issue
Block a user