diff --git a/src/agents/athena/index.ts b/src/agents/athena/index.ts new file mode 100644 index 000000000..123b68d15 --- /dev/null +++ b/src/agents/athena/index.ts @@ -0,0 +1,2 @@ +export * from "./types" +export * from "../../config/schema/athena" diff --git a/src/config/schema.test.ts b/src/config/schema.test.ts index 8a83fcd7d..72a6d780d 100644 --- a/src/config/schema.test.ts +++ b/src/config/schema.test.ts @@ -532,6 +532,76 @@ describe("Sisyphus-Junior agent override", () => { }) }) +describe("Athena agent override", () => { + test("accepts athena override with council members and standard override fields", () => { + // given + const config = { + agents: { + athena: { + model: "openai/gpt-5.3-codex", + temperature: 0.2, + prompt_append: "Use consensus-first synthesis.", + council: { + members: [ + { model: "openai/gpt-5.3-codex", temperature: 0.2, name: "Architect" }, + { model: "anthropic/claude-sonnet-4-5", temperature: 0.3, name: "Reviewer" }, + { model: "xai/grok-code-fast-1", temperature: 0.1, name: "Optimizer" }, + ], + }, + }, + }, + } + + // when + const result = OhMyOpenCodeConfigSchema.safeParse(config) + + // then + expect(result.success).toBe(true) + if (result.success) { + expect(result.data.agents?.athena?.model).toBe("openai/gpt-5.3-codex") + expect(result.data.agents?.athena?.temperature).toBe(0.2) + expect(result.data.agents?.athena?.prompt_append).toBe("Use consensus-first synthesis.") + expect(result.data.agents?.athena?.council.members).toHaveLength(3) + } + }) + + test("rejects athena override with fewer than two council members", () => { + // given + const config = { + agents: { + athena: { + council: { + members: [{ model: "openai/gpt-5.3-codex" }], + }, + }, + }, + } + + // when + const result = OhMyOpenCodeConfigSchema.safeParse(config) + + // then + expect(result.success).toBe(false) + }) + + test("rejects athena override when council is missing", () => { + // given + const config = { + agents: { + athena: { + model: "openai/gpt-5.3-codex", + }, + }, + } + + // when + const result = OhMyOpenCodeConfigSchema.safeParse(config) + + // then + expect(result.success).toBe(false) + }) +}) + describe("BrowserAutomationProviderSchema", () => { test("accepts 'playwright' as valid provider", () => { // given diff --git a/src/config/schema.ts b/src/config/schema.ts index 0d2c590ba..7b9cb295d 100644 --- a/src/config/schema.ts +++ b/src/config/schema.ts @@ -1,5 +1,6 @@ export * from "./schema/agent-names" export * from "./schema/agent-overrides" +export * from "./schema/athena" export * from "./schema/babysitting" export * from "./schema/background-task" export * from "./schema/browser-automation" diff --git a/src/config/schema/agent-overrides.ts b/src/config/schema/agent-overrides.ts index 7b3aa8d7a..4086c8a88 100644 --- a/src/config/schema/agent-overrides.ts +++ b/src/config/schema/agent-overrides.ts @@ -1,5 +1,6 @@ import { z } from "zod" import { FallbackModelsSchema } from "./fallback-models" +import { AthenaConfigSchema } from "./athena" import { AgentPermissionSchema } from "./internal/permission" export const AgentOverrideConfigSchema = z.object({ @@ -55,6 +56,12 @@ export const AgentOverrideConfigSchema = z.object({ .optional(), }) +export const AthenaOverrideConfigSchema = AgentOverrideConfigSchema.merge( + z.object({ + council: AthenaConfigSchema.shape.council, + }) +) + export const AgentOverridesSchema = z.object({ build: AgentOverrideConfigSchema.optional(), plan: AgentOverrideConfigSchema.optional(), @@ -70,6 +77,7 @@ export const AgentOverridesSchema = z.object({ explore: AgentOverrideConfigSchema.optional(), "multimodal-looker": AgentOverrideConfigSchema.optional(), atlas: AgentOverrideConfigSchema.optional(), + athena: AthenaOverrideConfigSchema.optional(), }) export type AgentOverrideConfig = z.infer