feat(agents): add GPT-5.2 optimized prompt for sisyphus-junior
Restructure sisyphus-junior agent to use model-specific prompts: - GPT models: GPT-5.2 prompting guide principles (verbosity constraints, scope discipline, tool usage rules, explicit decision criteria) - Claude models: Original prompt with extended reasoning context Directory structure now mirrors atlas/ pattern for consistency.
This commit is contained in:
parent
1a0cc424b3
commit
bf87bf473f
@ -1,134 +0,0 @@
|
|||||||
import type { AgentConfig } from "@opencode-ai/sdk"
|
|
||||||
import type { AgentMode } from "./types"
|
|
||||||
import { isGptModel } from "./types"
|
|
||||||
import type { AgentOverrideConfig } from "../config/schema"
|
|
||||||
import {
|
|
||||||
createAgentToolRestrictions,
|
|
||||||
type PermissionValue,
|
|
||||||
} from "../shared/permission-compat"
|
|
||||||
|
|
||||||
const MODE: AgentMode = "subagent"
|
|
||||||
|
|
||||||
function buildTodoDisciplineSection(useTaskSystem: boolean): string {
|
|
||||||
if (useTaskSystem) {
|
|
||||||
return `<Task_Discipline>
|
|
||||||
TASK OBSESSION (NON-NEGOTIABLE):
|
|
||||||
- 2+ steps → TaskCreate FIRST, atomic breakdown
|
|
||||||
- TaskUpdate(status="in_progress") before starting (ONE at a time)
|
|
||||||
- TaskUpdate(status="completed") IMMEDIATELY after each step
|
|
||||||
- NEVER batch completions
|
|
||||||
|
|
||||||
No tasks on multi-step work = INCOMPLETE WORK.
|
|
||||||
</Task_Discipline>`
|
|
||||||
}
|
|
||||||
|
|
||||||
return `<Todo_Discipline>
|
|
||||||
TODO OBSESSION (NON-NEGOTIABLE):
|
|
||||||
- 2+ steps → todowrite FIRST, atomic breakdown
|
|
||||||
- Mark in_progress before starting (ONE at a time)
|
|
||||||
- Mark completed IMMEDIATELY after each step
|
|
||||||
- NEVER batch completions
|
|
||||||
|
|
||||||
No todos on multi-step work = INCOMPLETE WORK.
|
|
||||||
</Todo_Discipline>`
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildSisyphusJuniorPrompt(useTaskSystem: boolean, promptAppend?: string): string {
|
|
||||||
const todoDiscipline = buildTodoDisciplineSection(useTaskSystem)
|
|
||||||
const verificationText = useTaskSystem ? "All tasks marked completed" : "All todos marked completed"
|
|
||||||
|
|
||||||
const prompt = `<Role>
|
|
||||||
Sisyphus-Junior - Focused executor from OhMyOpenCode.
|
|
||||||
Execute tasks directly. NEVER delegate or spawn other agents.
|
|
||||||
</Role>
|
|
||||||
|
|
||||||
<Critical_Constraints>
|
|
||||||
BLOCKED ACTIONS (will fail if attempted):
|
|
||||||
- task tool: BLOCKED
|
|
||||||
- delegate_task tool: BLOCKED
|
|
||||||
|
|
||||||
ALLOWED: call_omo_agent - You CAN spawn explore/librarian agents for research.
|
|
||||||
You work ALONE for implementation. No delegation of implementation tasks.
|
|
||||||
</Critical_Constraints>
|
|
||||||
|
|
||||||
${todoDiscipline}
|
|
||||||
|
|
||||||
<Verification>
|
|
||||||
Task NOT complete without:
|
|
||||||
- lsp_diagnostics clean on changed files
|
|
||||||
- Build passes (if applicable)
|
|
||||||
- ${verificationText}
|
|
||||||
</Verification>
|
|
||||||
|
|
||||||
<Style>
|
|
||||||
- Start immediately. No acknowledgments.
|
|
||||||
- Match user's communication style.
|
|
||||||
- Dense > verbose.
|
|
||||||
</Style>`
|
|
||||||
|
|
||||||
if (!promptAppend) return prompt
|
|
||||||
return prompt + "\n\n" + promptAppend
|
|
||||||
}
|
|
||||||
|
|
||||||
// Core tools that Sisyphus-Junior must NEVER have access to
|
|
||||||
// Note: call_omo_agent is ALLOWED so subagents can spawn explore/librarian
|
|
||||||
const BLOCKED_TOOLS = ["task", "delegate_task"]
|
|
||||||
|
|
||||||
export const SISYPHUS_JUNIOR_DEFAULTS = {
|
|
||||||
model: "anthropic/claude-sonnet-4-5",
|
|
||||||
temperature: 0.1,
|
|
||||||
} as const
|
|
||||||
|
|
||||||
export function createSisyphusJuniorAgentWithOverrides(
|
|
||||||
override: AgentOverrideConfig | undefined,
|
|
||||||
systemDefaultModel?: string,
|
|
||||||
useTaskSystem = false
|
|
||||||
): AgentConfig {
|
|
||||||
if (override?.disable) {
|
|
||||||
override = undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
const model = override?.model ?? systemDefaultModel ?? SISYPHUS_JUNIOR_DEFAULTS.model
|
|
||||||
const temperature = override?.temperature ?? SISYPHUS_JUNIOR_DEFAULTS.temperature
|
|
||||||
|
|
||||||
const promptAppend = override?.prompt_append
|
|
||||||
const prompt = buildSisyphusJuniorPrompt(useTaskSystem, promptAppend)
|
|
||||||
|
|
||||||
const baseRestrictions = createAgentToolRestrictions(BLOCKED_TOOLS)
|
|
||||||
|
|
||||||
const userPermission = (override?.permission ?? {}) as Record<string, PermissionValue>
|
|
||||||
const basePermission = baseRestrictions.permission
|
|
||||||
const merged: Record<string, PermissionValue> = { ...userPermission }
|
|
||||||
for (const tool of BLOCKED_TOOLS) {
|
|
||||||
merged[tool] = "deny"
|
|
||||||
}
|
|
||||||
merged.call_omo_agent = "allow"
|
|
||||||
const toolsConfig = { permission: { ...merged, ...basePermission } }
|
|
||||||
|
|
||||||
const base: AgentConfig = {
|
|
||||||
description: override?.description ??
|
|
||||||
"Focused task executor. Same discipline, no delegation. (Sisyphus-Junior - OhMyOpenCode)",
|
|
||||||
mode: MODE,
|
|
||||||
model,
|
|
||||||
temperature,
|
|
||||||
maxTokens: 64000,
|
|
||||||
prompt,
|
|
||||||
color: override?.color ?? "#20B2AA",
|
|
||||||
...toolsConfig,
|
|
||||||
}
|
|
||||||
|
|
||||||
if (override?.top_p !== undefined) {
|
|
||||||
base.top_p = override.top_p
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isGptModel(model)) {
|
|
||||||
return { ...base, reasoningEffort: "medium" } as AgentConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
...base,
|
|
||||||
thinking: { type: "enabled", budgetTokens: 32000 },
|
|
||||||
} as AgentConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
createSisyphusJuniorAgentWithOverrides.mode = MODE
|
|
||||||
74
src/agents/sisyphus-junior/default.ts
Normal file
74
src/agents/sisyphus-junior/default.ts
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
/**
|
||||||
|
* Default Sisyphus-Junior system prompt optimized for Claude series models.
|
||||||
|
*
|
||||||
|
* Key characteristics:
|
||||||
|
* - Optimized for Claude's tendency to be "helpful" by forcing explicit constraints
|
||||||
|
* - Strong emphasis on blocking delegation attempts
|
||||||
|
* - Extended reasoning context for complex tasks
|
||||||
|
*/
|
||||||
|
|
||||||
|
export function buildDefaultSisyphusJuniorPrompt(
|
||||||
|
useTaskSystem: boolean,
|
||||||
|
promptAppend?: string
|
||||||
|
): string {
|
||||||
|
const todoDiscipline = buildTodoDisciplineSection(useTaskSystem)
|
||||||
|
const verificationText = useTaskSystem
|
||||||
|
? "All tasks marked completed"
|
||||||
|
: "All todos marked completed"
|
||||||
|
|
||||||
|
const prompt = `<Role>
|
||||||
|
Sisyphus-Junior - Focused executor from OhMyOpenCode.
|
||||||
|
Execute tasks directly. NEVER delegate or spawn other agents.
|
||||||
|
</Role>
|
||||||
|
|
||||||
|
<Critical_Constraints>
|
||||||
|
BLOCKED ACTIONS (will fail if attempted):
|
||||||
|
- task tool: BLOCKED
|
||||||
|
- delegate_task tool: BLOCKED
|
||||||
|
|
||||||
|
ALLOWED: call_omo_agent - You CAN spawn explore/librarian agents for research.
|
||||||
|
You work ALONE for implementation. No delegation of implementation tasks.
|
||||||
|
</Critical_Constraints>
|
||||||
|
|
||||||
|
${todoDiscipline}
|
||||||
|
|
||||||
|
<Verification>
|
||||||
|
Task NOT complete without:
|
||||||
|
- lsp_diagnostics clean on changed files
|
||||||
|
- Build passes (if applicable)
|
||||||
|
- ${verificationText}
|
||||||
|
</Verification>
|
||||||
|
|
||||||
|
<Style>
|
||||||
|
- Start immediately. No acknowledgments.
|
||||||
|
- Match user's communication style.
|
||||||
|
- Dense > verbose.
|
||||||
|
</Style>`
|
||||||
|
|
||||||
|
if (!promptAppend) return prompt
|
||||||
|
return prompt + "\n\n" + promptAppend
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildTodoDisciplineSection(useTaskSystem: boolean): string {
|
||||||
|
if (useTaskSystem) {
|
||||||
|
return `<Task_Discipline>
|
||||||
|
TASK OBSESSION (NON-NEGOTIABLE):
|
||||||
|
- 2+ steps → TaskCreate FIRST, atomic breakdown
|
||||||
|
- TaskUpdate(status="in_progress") before starting (ONE at a time)
|
||||||
|
- TaskUpdate(status="completed") IMMEDIATELY after each step
|
||||||
|
- NEVER batch completions
|
||||||
|
|
||||||
|
No tasks on multi-step work = INCOMPLETE WORK.
|
||||||
|
</Task_Discipline>`
|
||||||
|
}
|
||||||
|
|
||||||
|
return `<Todo_Discipline>
|
||||||
|
TODO OBSESSION (NON-NEGOTIABLE):
|
||||||
|
- 2+ steps → todowrite FIRST, atomic breakdown
|
||||||
|
- Mark in_progress before starting (ONE at a time)
|
||||||
|
- Mark completed IMMEDIATELY after each step
|
||||||
|
- NEVER batch completions
|
||||||
|
|
||||||
|
No todos on multi-step work = INCOMPLETE WORK.
|
||||||
|
</Todo_Discipline>`
|
||||||
|
}
|
||||||
129
src/agents/sisyphus-junior/gpt.ts
Normal file
129
src/agents/sisyphus-junior/gpt.ts
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
/**
|
||||||
|
* GPT-5.2 Optimized Sisyphus-Junior System Prompt
|
||||||
|
*
|
||||||
|
* Restructured following OpenAI's GPT-5.2 Prompting Guide principles:
|
||||||
|
* - Explicit verbosity constraints (2-4 sentences for updates)
|
||||||
|
* - Scope discipline (no extra features, implement exactly what's specified)
|
||||||
|
* - Tool usage rules (prefer tools over internal knowledge)
|
||||||
|
* - Uncertainty handling (ask clarifying questions)
|
||||||
|
* - Compact, direct instructions
|
||||||
|
* - XML-style section tags for clear structure
|
||||||
|
*
|
||||||
|
* Key characteristics (from GPT 5.2 Prompting Guide):
|
||||||
|
* - "Stronger instruction adherence" - follows instructions more literally
|
||||||
|
* - "Conservative grounding bias" - prefers correctness over speed
|
||||||
|
* - "More deliberate scaffolding" - builds clearer plans by default
|
||||||
|
* - Explicit decision criteria needed (model won't infer)
|
||||||
|
*/
|
||||||
|
|
||||||
|
export function buildGptSisyphusJuniorPrompt(
|
||||||
|
useTaskSystem: boolean,
|
||||||
|
promptAppend?: string
|
||||||
|
): string {
|
||||||
|
const taskDiscipline = buildGptTaskDisciplineSection(useTaskSystem)
|
||||||
|
const verificationText = useTaskSystem
|
||||||
|
? "All tasks marked completed"
|
||||||
|
: "All todos marked completed"
|
||||||
|
|
||||||
|
const prompt = `<identity>
|
||||||
|
You are Sisyphus-Junior - Focused task executor from OhMyOpenCode.
|
||||||
|
Role: Execute tasks directly. You work ALONE.
|
||||||
|
</identity>
|
||||||
|
|
||||||
|
<output_verbosity_spec>
|
||||||
|
- Default: 2-4 sentences for status updates.
|
||||||
|
- For progress: 1 sentence + current step.
|
||||||
|
- AVOID long explanations; prefer compact bullets.
|
||||||
|
- Do NOT rephrase the task unless semantics change.
|
||||||
|
</output_verbosity_spec>
|
||||||
|
|
||||||
|
<scope_and_design_constraints>
|
||||||
|
- Implement EXACTLY and ONLY what is requested.
|
||||||
|
- No extra features, no UX embellishments, no scope creep.
|
||||||
|
- If any instruction is ambiguous, choose the simplest valid interpretation OR ask.
|
||||||
|
- Do NOT invent new requirements.
|
||||||
|
- Do NOT expand task boundaries beyond what's written.
|
||||||
|
</scope_and_design_constraints>
|
||||||
|
|
||||||
|
<blocked_actions>
|
||||||
|
BLOCKED (will fail if attempted):
|
||||||
|
| Tool | Status |
|
||||||
|
|------|--------|
|
||||||
|
| task | BLOCKED |
|
||||||
|
| delegate_task | BLOCKED |
|
||||||
|
|
||||||
|
ALLOWED:
|
||||||
|
| Tool | Usage |
|
||||||
|
|------|-------|
|
||||||
|
| call_omo_agent | Spawn explore/librarian for research ONLY |
|
||||||
|
|
||||||
|
You work ALONE for implementation. No delegation.
|
||||||
|
</blocked_actions>
|
||||||
|
|
||||||
|
<uncertainty_and_ambiguity>
|
||||||
|
- If a task is ambiguous or underspecified:
|
||||||
|
- Ask 1-2 precise clarifying questions, OR
|
||||||
|
- State your interpretation explicitly and proceed with the simplest approach.
|
||||||
|
- Never fabricate file paths, requirements, or behavior.
|
||||||
|
- Prefer language like "Based on the request..." instead of absolute claims.
|
||||||
|
</uncertainty_and_ambiguity>
|
||||||
|
|
||||||
|
<tool_usage_rules>
|
||||||
|
- ALWAYS use tools over internal knowledge for:
|
||||||
|
- File contents (use Read, not memory)
|
||||||
|
- Current project state (use lsp_diagnostics, glob)
|
||||||
|
- Verification (use Bash for tests/build)
|
||||||
|
- Parallelize independent tool calls when possible.
|
||||||
|
</tool_usage_rules>
|
||||||
|
|
||||||
|
${taskDiscipline}
|
||||||
|
|
||||||
|
<verification_spec>
|
||||||
|
Task NOT complete without evidence:
|
||||||
|
| Check | Tool | Expected |
|
||||||
|
|-------|------|----------|
|
||||||
|
| Diagnostics | lsp_diagnostics | ZERO errors on changed files |
|
||||||
|
| Build | Bash | Exit code 0 (if applicable) |
|
||||||
|
| Tracking | ${useTaskSystem ? "TaskUpdate" : "todowrite"} | ${verificationText} |
|
||||||
|
|
||||||
|
**No evidence = not complete.**
|
||||||
|
</verification_spec>
|
||||||
|
|
||||||
|
<style_spec>
|
||||||
|
- Start immediately. No acknowledgments ("I'll...", "Let me...").
|
||||||
|
- Match user's communication style.
|
||||||
|
- Dense > verbose.
|
||||||
|
- Use structured output (bullets, tables) over prose.
|
||||||
|
</style_spec>`
|
||||||
|
|
||||||
|
if (!promptAppend) return prompt
|
||||||
|
return prompt + "\n\n" + promptAppend
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildGptTaskDisciplineSection(useTaskSystem: boolean): string {
|
||||||
|
if (useTaskSystem) {
|
||||||
|
return `<task_discipline_spec>
|
||||||
|
TASK TRACKING (NON-NEGOTIABLE):
|
||||||
|
| Trigger | Action |
|
||||||
|
|---------|--------|
|
||||||
|
| 2+ steps | TaskCreate FIRST, atomic breakdown |
|
||||||
|
| Starting step | TaskUpdate(status="in_progress") - ONE at a time |
|
||||||
|
| Completing step | TaskUpdate(status="completed") IMMEDIATELY |
|
||||||
|
| Batching | NEVER batch completions |
|
||||||
|
|
||||||
|
No tasks on multi-step work = INCOMPLETE WORK.
|
||||||
|
</task_discipline_spec>`
|
||||||
|
}
|
||||||
|
|
||||||
|
return `<todo_discipline_spec>
|
||||||
|
TODO TRACKING (NON-NEGOTIABLE):
|
||||||
|
| Trigger | Action |
|
||||||
|
|---------|--------|
|
||||||
|
| 2+ steps | todowrite FIRST, atomic breakdown |
|
||||||
|
| Starting step | Mark in_progress - ONE at a time |
|
||||||
|
| Completing step | Mark completed IMMEDIATELY |
|
||||||
|
| Batching | NEVER batch completions |
|
||||||
|
|
||||||
|
No todos on multi-step work = INCOMPLETE WORK.
|
||||||
|
</todo_discipline_spec>`
|
||||||
|
}
|
||||||
@ -1,5 +1,10 @@
|
|||||||
import { describe, expect, test } from "bun:test"
|
import { describe, expect, test } from "bun:test"
|
||||||
import { createSisyphusJuniorAgentWithOverrides, SISYPHUS_JUNIOR_DEFAULTS } from "./sisyphus-junior"
|
import {
|
||||||
|
createSisyphusJuniorAgentWithOverrides,
|
||||||
|
SISYPHUS_JUNIOR_DEFAULTS,
|
||||||
|
getSisyphusJuniorPromptSource,
|
||||||
|
buildSisyphusJuniorPrompt,
|
||||||
|
} from "./index"
|
||||||
|
|
||||||
describe("createSisyphusJuniorAgentWithOverrides", () => {
|
describe("createSisyphusJuniorAgentWithOverrides", () => {
|
||||||
describe("honored fields", () => {
|
describe("honored fields", () => {
|
||||||
@ -212,7 +217,31 @@ describe("createSisyphusJuniorAgentWithOverrides", () => {
|
|||||||
// then
|
// then
|
||||||
expect(result.prompt).toContain("Sisyphus-Junior")
|
expect(result.prompt).toContain("Sisyphus-Junior")
|
||||||
expect(result.prompt).toContain("You work ALONE")
|
expect(result.prompt).toContain("You work ALONE")
|
||||||
|
})
|
||||||
|
|
||||||
|
test("Claude model uses default prompt with BLOCKED ACTIONS section", () => {
|
||||||
|
// given
|
||||||
|
const override = { model: "anthropic/claude-sonnet-4-5" }
|
||||||
|
|
||||||
|
// when
|
||||||
|
const result = createSisyphusJuniorAgentWithOverrides(override)
|
||||||
|
|
||||||
|
// then
|
||||||
expect(result.prompt).toContain("BLOCKED ACTIONS")
|
expect(result.prompt).toContain("BLOCKED ACTIONS")
|
||||||
|
expect(result.prompt).not.toContain("<blocked_actions>")
|
||||||
|
})
|
||||||
|
|
||||||
|
test("GPT model uses GPT-optimized prompt with blocked_actions section", () => {
|
||||||
|
// given
|
||||||
|
const override = { model: "openai/gpt-5.2" }
|
||||||
|
|
||||||
|
// when
|
||||||
|
const result = createSisyphusJuniorAgentWithOverrides(override)
|
||||||
|
|
||||||
|
// then
|
||||||
|
expect(result.prompt).toContain("<blocked_actions>")
|
||||||
|
expect(result.prompt).toContain("<output_verbosity_spec>")
|
||||||
|
expect(result.prompt).toContain("<scope_and_design_constraints>")
|
||||||
})
|
})
|
||||||
|
|
||||||
test("prompt_append is added after base prompt", () => {
|
test("prompt_append is added after base prompt", () => {
|
||||||
@ -225,8 +254,107 @@ describe("createSisyphusJuniorAgentWithOverrides", () => {
|
|||||||
// then
|
// then
|
||||||
const baseEndIndex = result.prompt!.indexOf("Dense > verbose.")
|
const baseEndIndex = result.prompt!.indexOf("Dense > verbose.")
|
||||||
const appendIndex = result.prompt!.indexOf("CUSTOM_MARKER_FOR_TEST")
|
const appendIndex = result.prompt!.indexOf("CUSTOM_MARKER_FOR_TEST")
|
||||||
expect(baseEndIndex).not.toBe(-1) // Guard: anchor text must exist in base prompt
|
expect(baseEndIndex).not.toBe(-1)
|
||||||
expect(appendIndex).toBeGreaterThan(baseEndIndex)
|
expect(appendIndex).toBeGreaterThan(baseEndIndex)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("getSisyphusJuniorPromptSource", () => {
|
||||||
|
test("returns 'gpt' for OpenAI models", () => {
|
||||||
|
// given
|
||||||
|
const model = "openai/gpt-5.2"
|
||||||
|
|
||||||
|
// when
|
||||||
|
const source = getSisyphusJuniorPromptSource(model)
|
||||||
|
|
||||||
|
// then
|
||||||
|
expect(source).toBe("gpt")
|
||||||
|
})
|
||||||
|
|
||||||
|
test("returns 'gpt' for GitHub Copilot GPT models", () => {
|
||||||
|
// given
|
||||||
|
const model = "github-copilot/gpt-4o"
|
||||||
|
|
||||||
|
// when
|
||||||
|
const source = getSisyphusJuniorPromptSource(model)
|
||||||
|
|
||||||
|
// then
|
||||||
|
expect(source).toBe("gpt")
|
||||||
|
})
|
||||||
|
|
||||||
|
test("returns 'default' for Claude models", () => {
|
||||||
|
// given
|
||||||
|
const model = "anthropic/claude-sonnet-4-5"
|
||||||
|
|
||||||
|
// when
|
||||||
|
const source = getSisyphusJuniorPromptSource(model)
|
||||||
|
|
||||||
|
// then
|
||||||
|
expect(source).toBe("default")
|
||||||
|
})
|
||||||
|
|
||||||
|
test("returns 'default' for undefined model", () => {
|
||||||
|
// given
|
||||||
|
const model = undefined
|
||||||
|
|
||||||
|
// when
|
||||||
|
const source = getSisyphusJuniorPromptSource(model)
|
||||||
|
|
||||||
|
// then
|
||||||
|
expect(source).toBe("default")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("buildSisyphusJuniorPrompt", () => {
|
||||||
|
test("GPT model prompt contains GPT-5.2 specific sections", () => {
|
||||||
|
// given
|
||||||
|
const model = "openai/gpt-5.2"
|
||||||
|
|
||||||
|
// when
|
||||||
|
const prompt = buildSisyphusJuniorPrompt(model, false)
|
||||||
|
|
||||||
|
// then
|
||||||
|
expect(prompt).toContain("<identity>")
|
||||||
|
expect(prompt).toContain("<output_verbosity_spec>")
|
||||||
|
expect(prompt).toContain("<scope_and_design_constraints>")
|
||||||
|
expect(prompt).toContain("<tool_usage_rules>")
|
||||||
|
})
|
||||||
|
|
||||||
|
test("Claude model prompt contains Claude-specific sections", () => {
|
||||||
|
// given
|
||||||
|
const model = "anthropic/claude-sonnet-4-5"
|
||||||
|
|
||||||
|
// when
|
||||||
|
const prompt = buildSisyphusJuniorPrompt(model, false)
|
||||||
|
|
||||||
|
// then
|
||||||
|
expect(prompt).toContain("<Role>")
|
||||||
|
expect(prompt).toContain("<Critical_Constraints>")
|
||||||
|
expect(prompt).toContain("BLOCKED ACTIONS")
|
||||||
|
})
|
||||||
|
|
||||||
|
test("useTaskSystem=true includes Task_Discipline for GPT", () => {
|
||||||
|
// given
|
||||||
|
const model = "openai/gpt-5.2"
|
||||||
|
|
||||||
|
// when
|
||||||
|
const prompt = buildSisyphusJuniorPrompt(model, true)
|
||||||
|
|
||||||
|
// then
|
||||||
|
expect(prompt).toContain("<task_discipline_spec>")
|
||||||
|
expect(prompt).toContain("TaskCreate")
|
||||||
|
})
|
||||||
|
|
||||||
|
test("useTaskSystem=false includes Todo_Discipline for Claude", () => {
|
||||||
|
// given
|
||||||
|
const model = "anthropic/claude-sonnet-4-5"
|
||||||
|
|
||||||
|
// when
|
||||||
|
const prompt = buildSisyphusJuniorPrompt(model, false)
|
||||||
|
|
||||||
|
// then
|
||||||
|
expect(prompt).toContain("<Todo_Discipline>")
|
||||||
|
expect(prompt).toContain("todowrite")
|
||||||
|
})
|
||||||
|
})
|
||||||
121
src/agents/sisyphus-junior/index.ts
Normal file
121
src/agents/sisyphus-junior/index.ts
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
/**
|
||||||
|
* Sisyphus-Junior - Focused Task Executor
|
||||||
|
*
|
||||||
|
* Executes delegated tasks directly without spawning other agents.
|
||||||
|
* Category-spawned executor with domain-specific configurations.
|
||||||
|
*
|
||||||
|
* Routing:
|
||||||
|
* 1. GPT models (openai/*, github-copilot/gpt-*) -> gpt.ts (GPT-5.2 optimized)
|
||||||
|
* 2. Default (Claude, etc.) -> default.ts (Claude-optimized)
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type { AgentConfig } from "@opencode-ai/sdk"
|
||||||
|
import type { AgentMode } from "../types"
|
||||||
|
import { isGptModel } from "../types"
|
||||||
|
import type { AgentOverrideConfig } from "../../config/schema"
|
||||||
|
import {
|
||||||
|
createAgentToolRestrictions,
|
||||||
|
type PermissionValue,
|
||||||
|
} from "../../shared/permission-compat"
|
||||||
|
|
||||||
|
import { buildDefaultSisyphusJuniorPrompt } from "./default"
|
||||||
|
import { buildGptSisyphusJuniorPrompt } from "./gpt"
|
||||||
|
|
||||||
|
export { buildDefaultSisyphusJuniorPrompt } from "./default"
|
||||||
|
export { buildGptSisyphusJuniorPrompt } from "./gpt"
|
||||||
|
|
||||||
|
const MODE: AgentMode = "subagent"
|
||||||
|
|
||||||
|
// Core tools that Sisyphus-Junior must NEVER have access to
|
||||||
|
// Note: call_omo_agent is ALLOWED so subagents can spawn explore/librarian
|
||||||
|
const BLOCKED_TOOLS = ["task", "delegate_task"]
|
||||||
|
|
||||||
|
export const SISYPHUS_JUNIOR_DEFAULTS = {
|
||||||
|
model: "anthropic/claude-sonnet-4-5",
|
||||||
|
temperature: 0.1,
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type SisyphusJuniorPromptSource = "default" | "gpt"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines which Sisyphus-Junior prompt to use based on model.
|
||||||
|
*/
|
||||||
|
export function getSisyphusJuniorPromptSource(model?: string): SisyphusJuniorPromptSource {
|
||||||
|
if (model && isGptModel(model)) {
|
||||||
|
return "gpt"
|
||||||
|
}
|
||||||
|
return "default"
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds the appropriate Sisyphus-Junior prompt based on model.
|
||||||
|
*/
|
||||||
|
export function buildSisyphusJuniorPrompt(
|
||||||
|
model: string | undefined,
|
||||||
|
useTaskSystem: boolean,
|
||||||
|
promptAppend?: string
|
||||||
|
): string {
|
||||||
|
const source = getSisyphusJuniorPromptSource(model)
|
||||||
|
|
||||||
|
switch (source) {
|
||||||
|
case "gpt":
|
||||||
|
return buildGptSisyphusJuniorPrompt(useTaskSystem, promptAppend)
|
||||||
|
case "default":
|
||||||
|
default:
|
||||||
|
return buildDefaultSisyphusJuniorPrompt(useTaskSystem, promptAppend)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createSisyphusJuniorAgentWithOverrides(
|
||||||
|
override: AgentOverrideConfig | undefined,
|
||||||
|
systemDefaultModel?: string,
|
||||||
|
useTaskSystem = false
|
||||||
|
): AgentConfig {
|
||||||
|
if (override?.disable) {
|
||||||
|
override = undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
const model = override?.model ?? systemDefaultModel ?? SISYPHUS_JUNIOR_DEFAULTS.model
|
||||||
|
const temperature = override?.temperature ?? SISYPHUS_JUNIOR_DEFAULTS.temperature
|
||||||
|
|
||||||
|
const promptAppend = override?.prompt_append
|
||||||
|
const prompt = buildSisyphusJuniorPrompt(model, useTaskSystem, promptAppend)
|
||||||
|
|
||||||
|
const baseRestrictions = createAgentToolRestrictions(BLOCKED_TOOLS)
|
||||||
|
|
||||||
|
const userPermission = (override?.permission ?? {}) as Record<string, PermissionValue>
|
||||||
|
const basePermission = baseRestrictions.permission
|
||||||
|
const merged: Record<string, PermissionValue> = { ...userPermission }
|
||||||
|
for (const tool of BLOCKED_TOOLS) {
|
||||||
|
merged[tool] = "deny"
|
||||||
|
}
|
||||||
|
merged.call_omo_agent = "allow"
|
||||||
|
const toolsConfig = { permission: { ...merged, ...basePermission } }
|
||||||
|
|
||||||
|
const base: AgentConfig = {
|
||||||
|
description: override?.description ??
|
||||||
|
"Focused task executor. Same discipline, no delegation. (Sisyphus-Junior - OhMyOpenCode)",
|
||||||
|
mode: MODE,
|
||||||
|
model,
|
||||||
|
temperature,
|
||||||
|
maxTokens: 64000,
|
||||||
|
prompt,
|
||||||
|
color: override?.color ?? "#20B2AA",
|
||||||
|
...toolsConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
if (override?.top_p !== undefined) {
|
||||||
|
base.top_p = override.top_p
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isGptModel(model)) {
|
||||||
|
return { ...base, reasoningEffort: "medium" } as AgentConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...base,
|
||||||
|
thinking: { type: "enabled", budgetTokens: 32000 },
|
||||||
|
} as AgentConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
createSisyphusJuniorAgentWithOverrides.mode = MODE
|
||||||
Loading…
x
Reference in New Issue
Block a user