fix(config): allow Sisyphus-Junior agent customization via oh-my-opencode.json (#648)

* fix(config): allow Sisyphus-Junior agent customization via oh-my-opencode.json

Allow users to configure Sisyphus-Junior agent via agents["Sisyphus-Junior"]
in oh-my-opencode.json, removing hardcoded defaults while preserving safety
constraints.
Closes #623
Changes:
- Add "Sisyphus-Junior" to AgentOverridesSchema and OverridableAgentNameSchema
- Create createSisyphusJuniorAgentWithOverrides() helper with guardrails
- Update config-handler to use override helper instead of hardcoded values
- Fix README category wording (runtime presets, not separate agents)
Honored override fields:
- model, temperature, top_p, tools, permission, description, color, prompt_append
Safety guardrails enforced post-merge:
- mode forced to "subagent" (cannot change)
- prompt is append-only (base discipline text preserved)
- blocked tools (task, sisyphus_task, call_omo_agent) always denied
- disable: true ignores override block, uses defaults
Category interaction:
- sisyphus_task(category=...) runs use the base Sisyphus-Junior agent config
- Category model/temperature overrides take precedence at request time
- To change model for a category, set categories.<cat>.model (not agent override)
- Categories are runtime presets applied to Sisyphus-Junior, not separate agents
Tests: 15 new tests in sisyphus-junior.test.ts, 3 new schema tests

Co-Authored-By: Sisyphus <sisyphus@mengmota.com>

* test(sisyphus-junior): add guard assertion for prompt anchor text

Add validation that baseEndIndex is not -1 before using it for ordering
assertion. Previously, if "Dense > verbose." text changed in the base
prompt, indexOf would return -1 and any positive appendIndex would pass.

Co-Authored-By: Sisyphus <sisyphus@mengmota.com>

---------

Co-authored-by: Sisyphus <sisyphus@mengmota.com>
This commit is contained in:
Ivan Marshall Widjaja
2026-01-12 19:46:47 +11:00
committed by GitHub
parent c79235744b
commit 0fada4d0fc
8 changed files with 502 additions and 7 deletions
+73
View File
@@ -315,3 +315,76 @@ describe("BuiltinCategoryNameSchema", () => {
}
})
})
describe("Sisyphus-Junior agent override", () => {
test("schema accepts agents['Sisyphus-Junior'] and retains the key after parsing", () => {
// #given
const config = {
agents: {
"Sisyphus-Junior": {
model: "openai/gpt-5.2",
temperature: 0.2,
},
},
}
// #when
const result = OhMyOpenCodeConfigSchema.safeParse(config)
// #then
expect(result.success).toBe(true)
if (result.success) {
expect(result.data.agents?.["Sisyphus-Junior"]).toBeDefined()
expect(result.data.agents?.["Sisyphus-Junior"]?.model).toBe("openai/gpt-5.2")
expect(result.data.agents?.["Sisyphus-Junior"]?.temperature).toBe(0.2)
}
})
test("schema accepts Sisyphus-Junior with prompt_append", () => {
// #given
const config = {
agents: {
"Sisyphus-Junior": {
prompt_append: "Additional instructions for Sisyphus-Junior",
},
},
}
// #when
const result = OhMyOpenCodeConfigSchema.safeParse(config)
// #then
expect(result.success).toBe(true)
if (result.success) {
expect(result.data.agents?.["Sisyphus-Junior"]?.prompt_append).toBe(
"Additional instructions for Sisyphus-Junior"
)
}
})
test("schema accepts Sisyphus-Junior with tools override", () => {
// #given
const config = {
agents: {
"Sisyphus-Junior": {
tools: {
read: true,
write: false,
},
},
},
}
// #when
const result = OhMyOpenCodeConfigSchema.safeParse(config)
// #then
expect(result.success).toBe(true)
if (result.success) {
expect(result.data.agents?.["Sisyphus-Junior"]?.tools).toEqual({
read: true,
write: false,
})
}
})
})
+2
View File
@@ -39,6 +39,7 @@ export const OverridableAgentNameSchema = z.enum([
"build",
"plan",
"Sisyphus",
"Sisyphus-Junior",
"OpenCode-Builder",
"Prometheus (Planner)",
"Metis (Plan Consultant)",
@@ -119,6 +120,7 @@ export const AgentOverridesSchema = z.object({
build: AgentOverrideConfigSchema.optional(),
plan: AgentOverrideConfigSchema.optional(),
Sisyphus: AgentOverrideConfigSchema.optional(),
"Sisyphus-Junior": AgentOverrideConfigSchema.optional(),
"OpenCode-Builder": AgentOverrideConfigSchema.optional(),
"Prometheus (Planner)": AgentOverrideConfigSchema.optional(),
"Metis (Plan Consultant)": AgentOverrideConfigSchema.optional(),