Files
fusion/plugins/fusion-plugin-agent-browser/src/index.ts
gsxdsm 3f2197be20 feat(agent-browser): real navigate/interact/observe driver (U8)
Replaces the metadata/probe stub with a playwright-core driver (no bundled
browser download; uses a probe-discovered Chrome) exposing navigate/click/type/
observe + idempotent dispose. Browser-unavailable and un-exercisable assertions
return inconclusive (never a false pass/fail); a missing selector returns a
distinct 'absent' negative observation. Driver is a direct export scoped to the
verification run, not registered as a coding-agent tool.
2026-06-12 02:11:04 -07:00

92 lines
5.1 KiB
TypeScript

import { definePlugin } from "@fusion/plugin-sdk";
import type { FusionPlugin, PluginSettingSchema } from "@fusion/plugin-sdk";
import { AGENT_BROWSER_SKILLS } from "./skills.js";
import { buildPromptContributions } from "./prompts.js";
import { setupHooks, setupManifest } from "./setup.js";
import { resolveSettings } from "./types.js";
import { AGENT_BROWSER_WORKFLOW_STEPS } from "./workflow-steps.js";
import { AGENT_BROWSER_TOOLS } from "./tools.js";
import { probeAgentBrowserBinary } from "./probe.js";
const MAX_PROBE_TIMEOUT_MS = 30_000;
export const AGENT_BROWSER_SETTINGS_SCHEMA: Record<string, PluginSettingSchema> = {
enabled: { type: "boolean", label: "Enable Agent Browser", group: "General", defaultValue: true },
installChannel: { type: "enum", label: "Install Channel", enumValues: ["stable", "beta", "nightly"], defaultValue: "stable", group: "General" },
commandTimeoutMs: { type: "number", label: "Command Timeout (ms)", defaultValue: 120000, group: "General" },
headlessMode: { type: "boolean", label: "Headless Mode", defaultValue: true, group: "Browser" },
allowedDomains: { type: "array", label: "Allowed Domains", itemType: "string", defaultValue: [], group: "Browser" },
promptExecutorSystem: { type: "string", label: "Executor System Prompt", multiline: true, defaultValue: "When browsing, summarize evidence with URLs.", group: "Prompt Contributions" },
promptExecutorTask: { type: "string", label: "Executor Task Prompt", multiline: true, defaultValue: "Use browser context only when needed for the task.", group: "Prompt Contributions" },
promptTriage: { type: "string", label: "Triage Prompt", multiline: true, defaultValue: "Mark tasks requiring browser evidence explicitly.", group: "Prompt Contributions" },
promptReviewer: { type: "string", label: "Reviewer Prompt", multiline: true, defaultValue: "Verify browser-derived claims are backed by cited pages.", group: "Prompt Contributions" },
promptHeartbeat: { type: "string", label: "Heartbeat Prompt", multiline: true, defaultValue: "Keep browser interactions bounded and report failures clearly.", group: "Prompt Contributions" },
skillExposure: { type: "enum", label: "Skill Exposure", enumValues: ["none", "selected", "all"], defaultValue: "selected", group: "Skills" },
};
const plugin: FusionPlugin = definePlugin({
manifest: {
id: "fusion-plugin-agent-browser",
name: "Agent Browser Plugin",
version: "0.1.0",
description: "Adds agent-browser setup hooks plus skills, prompt contributions, and workflow steps",
author: "Fusion Team",
homepage: "https://github.com/gsxdsm/fusion",
settingsSchema: AGENT_BROWSER_SETTINGS_SCHEMA,
skills: AGENT_BROWSER_SKILLS.map((s) => ({ skillId: s.skillId, name: s.name })),
workflowSteps: AGENT_BROWSER_WORKFLOW_STEPS.map((s) => ({ stepId: s.stepId, name: s.name })),
promptSurfaces: ["executor-system", "executor-task", "triage", "reviewer", "heartbeat"],
setup: setupManifest,
},
state: "installed",
hooks: {
onLoad: async (ctx) => {
try {
const settings = resolveSettings(ctx.settings);
plugin.promptContributions = buildPromptContributions(settings);
const probe = await probeAgentBrowserBinary({ timeoutMs: Math.min(settings.commandTimeoutMs, MAX_PROBE_TIMEOUT_MS) });
ctx.logger.info(`Agent Browser Plugin loaded — available=${String(probe.available)} channel=${settings.installChannel}`);
ctx.emitEvent("agent-browser:loaded", { available: probe.available, version: probe.version, settings });
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
ctx.logger.error(`Agent Browser Plugin probe failed: ${message}`);
ctx.emitEvent("agent-browser:loaded", { available: false, error: message });
}
},
},
tools: AGENT_BROWSER_TOOLS,
skills: AGENT_BROWSER_SKILLS,
workflowSteps: AGENT_BROWSER_WORKFLOW_STEPS,
promptContributions: buildPromptContributions(resolveSettings(undefined)),
setup: {
manifest: setupManifest,
hooks: setupHooks,
},
});
export default plugin;
// ── Verification-scoped app/browser driver (U8) ───────────────────────────────
//
// The navigate/interact/observe driver is exported as a typed capability the
// engine imports DIRECTLY inside the verification run (U5). It is intentionally
// NOT added to `plugin.tools` — the engine only exposes `plugin.tools` to
// coding-agent sessions (`pluginLoader.getPluginTools()`), so keeping the driver
// out of that array is what scopes it to verification and keeps it unreachable
// from normal coding sessions. `browser_fetch_metadata` remains the only
// coding-agent-facing tool.
export {
launchBrowserDriver,
createPlaywrightClient,
type BrowserDriverSession,
type BrowserAutomationClient,
type DriverLaunchResult,
type NavigateOutcome,
type InteractOutcome,
type ObserveOutcome,
type OperationInconclusive,
type InconclusiveReason,
type LaunchDriverOptions,
} from "./driver.js";
export { probeBrowserExecutable, type BrowserExecutableProbeResult } from "./probe.js";