test(delegate-task): isolate browser provider coverage
This commit is contained in:
@@ -0,0 +1,163 @@
|
||||
/// <reference types="bun-types" />
|
||||
|
||||
import { mkdirSync, rmSync, writeFileSync } from "node:fs"
|
||||
import { tmpdir } from "node:os"
|
||||
import { join } from "node:path"
|
||||
import { clearSkillCache } from "../../features/opencode-skill-loader/skill-content"
|
||||
|
||||
declare const require: NodeJS.Require
|
||||
|
||||
const { afterEach, beforeEach, describe, expect, test } = require("bun:test")
|
||||
|
||||
const SYSTEM_DEFAULT_MODEL = "anthropic/claude-sonnet-4-6"
|
||||
const TOOL_CONTEXT = {
|
||||
sessionID: "parent-session",
|
||||
messageID: "parent-message",
|
||||
agent: "sisyphus",
|
||||
abort: new AbortController().signal,
|
||||
}
|
||||
|
||||
type EnvSnapshot = Record<"CLAUDE_CONFIG_DIR" | "OPENCODE_CONFIG_DIR", string | undefined>
|
||||
type PromptBody = { system?: string }
|
||||
type PromptInput = { body?: PromptBody }
|
||||
|
||||
let envSnapshot: EnvSnapshot
|
||||
let testConfigDir: string | undefined
|
||||
|
||||
function restoreEnvValue(key: keyof EnvSnapshot): void {
|
||||
const value = envSnapshot[key]
|
||||
if (value === undefined) {
|
||||
delete process.env[key]
|
||||
return
|
||||
}
|
||||
|
||||
process.env[key] = value
|
||||
}
|
||||
|
||||
function createAgentBrowserSkillFixture(content: string): void {
|
||||
const unique = `delegate-agent-browser-${Date.now()}-${Math.random().toString(16).slice(2)}`
|
||||
testConfigDir = join(tmpdir(), unique)
|
||||
const skillDir = join(testConfigDir, "skills", "compound-engineering", "agent-browser")
|
||||
mkdirSync(skillDir, { recursive: true })
|
||||
writeFileSync(
|
||||
join(skillDir, "SKILL.md"),
|
||||
`---\nname: agent-browser\ndescription: Test-owned browser automation skill\n---\n${content}`,
|
||||
)
|
||||
process.env.CLAUDE_CONFIG_DIR = testConfigDir
|
||||
process.env.OPENCODE_CONFIG_DIR = testConfigDir
|
||||
clearSkillCache()
|
||||
}
|
||||
|
||||
describe("delegate task browserProvider propagation", () => {
|
||||
beforeEach(() => {
|
||||
envSnapshot = {
|
||||
CLAUDE_CONFIG_DIR: process.env.CLAUDE_CONFIG_DIR,
|
||||
OPENCODE_CONFIG_DIR: process.env.OPENCODE_CONFIG_DIR,
|
||||
}
|
||||
testConfigDir = undefined
|
||||
clearSkillCache()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
restoreEnvValue("CLAUDE_CONFIG_DIR")
|
||||
restoreEnvValue("OPENCODE_CONFIG_DIR")
|
||||
clearSkillCache()
|
||||
if (testConfigDir !== undefined) {
|
||||
rmSync(testConfigDir, { recursive: true, force: true })
|
||||
}
|
||||
})
|
||||
|
||||
test("resolves agent-browser builtin skill when browserProvider is passed", async () => {
|
||||
// given
|
||||
const { createDelegateTask } = require("./tools")
|
||||
let promptBody: PromptBody | undefined
|
||||
const promptMock = async (input: PromptInput) => {
|
||||
promptBody = input.body
|
||||
return { data: {} }
|
||||
}
|
||||
const mockClient = {
|
||||
app: { agents: async () => ({ data: [] }) },
|
||||
config: { get: async () => ({ data: { model: SYSTEM_DEFAULT_MODEL } }) },
|
||||
session: {
|
||||
get: async () => ({ data: { directory: "/project" } }),
|
||||
create: async () => ({ data: { id: "ses_browser_provider" } }),
|
||||
prompt: promptMock,
|
||||
promptAsync: promptMock,
|
||||
messages: async () => ({
|
||||
data: [{ info: { role: "assistant" }, parts: [{ type: "text", text: "Done" }] }],
|
||||
}),
|
||||
status: async () => ({ data: {} }),
|
||||
},
|
||||
}
|
||||
const tool = createDelegateTask({
|
||||
manager: { launch: async () => ({}) },
|
||||
client: mockClient,
|
||||
browserProvider: "agent-browser",
|
||||
})
|
||||
|
||||
// when
|
||||
await tool.execute(
|
||||
{
|
||||
description: "Test browserProvider propagation",
|
||||
prompt: "Do something",
|
||||
category: "ultrabrain",
|
||||
run_in_background: false,
|
||||
load_skills: ["agent-browser"],
|
||||
},
|
||||
TOOL_CONTEXT,
|
||||
)
|
||||
|
||||
// then
|
||||
const system = promptBody?.system ?? ""
|
||||
expect(system).toContain("agent-browser")
|
||||
expect(system).toContain("<Category_Context>")
|
||||
expect(system.startsWith("<Category_Context>")).toBe(false)
|
||||
}, { timeout: 20000 })
|
||||
|
||||
test("resolves discovered agent-browser skill by short name without browserProvider", async () => {
|
||||
// given
|
||||
const fixtureContent = "Test-owned agent-browser fixture content"
|
||||
createAgentBrowserSkillFixture(fixtureContent)
|
||||
const { createDelegateTask } = require("./tools")
|
||||
let promptBody: PromptBody | undefined
|
||||
const promptMock = async (input: PromptInput) => {
|
||||
promptBody = input.body
|
||||
return { data: {} }
|
||||
}
|
||||
const mockClient = {
|
||||
app: { agents: async () => ({ data: [] }) },
|
||||
config: { get: async () => ({ data: { model: SYSTEM_DEFAULT_MODEL } }) },
|
||||
session: {
|
||||
get: async () => ({ data: { directory: "/project" } }),
|
||||
create: async () => ({ data: { id: "ses_no_browser_provider" } }),
|
||||
prompt: promptMock,
|
||||
promptAsync: promptMock,
|
||||
messages: async () => ({
|
||||
data: [{ info: { role: "assistant" }, parts: [{ type: "text", text: "Done" }] }],
|
||||
}),
|
||||
status: async () => ({ data: {} }),
|
||||
},
|
||||
}
|
||||
const tool = createDelegateTask({
|
||||
manager: { launch: async () => ({}) },
|
||||
client: mockClient,
|
||||
})
|
||||
|
||||
// when
|
||||
const result = await tool.execute(
|
||||
{
|
||||
description: "Test missing browserProvider",
|
||||
prompt: "Do something",
|
||||
category: "ultrabrain",
|
||||
run_in_background: false,
|
||||
load_skills: ["agent-browser"],
|
||||
},
|
||||
TOOL_CONTEXT,
|
||||
)
|
||||
|
||||
// then
|
||||
expect(result).toContain("Task completed")
|
||||
expect(result).toContain("ses_no_browser_provider")
|
||||
expect(promptBody?.system).toContain(fixtureContent)
|
||||
})
|
||||
})
|
||||
@@ -696,7 +696,7 @@ describe("sisyphus-task", () => {
|
||||
//#given - manager.launch returns before sessionID is available
|
||||
const { createDelegateTask } = require("./tools")
|
||||
|
||||
const tasks = new Map<string, { id: string; sessionID?: string; status: string; description: string; agent: string }>()
|
||||
const tasks = new Map<string, { id: string; sessionId?: string; status: string; description: string; agent: string }>()
|
||||
const mockManager = {
|
||||
getTask: (id: string) => tasks.get(id),
|
||||
launch: async () => {
|
||||
@@ -3222,119 +3222,6 @@ describe("sisyphus-task", () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe("browserProvider propagation", () => {
|
||||
test("should resolve agent-browser skill when browserProvider is passed", async () => {
|
||||
// given - task configured with browserProvider: "agent-browser"
|
||||
const { createDelegateTask } = require("./tools")
|
||||
let promptBody: any
|
||||
|
||||
const mockManager = { launch: async () => ({}) }
|
||||
|
||||
const promptMock = async (input: any) => {
|
||||
promptBody = input.body
|
||||
return { data: {} }
|
||||
}
|
||||
|
||||
const mockClient = {
|
||||
app: { agents: async () => ({ data: [] }) },
|
||||
config: { get: async () => ({ data: { model: SYSTEM_DEFAULT_MODEL } }) },
|
||||
session: {
|
||||
get: async () => ({ data: { directory: "/project" } }),
|
||||
create: async () => ({ data: { id: "ses_browser_provider" } }),
|
||||
prompt: promptMock,
|
||||
promptAsync: promptMock,
|
||||
messages: async () => ({
|
||||
data: [{ info: { role: "assistant" }, parts: [{ type: "text", text: "Done" }] }]
|
||||
}),
|
||||
status: async () => ({ data: {} }),
|
||||
},
|
||||
}
|
||||
|
||||
// Pass browserProvider to createDelegateTask
|
||||
const tool = createDelegateTask({
|
||||
manager: mockManager,
|
||||
client: mockClient,
|
||||
browserProvider: "agent-browser",
|
||||
})
|
||||
|
||||
const toolContext = {
|
||||
sessionID: "parent-session",
|
||||
messageID: "parent-message",
|
||||
agent: "sisyphus",
|
||||
abort: new AbortController().signal,
|
||||
}
|
||||
|
||||
// when - request agent-browser skill
|
||||
await tool.execute(
|
||||
{
|
||||
description: "Test browserProvider propagation",
|
||||
prompt: "Do something",
|
||||
category: "ultrabrain",
|
||||
run_in_background: false,
|
||||
load_skills: ["agent-browser"],
|
||||
},
|
||||
toolContext
|
||||
)
|
||||
|
||||
// then - agent-browser skill should be resolved
|
||||
expect(promptBody).toBeDefined()
|
||||
expect(promptBody.system).toBeDefined()
|
||||
expect(promptBody.system).toContain("<Category_Context>")
|
||||
expect(String(promptBody.system).startsWith("<Category_Context>")).toBe(false)
|
||||
}, { timeout: 20000 })
|
||||
|
||||
test("should resolve agent-browser skill even when browserProvider is not set", async () => {
|
||||
// given - delegate_task without browserProvider
|
||||
const { createDelegateTask } = require("./tools")
|
||||
const mockManager = { launch: async () => ({}) }
|
||||
const mockClient = {
|
||||
app: { agents: async () => ({ data: [] }) },
|
||||
config: { get: async () => ({ data: { model: SYSTEM_DEFAULT_MODEL } }) },
|
||||
session: {
|
||||
get: async () => ({ data: { directory: "/project" } }),
|
||||
create: async () => ({ data: { id: "ses_no_browser_provider" } }),
|
||||
prompt: async () => {
|
||||
return { data: {} }
|
||||
},
|
||||
promptAsync: async () => ({ data: {} }),
|
||||
messages: async () => ({
|
||||
data: [{ info: { role: "assistant" }, parts: [{ type: "text", text: "Done" }] }]
|
||||
}),
|
||||
status: async () => ({ data: {} }),
|
||||
},
|
||||
}
|
||||
|
||||
// No browserProvider passed
|
||||
const tool = createDelegateTask({
|
||||
manager: mockManager,
|
||||
client: mockClient,
|
||||
})
|
||||
|
||||
const toolContext = {
|
||||
sessionID: "parent-session",
|
||||
messageID: "parent-message",
|
||||
agent: "sisyphus",
|
||||
abort: new AbortController().signal,
|
||||
}
|
||||
|
||||
// when - request agent-browser skill without browserProvider
|
||||
const result = await tool.execute(
|
||||
{
|
||||
description: "Test missing browserProvider",
|
||||
prompt: "Do something",
|
||||
category: "ultrabrain",
|
||||
run_in_background: false,
|
||||
load_skills: ["agent-browser"],
|
||||
},
|
||||
toolContext
|
||||
)
|
||||
|
||||
// then - the external compound-engineering/agent-browser skill can resolve by unique short name
|
||||
expect(result).toContain("Task completed")
|
||||
expect(result).toContain("ses_no_browser_provider")
|
||||
})
|
||||
})
|
||||
|
||||
describe("delegate task with short skill name", () => {
|
||||
let envCleanup: Record<string, string | undefined>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user