feat(skills): add agent-browser option for browser automation (#1090)

Add configurable browser automation allowing users to choose between
Playwright MCP (default) and Vercel's agent-browser CLI.

Changes:
- Add browser_automation_engine.provider config option
- Dynamic skill loading based on provider selection
- Comprehensive agent-browser CLI reference (inline in skills.ts)
- Propagate browserProvider to delegate_task and buildAgent
- Update documentation with provider comparison

Co-authored-by: Suyeol Jeon <devxoul@gmail.com>
Co-authored-by: YeonGyu Kim <code.yeongyu@gmail.com>
This commit is contained in:
YeonGyu-Kim
2026-01-25 15:02:41 +09:00
committed by GitHub
parent b55fd8d76f
commit 3af30b0a21
17 changed files with 1155 additions and 38 deletions

View File

@@ -3,24 +3,27 @@ import { discoverSkills } from "./loader"
import type { LoadedSkill } from "./types"
import { parseFrontmatter } from "../../shared/frontmatter"
import { readFileSync } from "node:fs"
import type { GitMasterConfig } from "../../config/schema"
import type { GitMasterConfig, BrowserAutomationProvider } from "../../config/schema"
export interface SkillResolutionOptions {
gitMasterConfig?: GitMasterConfig
browserProvider?: BrowserAutomationProvider
}
let cachedSkills: LoadedSkill[] | null = null
const cachedSkillsByProvider = new Map<string, LoadedSkill[]>()
function clearSkillCache(): void {
cachedSkills = null
cachedSkillsByProvider.clear()
}
async function getAllSkills(): Promise<LoadedSkill[]> {
if (cachedSkills) return cachedSkills
async function getAllSkills(options?: SkillResolutionOptions): Promise<LoadedSkill[]> {
const cacheKey = options?.browserProvider ?? "playwright"
const cached = cachedSkillsByProvider.get(cacheKey)
if (cached) return cached
const [discoveredSkills, builtinSkillDefs] = await Promise.all([
discoverSkills({ includeClaudeCodePaths: true }),
Promise.resolve(createBuiltinSkills()),
Promise.resolve(createBuiltinSkills({ browserProvider: options?.browserProvider })),
])
const builtinSkillsAsLoaded: LoadedSkill[] = builtinSkillDefs.map((skill) => ({
@@ -44,8 +47,9 @@ async function getAllSkills(): Promise<LoadedSkill[]> {
const discoveredNames = new Set(discoveredSkills.map((s) => s.name))
const uniqueBuiltins = builtinSkillsAsLoaded.filter((s) => !discoveredNames.has(s.name))
cachedSkills = [...discoveredSkills, ...uniqueBuiltins]
return cachedSkills
const allSkills = [...discoveredSkills, ...uniqueBuiltins]
cachedSkillsByProvider.set(cacheKey, allSkills)
return allSkills
}
async function extractSkillTemplate(skill: LoadedSkill): Promise<string> {
@@ -118,7 +122,7 @@ export function injectGitMasterConfig(template: string, config?: GitMasterConfig
}
export function resolveSkillContent(skillName: string, options?: SkillResolutionOptions): string | null {
const skills = createBuiltinSkills()
const skills = createBuiltinSkills({ browserProvider: options?.browserProvider })
const skill = skills.find((s) => s.name === skillName)
if (!skill) return null
@@ -133,7 +137,7 @@ export function resolveMultipleSkills(skillNames: string[], options?: SkillResol
resolved: Map<string, string>
notFound: string[]
} {
const skills = createBuiltinSkills()
const skills = createBuiltinSkills({ browserProvider: options?.browserProvider })
const skillMap = new Map(skills.map((s) => [s.name, s.template]))
const resolved = new Map<string, string>()
@@ -159,7 +163,7 @@ export async function resolveSkillContentAsync(
skillName: string,
options?: SkillResolutionOptions
): Promise<string | null> {
const allSkills = await getAllSkills()
const allSkills = await getAllSkills(options)
const skill = allSkills.find((s) => s.name === skillName)
if (!skill) return null
@@ -179,7 +183,7 @@ export async function resolveMultipleSkillsAsync(
resolved: Map<string, string>
notFound: string[]
}> {
const allSkills = await getAllSkills()
const allSkills = await getAllSkills(options)
const skillMap = new Map<string, LoadedSkill>()
for (const skill of allSkills) {
skillMap.set(skill.name, skill)