Built-ins

web Plugin

Ready-to-use document reading and local browsing, with configurable Tavily, Exa, and Firecrawl providers

web Plugin

web owns its search, document, and browser providers. It does not depend on context.agent.web. In Desktop, static document reading and a managed local Chrome browser work without manual CDP setup. Search becomes available after an API key is configured.

Desktop configuration

Open Plugins → Web. The page has three capability sections:

  • Search: Auto, Tavily, Exa, or disabled. Auto prefers Tavily and then Exa.
  • Documents: built-in Fetch by default, or Firecrawl for harder pages.
  • Browser: managed Local Chrome by default, Remote CDP, or disabled.

API keys can be entered directly on the Web configuration page. Saved values are never returned to the renderer; the page only shows whether a key is configured. An empty field preserves the existing value, while the explicit Clear action removes it. Keys currently live in Downcity's local Plugin configuration and are not stored in the operating-system keychain.

Global Env remains supported:

TAVILY_API_KEY=...
EXA_API_KEY=...
FIRECRAWL_API_KEY=...

Plugin configuration takes precedence over Global Env. Each capability section includes a test button that saves the draft and performs one minimal call through a real Agent and Workspace.

Defaults

import { WebPlugin } from "@downcity/plugins/web";

const web = new WebPlugin();
  • open uses the built-in Fetch provider and never executes page scripts.
  • Browser actions discover Google Chrome, Chromium, or Microsoft Edge and use a private persistent profile.
  • search selects Tavily or Exa when a key is available; missing search credentials do not disable other capabilities.

WebPlugin closes browser processes and pages it owns. The persistent profile keeps login state. For a cloud browser, select Remote CDP and enter its HTTP or WebSocket endpoint.

Fixed SDK configuration

Constructor configuration overrides saved City/Desktop configuration:

const web = new WebPlugin({
  config: {
    search_provider: "tavily",
    tavily_api_key: process.env.TAVILY_API_KEY,
    document_provider: "firecrawl",
    firecrawl_api_key: process.env.FIRECRAWL_API_KEY,
    browser_provider: "cdp",
    cdp_url: "https://browser.example.com/cdp",
  },
});

Hosts may still inject search_provider, document_provider, or browser_provider_factory. Ownership of injected providers transfers to WebPlugin.

Actions

ActionPurpose
searchSearch through Tavily, Exa, or an injected provider
openRead through safe Fetch, Firecrawl, or an injected provider
browser_create_sessionCreate a browser session
browser_observeRead URL, title, accessibility snapshot, visible text, refs, and an optional screenshot
browser_actPerform a deterministic action with an observation generation and ref
browser_semantic_actUse an optional semantic adapter
browser_extractExtract text from a selector or the body
browser_semantic_extractExtract through an optional semantic adapter
browser_close_sessionClose a session and release its page

Observe first, then act with a ref from that exact generation:

const observed = await web.actions.browser_observe.execute({
  context,
  input: { session_id },
});

await web.actions.browser_act.execute({
  context,
  input: {
    session_id,
    action: {
      type: "click",
      ref: observed.data.elements[0].ref,
      observation_generation: observed.data.observation_generation,
    },
  },
});

Element refs are valid only for the observation generation that produced them. Use new refs after every action. CSS selectors remain available only for explicit deterministic automation.

Network and safety boundaries

  • Fetch only permits public HTTP(S) targets and revalidates every redirect against SSRF rules.
  • Requests have timeout, redirect-count, and response-size limits.
  • Provider errors do not expose API keys, authentication headers, or full error response bodies.
  • Consequential actions such as submit, send, purchase, upload, and delete still require host approval.
  • Page content is always untrusted input and cannot override Agent or host instructions.