fix(athena): remove dead temperature/permission fields from council launch pipeline
LaunchInput.temperature and LaunchInput.permission were accepted and passed through the council orchestrator but never forwarded to the actual promptAsync API call (SDK doesn't support per-request temperature or permission). Remove the dead fields, the unused AthenaConfig interface, and update tests/docs/schema accordingly.
This commit is contained in:
parent
189bf89dc6
commit
13692c63d1
@ -3338,11 +3338,6 @@
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"minLength": 1
|
"minLength": 1
|
||||||
},
|
},
|
||||||
"temperature": {
|
|
||||||
"type": "number",
|
|
||||||
"minimum": 0,
|
|
||||||
"maximum": 2
|
|
||||||
},
|
|
||||||
"variant": {
|
"variant": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -11,8 +11,6 @@ interface MockLaunchInput {
|
|||||||
parentMessageID: string
|
parentMessageID: string
|
||||||
parentAgent?: string
|
parentAgent?: string
|
||||||
model?: { providerID: string; modelID: string; variant?: string }
|
model?: { providerID: string; modelID: string; variant?: string }
|
||||||
temperature?: number
|
|
||||||
permission?: Record<string, "ask" | "allow" | "deny">
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function createMockTask(id: string, launch: MockLaunchInput) {
|
function createMockTask(id: string, launch: MockLaunchInput) {
|
||||||
@ -68,7 +66,6 @@ describe("executeCouncil", () => {
|
|||||||
for (const launch of launches) {
|
for (const launch of launches) {
|
||||||
expect(launch.prompt).toBe(expectedPrompt)
|
expect(launch.prompt).toBe(expectedPrompt)
|
||||||
expect(launch.agent).toBe("athena")
|
expect(launch.agent).toBe("athena")
|
||||||
expect(launch.permission).toEqual({ write: "deny", edit: "deny", task: "deny", athena_council: "deny" })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(launches[0]?.model).toEqual({ providerID: "openai", modelID: "gpt-5.3-codex" })
|
expect(launches[0]?.model).toEqual({ providerID: "openai", modelID: "gpt-5.3-codex" })
|
||||||
@ -170,10 +167,10 @@ describe("executeCouncil", () => {
|
|||||||
expect(result.failures.find((f) => f.member.model === "invalid-model")?.error).toContain("Launch failed")
|
expect(result.failures.find((f) => f.member.model === "invalid-model")?.error).toContain("Launch failed")
|
||||||
})
|
})
|
||||||
|
|
||||||
//#given members with per-member temperature and variant
|
//#given members with per-member variant
|
||||||
//#when executeCouncil is called
|
//#when executeCouncil is called
|
||||||
//#then launch receives those values for each corresponding member
|
//#then launch receives variant in model for each corresponding member
|
||||||
test("passes member temperature and variant to launch input", async () => {
|
test("passes member variant to launch input model", async () => {
|
||||||
const launches: MockLaunchInput[] = []
|
const launches: MockLaunchInput[] = []
|
||||||
const launcher = {
|
const launcher = {
|
||||||
launch: async (input: MockLaunchInput) => {
|
launch: async (input: MockLaunchInput) => {
|
||||||
@ -186,8 +183,8 @@ describe("executeCouncil", () => {
|
|||||||
question: "Compare architecture options",
|
question: "Compare architecture options",
|
||||||
council: {
|
council: {
|
||||||
members: [
|
members: [
|
||||||
{ model: "openai/gpt-5.3-codex", temperature: 0.1, variant: "high" },
|
{ model: "openai/gpt-5.3-codex", variant: "high" },
|
||||||
{ model: "anthropic/claude-sonnet-4-5", temperature: 0.3 },
|
{ model: "anthropic/claude-sonnet-4-5" },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
launcher,
|
launcher,
|
||||||
@ -196,9 +193,7 @@ describe("executeCouncil", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
expect(launches).toHaveLength(2)
|
expect(launches).toHaveLength(2)
|
||||||
expect(launches[0]?.temperature).toBe(0.1)
|
|
||||||
expect(launches[0]?.model?.variant).toBe("high")
|
expect(launches[0]?.model?.variant).toBe("high")
|
||||||
expect(launches[1]?.temperature).toBe(0.3)
|
|
||||||
expect(launches[1]?.model?.variant).toBeUndefined()
|
expect(launches[1]?.model?.variant).toBeUndefined()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import type { LaunchInput, BackgroundTask } from "../../features/background-agent/types"
|
import type { LaunchInput, BackgroundTask } from "../../features/background-agent/types"
|
||||||
import { createAgentToolRestrictions } from "../../shared/permission-compat"
|
|
||||||
import { buildCouncilPrompt } from "./council-prompt"
|
import { buildCouncilPrompt } from "./council-prompt"
|
||||||
import { parseModelString } from "./model-parser"
|
import { parseModelString } from "./model-parser"
|
||||||
import type { CouncilConfig, CouncilLaunchFailure, CouncilLaunchedMember, CouncilLaunchResult, CouncilMemberConfig } from "./types"
|
import type { CouncilConfig, CouncilLaunchFailure, CouncilLaunchedMember, CouncilLaunchResult, CouncilMemberConfig } from "./types"
|
||||||
@ -72,7 +71,6 @@ async function launchMember(
|
|||||||
throw new Error(`Invalid model string: "${member.model}"`)
|
throw new Error(`Invalid model string: "${member.model}"`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const restrictions = createAgentToolRestrictions(["write", "edit", "task", "athena_council"])
|
|
||||||
const memberName = member.name ?? member.model
|
const memberName = member.name ?? member.model
|
||||||
return launcher.launch({
|
return launcher.launch({
|
||||||
description: `Council member: ${memberName}`,
|
description: `Council member: ${memberName}`,
|
||||||
@ -86,7 +84,5 @@ async function launchMember(
|
|||||||
modelID: parsedModel.modelID,
|
modelID: parsedModel.modelID,
|
||||||
...(member.variant ? { variant: member.variant } : {}),
|
...(member.variant ? { variant: member.variant } : {}),
|
||||||
},
|
},
|
||||||
...(member.temperature !== undefined ? { temperature: member.temperature } : {}),
|
|
||||||
permission: restrictions.permission,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
export interface CouncilMemberConfig {
|
export interface CouncilMemberConfig {
|
||||||
model: string
|
model: string
|
||||||
temperature?: number
|
|
||||||
variant?: string
|
variant?: string
|
||||||
name?: string
|
name?: string
|
||||||
}
|
}
|
||||||
@ -9,11 +8,6 @@ export interface CouncilConfig {
|
|||||||
members: CouncilMemberConfig[]
|
members: CouncilMemberConfig[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AthenaConfig {
|
|
||||||
model?: string
|
|
||||||
council: CouncilConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CouncilLaunchFailure {
|
export interface CouncilLaunchFailure {
|
||||||
member: CouncilMemberConfig
|
member: CouncilMemberConfig
|
||||||
error: string
|
error: string
|
||||||
|
|||||||
@ -18,7 +18,6 @@ describe("CouncilMemberSchema", () => {
|
|||||||
//#given
|
//#given
|
||||||
const config = {
|
const config = {
|
||||||
model: "openai/gpt-5.3-codex",
|
model: "openai/gpt-5.3-codex",
|
||||||
temperature: 0.4,
|
|
||||||
variant: "high",
|
variant: "high",
|
||||||
name: "analyst-a",
|
name: "analyst-a",
|
||||||
}
|
}
|
||||||
@ -32,7 +31,7 @@ describe("CouncilMemberSchema", () => {
|
|||||||
|
|
||||||
test("rejects member config missing model", () => {
|
test("rejects member config missing model", () => {
|
||||||
//#given
|
//#given
|
||||||
const config = { temperature: 0.5 }
|
const config = { name: "no-model" }
|
||||||
|
|
||||||
//#when
|
//#when
|
||||||
const result = CouncilMemberSchema.safeParse(config)
|
const result = CouncilMemberSchema.safeParse(config)
|
||||||
@ -85,34 +84,11 @@ describe("CouncilMemberSchema", () => {
|
|||||||
expect(result.success).toBe(false)
|
expect(result.success).toBe(false)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("rejects temperature below 0", () => {
|
|
||||||
//#given
|
|
||||||
const config = { model: "openai/gpt-5.3-codex", temperature: -0.1 }
|
|
||||||
|
|
||||||
//#when
|
|
||||||
const result = CouncilMemberSchema.safeParse(config)
|
|
||||||
|
|
||||||
//#then
|
|
||||||
expect(result.success).toBe(false)
|
|
||||||
})
|
|
||||||
|
|
||||||
test("rejects temperature above 2", () => {
|
|
||||||
//#given
|
|
||||||
const config = { model: "openai/gpt-5.3-codex", temperature: 2.1 }
|
|
||||||
|
|
||||||
//#when
|
|
||||||
const result = CouncilMemberSchema.safeParse(config)
|
|
||||||
|
|
||||||
//#then
|
|
||||||
expect(result.success).toBe(false)
|
|
||||||
})
|
|
||||||
|
|
||||||
test("z.infer produces expected type shape", () => {
|
test("z.infer produces expected type shape", () => {
|
||||||
//#given
|
//#given
|
||||||
type InferredCouncilMember = z.infer<typeof CouncilMemberSchema>
|
type InferredCouncilMember = z.infer<typeof CouncilMemberSchema>
|
||||||
const member: InferredCouncilMember = {
|
const member: InferredCouncilMember = {
|
||||||
model: "anthropic/claude-opus-4-6",
|
model: "anthropic/claude-opus-4-6",
|
||||||
temperature: 0.1,
|
|
||||||
variant: "medium",
|
variant: "medium",
|
||||||
name: "oracle",
|
name: "oracle",
|
||||||
}
|
}
|
||||||
@ -132,7 +108,6 @@ describe("CouncilMemberSchema", () => {
|
|||||||
const parsed = CouncilMemberSchema.parse(config)
|
const parsed = CouncilMemberSchema.parse(config)
|
||||||
|
|
||||||
//#then
|
//#then
|
||||||
expect(parsed.temperature).toBeUndefined()
|
|
||||||
expect(parsed.variant).toBeUndefined()
|
expect(parsed.variant).toBeUndefined()
|
||||||
expect(parsed.name).toBeUndefined()
|
expect(parsed.name).toBeUndefined()
|
||||||
})
|
})
|
||||||
@ -156,9 +131,9 @@ describe("CouncilConfigSchema", () => {
|
|||||||
//#given
|
//#given
|
||||||
const config = {
|
const config = {
|
||||||
members: [
|
members: [
|
||||||
{ model: "anthropic/claude-opus-4-6", name: "a", temperature: 0.1 },
|
{ model: "anthropic/claude-opus-4-6", name: "a" },
|
||||||
{ model: "openai/gpt-5.3-codex", name: "b", variant: "high" },
|
{ model: "openai/gpt-5.3-codex", name: "b", variant: "high" },
|
||||||
{ model: "xai/grok-code-fast-1", name: "c", temperature: 1.2, variant: "low" },
|
{ model: "xai/grok-code-fast-1", name: "c", variant: "low" },
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -14,7 +14,6 @@ const ModelStringSchema = z
|
|||||||
|
|
||||||
export const CouncilMemberSchema = z.object({
|
export const CouncilMemberSchema = z.object({
|
||||||
model: ModelStringSchema,
|
model: ModelStringSchema,
|
||||||
temperature: z.number().min(0).max(2).optional(),
|
|
||||||
variant: z.string().optional(),
|
variant: z.string().optional(),
|
||||||
name: z.string().optional(),
|
name: z.string().optional(),
|
||||||
})
|
})
|
||||||
|
|||||||
@ -72,10 +72,6 @@ export interface LaunchInput {
|
|||||||
skills?: string[]
|
skills?: string[]
|
||||||
skillContent?: string
|
skillContent?: string
|
||||||
category?: string
|
category?: string
|
||||||
/** Per-task temperature override for council members or custom launches */
|
|
||||||
temperature?: number
|
|
||||||
/** Tool permission overrides (e.g., { write: "deny", edit: "deny" }) */
|
|
||||||
permission?: Record<string, "ask" | "allow" | "deny">
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ResumeInput {
|
export interface ResumeInput {
|
||||||
|
|||||||
@ -16,10 +16,10 @@ function createMockTask(id: string): BackgroundTask {
|
|||||||
}
|
}
|
||||||
|
|
||||||
describe("createCouncilLauncher", () => {
|
describe("createCouncilLauncher", () => {
|
||||||
//#given a council launch input with temperature and permission
|
//#given a council launch input with all fields
|
||||||
//#when launch is called
|
//#when launch is called
|
||||||
//#then temperature and permission are forwarded to the background manager
|
//#then all fields are forwarded to the background manager
|
||||||
test("forwards temperature and permission to background manager", async () => {
|
test("forwards all launch input fields to background manager", async () => {
|
||||||
const capturedInputs: LaunchInput[] = []
|
const capturedInputs: LaunchInput[] = []
|
||||||
const mockManager = {
|
const mockManager = {
|
||||||
launch: async (input: LaunchInput) => {
|
launch: async (input: LaunchInput) => {
|
||||||
@ -38,40 +38,14 @@ describe("createCouncilLauncher", () => {
|
|||||||
parentSessionID: "session-1",
|
parentSessionID: "session-1",
|
||||||
parentMessageID: "message-1",
|
parentMessageID: "message-1",
|
||||||
model: { providerID: "openai", modelID: "gpt-5.3-codex" },
|
model: { providerID: "openai", modelID: "gpt-5.3-codex" },
|
||||||
temperature: 0.3,
|
|
||||||
permission: { write: "deny", edit: "deny", task: "deny" },
|
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(capturedInputs).toHaveLength(1)
|
expect(capturedInputs).toHaveLength(1)
|
||||||
expect(capturedInputs[0]?.temperature).toBe(0.3)
|
expect(capturedInputs[0]?.description).toBe("Council member: test")
|
||||||
expect(capturedInputs[0]?.permission).toEqual({ write: "deny", edit: "deny", task: "deny" })
|
expect(capturedInputs[0]?.prompt).toBe("Analyze this")
|
||||||
})
|
expect(capturedInputs[0]?.agent).toBe("athena")
|
||||||
|
expect(capturedInputs[0]?.parentSessionID).toBe("session-1")
|
||||||
//#given a council launch input without temperature and permission
|
expect(capturedInputs[0]?.parentMessageID).toBe("message-1")
|
||||||
//#when launch is called
|
expect(capturedInputs[0]?.model).toEqual({ providerID: "openai", modelID: "gpt-5.3-codex" })
|
||||||
//#then undefined temperature and permission are forwarded (not dropped)
|
|
||||||
test("forwards undefined temperature and permission without error", async () => {
|
|
||||||
const capturedInputs: LaunchInput[] = []
|
|
||||||
const mockManager = {
|
|
||||||
launch: async (input: LaunchInput) => {
|
|
||||||
capturedInputs.push(input)
|
|
||||||
return createMockTask("bg-2")
|
|
||||||
},
|
|
||||||
getTask: () => undefined,
|
|
||||||
} as unknown as BackgroundManager
|
|
||||||
|
|
||||||
const launcher = createCouncilLauncher(mockManager)
|
|
||||||
|
|
||||||
await launcher.launch({
|
|
||||||
description: "Council member: test",
|
|
||||||
prompt: "Analyze this",
|
|
||||||
agent: "athena",
|
|
||||||
parentSessionID: "session-1",
|
|
||||||
parentMessageID: "message-1",
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(capturedInputs).toHaveLength(1)
|
|
||||||
expect(capturedInputs[0]?.temperature).toBeUndefined()
|
|
||||||
expect(capturedInputs[0]?.permission).toBeUndefined()
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -12,8 +12,6 @@ export function createCouncilLauncher(manager: BackgroundManager): CouncilLaunch
|
|||||||
parentMessageID: input.parentMessageID,
|
parentMessageID: input.parentMessageID,
|
||||||
parentAgent: input.parentAgent,
|
parentAgent: input.parentAgent,
|
||||||
model: input.model,
|
model: input.model,
|
||||||
temperature: input.temperature,
|
|
||||||
permission: input.permission,
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user