ricardochen1996/dsh-browser-use ↗★ 1

@weichen96/dsh-browser-use

DeepSeek Harness browser provider: read a page as an indexed action space, then run one guarded operation at a time. 适合需要让Agent通过浏览器执行自动化网页操作任务的用户。

패키지
@weichen96/dsh-browser-use
호환성
미검증
버전
0.3.0
라이선스
MIT
최근 업데이트
2026. 10. 1.

설치

$npx -p @deepseek-ai/dsh dsh plugin --profile web add github:ricardochen1996/dsh-browser-use

5. Configuration

Change it in the UI (recommended): the plugin exports DSH's Config schema (lib/config.js), and the web half mounts the form in two places, so you don't need to find a config file and changes take effect immediately:

  • Sidebar → Plugins → open @weichen96/dsh-browser-use: the toggles are drawn right above "Included components" (the plugin page's own config area).
  • On the same page, the dsh-browser-use row title is itself a "Configure" button (with a > arrow, accessible name Configure @weichen96/dsh-browser-use) — it opens the same form.

The form has only the jev group, drawn with the shell's own components in the same row layout as other plugins:

Field in the formMeaning
jev.enabledEnable browser_goal and browser_act's intent (spends TypeSafe and text-model quota)
jev.sourcesession inherits the main conversation; custom uses the URL/key you fill in below
jev.typesafe.baseURL / .model / .apiKeyEnv / .apiKeyTypeSafe endpoint, model name, key (credential name or plaintext)
jev.textModel.baseURL / .model / .apiKeyEnv / .apiKeytext-model endpoint, model name, key

These fields are .volatile(): a change takes effect on the spot (the next browser_goal or intent-bearing browser_act uses the new value); apiKey is submitted with role('secret') and never appears in any form response, and leaving it blank in the form means "don't touch the stored key".

All other switches are changed in the profile patch (after which DSH remounts the plugin, as before): mode, cdpEndpoint, executablePath, userDataDir, headless, allowScreenshots, requestTimeoutMs, delegate, delegateMode, subagentProvider, maxDepth, projectPath, pythonPath, reserveBrowserUseSlot, jev.typesafe.fallbackURL, jev.textModel.reasoning, jev.textModel.headers. They decide which tools exist, which interpreter runs, and whether a composition slot is taken — making them form fields would promise an "immediate effect" that can't be delivered.

One known edge: jev.enabled changes the tool set, and the conversation's own tool surface rebuilds immediately; but an already-running persistent browser subagent keeps the tools it was composed with, until it is swapped with fresh: true or the plugin is remounted (the browser_doctor Jev line always reflects the current config).

After a first pass through the UI, the YAML form below still works (and is the only entry point for fields like projectPath):

Write it into the config: of the id: dsh-browser-use line in the profile's cordis.patch.yml:

- id: dsh-browser-use
  config:
    # projectPath: /absolute/path/to/jev-ultrafast   # only to run an engine checkout instead of the bundled engine
    jev:
      enabled: true              # enable browser_goal and browser_act's intent; when false nothing is resolved and no key is sent
      source: session            # session: inherit the main conversation; custom: configure it yourself
      typesafe:
        baseURL: https://opencode.ai/zen/v1/systemone
        model: jev-1.13
      textModel:
        reasoning: thinking-disabled
        headers: { x-opencode-session: dsh-harness }

source: session (inherit from the main conversation): on each browser_goal or intent-bearing browser_act, it reads the model route the conversation is currently using (it follows you when you switch models) — the text model uses that route's baseURL, headers, model name and key (the DSH credential the provider config's apiKeyEnv points at); TypeSafe uses the same key, with its endpoint from jev.typesafe.baseURL (the TypeSafe endpoint can't be inferred from a chat route). You can only override typesafe.baseURL/model/fallbackURL, textModel.model (blank = the main conversation's model), textModel.reasoning and appended textModel.headers. It refuses with a fix hint when: the route is the Anthropic protocol, has no baseURL, uses a login session rather than an API key (e.g. a DeepSeek account login), or the conversation hasn't picked a model yet.

source: custom (configure separately):

    jev:
      enabled: true
      source: custom
      typesafe:
        baseURL: https://opencode.ai/zen/v1/systemone
        model: jev-1.13
        apiKeyEnv: OPENCODE_GATEWAY_API_KEY   # name of a DSH credential (stored on the Models page) or a DSH env var
      textModel:
        baseURL: https://opencode.ai/zen/go/v1
        model: deepseek-flash
        reasoning: thinking-disabled
        headers: { x-opencode-session: dsh-harness }
        apiKeyEnv: OPENCODE_GATEWAY_API_KEY   # or apiKey: plaintext (not recommended)

In both modes, the endpoint and key used by browser_goal and browser_act's intent come only from the plugin config / main conversation: the sidecar does not read the engine checkout's .env, and any TYPESAFE_* / TEXT_MODEL_* in the DSH process environment are cleared before the sidecar starts; the key is passed per request to the sidecar and is visible only during that run. browser_doctor shows the jev status and key source (never the key itself). The old allowGoalMode: true is still equivalent to jev.enabled: true.

FieldDefaultMeaning
projectPathempty (the bundled engine, in this package's .venv, installed automatically)an engine checkout to run instead; once set, only interpreters that import the engine from here are accepted, and the plugin installs nothing
pythonPathautopin an interpreter that already imports jev_ultrafast; once set, only it is tried, and the plugin installs nothing
modelaunchlaunch starts a browser; attach connects to a running one
cdpEndpoint—the DevTools address for attach (http(s):// or ws(s)://); blank auto-attaches to the Chrome you use with chrome://inspect remote debugging on
executablePathsystem Chromewhich browser to launch
userDataDirone per Session (~/.jev-ultrafast/browser/)dedicated profile directory
headlessfalselaunch without a window
reserveBrowserUseSlottruetake the ctx.browserUse singleton slot (when that service is mounted)
jev.enabled ✎falseenable browser_goal and browser_act's intent (spends TypeSafe and text-model quota); old name allowGoalMode
jev.source ✎sessionsession inherits the main conversation's route and key; custom uses the baseURL/key you configure below
jev.typesafeengine defaultTypeSafe endpoint: baseURL, model, fallbackURL; add apiKeyEnv / apiKey for custom. The form has the first two plus two key fields; fallbackURL is YAML-only
jev.textModelmain conversation / engine defaulttext model (OpenAI-compatible): model, reasoning (none / thinking-disabled), headers; add baseURL, apiKeyEnv / apiKey for custom. The form has baseURL / model plus two key fields; reasoning / headers are YAML-only
allowScreenshotstrueenable browser_screenshot
requestTimeoutMs180000per-request cap for the sidecar
delegatetruehand browser operations to a subagent; when false, mount them on this conversation (direct mode)
delegateModepersistentpersistent: one persistent browser subagent per conversation, receiving all later tasks; one-shot: one subagent per task, returning after it reports. Falls back to one-shot automatically when the provider doesn't support continuable subagents
subagentProviderspawnthe provider name in ctx.subagents; it must be able to compose an in-process subagent, otherwise it falls back to direct mode
maxDepth0delegation-depth cap for the subagent; 0 means use the provider's own recursion budget

✎ = appears in the form under Sidebar → Plugins → @weichen96/dsh-browser-use (the package page, or the "Configure" in the row title), with immediate effect (the next time the value is used); fields without ✎ are set only in the profile patch.