diff --git a/src/features/background-agent/manager.test.ts b/src/features/background-agent/manager.test.ts index 41f0d622..e340af68 100644 --- a/src/features/background-agent/manager.test.ts +++ b/src/features/background-agent/manager.test.ts @@ -643,3 +643,34 @@ describe("BackgroundManager.resume", () => { expect(result.progress?.toolCalls).toBe(42) }) }) + +describe("LaunchInput.skillContent", () => { + test("skillContent should be optional in LaunchInput type", () => { + // #given + const input: import("./types").LaunchInput = { + description: "test", + prompt: "test prompt", + agent: "explore", + parentSessionID: "parent-session", + parentMessageID: "parent-msg", + } + + // #when / #then - should compile without skillContent + expect(input.skillContent).toBeUndefined() + }) + + test("skillContent can be provided in LaunchInput", () => { + // #given + const input: import("./types").LaunchInput = { + description: "test", + prompt: "test prompt", + agent: "explore", + parentSessionID: "parent-session", + parentMessageID: "parent-msg", + skillContent: "You are a playwright expert", + } + + // #when / #then + expect(input.skillContent).toBe("You are a playwright expert") + }) +}) diff --git a/src/features/background-agent/manager.ts b/src/features/background-agent/manager.ts index be52b08d..9b34192f 100644 --- a/src/features/background-agent/manager.ts +++ b/src/features/background-agent/manager.ts @@ -140,6 +140,7 @@ export class BackgroundManager { path: { id: sessionID }, body: { agent: input.agent, + system: input.skillContent, tools: { task: false, call_omo_agent: false, diff --git a/src/features/background-agent/types.ts b/src/features/background-agent/types.ts index 661afa6c..415320d7 100644 --- a/src/features/background-agent/types.ts +++ b/src/features/background-agent/types.ts @@ -41,6 +41,7 @@ export interface LaunchInput { parentModel?: { providerID: string; modelID: string } model?: { providerID: string; modelID: string } skills?: string[] + skillContent?: string } export interface ResumeInput { diff --git a/src/tools/sisyphus-task/tools.test.ts b/src/tools/sisyphus-task/tools.test.ts index d3df0768..aed4e129 100644 --- a/src/tools/sisyphus-task/tools.test.ts +++ b/src/tools/sisyphus-task/tools.test.ts @@ -214,4 +214,56 @@ describe("sisyphus-task", () => { expect(SISYPHUS_TASK_DESCRIPTION).toContain("Array of skill names") }) }) + + describe("buildSystemContent", () => { + test("returns undefined when no skills and no category promptAppend", () => { + // #given + const { buildSystemContent } = require("./tools") + + // #when + const result = buildSystemContent({ skills: undefined, categoryPromptAppend: undefined }) + + // #then + expect(result).toBeUndefined() + }) + + test("returns skill content only when skills provided without category", () => { + // #given + const { buildSystemContent } = require("./tools") + const skillContent = "You are a playwright expert" + + // #when + const result = buildSystemContent({ skillContent, categoryPromptAppend: undefined }) + + // #then + expect(result).toBe(skillContent) + }) + + test("returns category promptAppend only when no skills", () => { + // #given + const { buildSystemContent } = require("./tools") + const categoryPromptAppend = "Focus on visual design" + + // #when + const result = buildSystemContent({ skillContent: undefined, categoryPromptAppend }) + + // #then + expect(result).toBe(categoryPromptAppend) + }) + + test("combines skill content and category promptAppend with separator", () => { + // #given + const { buildSystemContent } = require("./tools") + const skillContent = "You are a playwright expert" + const categoryPromptAppend = "Focus on visual design" + + // #when + const result = buildSystemContent({ skillContent, categoryPromptAppend }) + + // #then + expect(result).toContain(skillContent) + expect(result).toContain(categoryPromptAppend) + expect(result).toContain("\n\n") + }) + }) }) diff --git a/src/tools/sisyphus-task/tools.ts b/src/tools/sisyphus-task/tools.ts index c79999da..47bf9c94 100644 --- a/src/tools/sisyphus-task/tools.ts +++ b/src/tools/sisyphus-task/tools.ts @@ -90,6 +90,25 @@ export interface SisyphusTaskToolOptions { userCategories?: CategoriesConfig } +export interface BuildSystemContentInput { + skillContent?: string + categoryPromptAppend?: string +} + +export function buildSystemContent(input: BuildSystemContentInput): string | undefined { + const { skillContent, categoryPromptAppend } = input + + if (!skillContent && !categoryPromptAppend) { + return undefined + } + + if (skillContent && categoryPromptAppend) { + return `${skillContent}\n\n${categoryPromptAppend}` + } + + return skillContent || categoryPromptAppend +} + export function createSisyphusTask(options: SisyphusTaskToolOptions): ToolDefinition { const { manager, client, userCategories } = options @@ -111,15 +130,14 @@ export function createSisyphusTask(options: SisyphusTaskToolOptions): ToolDefini } const runInBackground = args.background === true - // Handle skills - resolve and prepend to prompt + let skillContent: string | undefined if (args.skills && args.skills.length > 0) { const { resolved, notFound } = resolveMultipleSkills(args.skills) if (notFound.length > 0) { const available = createBuiltinSkills().map(s => s.name).join(", ") return `❌ Skills not found: ${notFound.join(", ")}. Available: ${available}` } - const skillContent = Array.from(resolved.values()).join("\n\n") - args.prompt = skillContent + "\n\n---\n\n" + args.prompt + skillContent = Array.from(resolved.values()).join("\n\n") } const messageDir = getMessageDir(ctx.sessionID) @@ -169,8 +187,8 @@ Use \`background_output\` with task_id="${task.id}" to check progress.` } let agentToUse: string - let categoryModel: { providerID: string; modelID: string } | undefined + let categoryPromptAppend: string | undefined if (args.category) { const resolved = resolveCategoryConfig(args.category, userCategories) @@ -180,6 +198,7 @@ Use \`background_output\` with task_id="${task.id}" to check progress.` agentToUse = SISYPHUS_JUNIOR_AGENT categoryModel = parseModelString(resolved.config.model) + categoryPromptAppend = resolved.promptAppend || undefined } else { agentToUse = args.subagent_type!.trim() if (!agentToUse) { @@ -211,6 +230,8 @@ Use \`background_output\` with task_id="${task.id}" to check progress.` } } + const systemContent = buildSystemContent({ skillContent, categoryPromptAppend }) + if (runInBackground) { try { const task = await manager.launch({ @@ -222,6 +243,7 @@ Use \`background_output\` with task_id="${task.id}" to check progress.` parentModel, model: categoryModel, skills: args.skills, + skillContent: systemContent, }) ctx.metadata?.({ @@ -284,6 +306,7 @@ System notifies on completion. Use \`background_output\` with task_id="${task.id body: { agent: agentToUse, model: categoryModel, + system: systemContent, tools: { task: false, sisyphus_task: false,