fix(#2748): pass browserProvider into skill() discovery

skill-context already filtered browser-related skills using the configured
browser provider, but the skill tool rebuilt discovery without forwarding
browserProvider. That caused skills like agent-browser to be prompt-visible
while skill() could still fail to resolve them unless browser_automation_engine.provider
was explicitly threaded through both paths.

Fix:
- pass skillContext.browserProvider from tool-registry into createSkillTool
- extend SkillLoadOptions with browserProvider
- forward browserProvider to getAllSkills()
- add regression tests for execution and description visibility
This commit is contained in:
YeonGyu-Kim
2026-03-27 17:58:38 +09:00
parent 76bf269b39
commit 6662205646
4 changed files with 37 additions and 2 deletions

View File

@@ -113,6 +113,7 @@ export function createToolRegistry(args: {
mcpManager: managers.skillMcpManager,
getSessionID: getSessionIDForMcp,
gitMasterConfig: pluginConfig.git_master,
browserProvider: skillContext.browserProvider,
nativeSkills: "skills" in ctx ? (ctx as { skills: SkillLoadOptions["nativeSkills"] }).skills : undefined,
})

View File

@@ -583,6 +583,38 @@ describe("skill tool - dynamic description cache invalidation", () => {
describe("skill tool - browserProvider forwarding", () => {
it("passes browserProvider to getAllSkills during execution", async () => {
// given: a skill tool configured with agent-browser as browserProvider
// and a pre-provided agent-browser skill (simulating what skill-context provides)
const agentBrowserSkill = createMockSkill("agent-browser")
const tool = createSkillTool({
skills: [agentBrowserSkill],
browserProvider: "agent-browser",
})
// when: executing skill("agent-browser")
const result = await tool.execute({ name: "agent-browser" }, mockContext)
// then: skill should resolve successfully (not filtered out)
expect(result).toContain("Skill: agent-browser")
})
it("description includes agent-browser when browserProvider is agent-browser", () => {
// given
const agentBrowserSkill = createMockSkill("agent-browser")
// when
const tool = createSkillTool({
skills: [agentBrowserSkill],
browserProvider: "agent-browser",
})
// then
expect(tool.description).toContain("agent-browser")
})
})
describe("skill tool - nativeSkills integration", () => {
it("merges native skills exposed by PluginInput.skills.all()", async () => {
//#given

View File

@@ -189,7 +189,7 @@ export function createSkillTool(options: SkillLoadOptions = {}): ToolDefinition
const getSkills = async (): Promise<LoadedSkill[]> => {
clearSkillCache()
const discovered = await getAllSkills({disabledSkills: options?.disabledSkills})
const discovered = await getAllSkills({disabledSkills: options?.disabledSkills, browserProvider: options?.browserProvider})
const allSkills = !options.skills
? discovered
: [...discovered, ...options.skills.filter(s => !new Set(discovered.map(d => d.name)).has(s.name))]

View File

@@ -1,6 +1,6 @@
import type { SkillScope, LoadedSkill } from "../../features/opencode-skill-loader/types"
import type { SkillMcpManager } from "../../features/skill-mcp-manager"
import type { GitMasterConfig } from "../../config/schema"
import type { BrowserAutomationProvider, GitMasterConfig } from "../../config/schema"
import type { CommandInfo } from "../slashcommand/types"
export interface SkillArgs {
@@ -33,6 +33,8 @@ export interface SkillLoadOptions {
/** Git master configuration for watermark/co-author settings */
gitMasterConfig?: GitMasterConfig
disabledSkills?: Set<string>
/** Browser automation provider for provider-gated skill filtering */
browserProvider?: BrowserAutomationProvider
/** Include Claude marketplace plugin commands in discovery (default: true) */
pluginsEnabled?: boolean
/** Override plugin enablement from Claude settings by plugin key */