diff --git a/AGENT_INSTALL.md b/AGENT_INSTALL.md index ce4b58c70..e6116c759 100644 --- a/AGENT_INSTALL.md +++ b/AGENT_INSTALL.md @@ -131,7 +131,7 @@ For CLI harnesses, start with `bsk session start --no-focus --json`, retain the returned session ID, then navigate and observe using `--session `. Stop that session with `bsk session stop ` on success or failure. With multiple browsers, use `bsk browsers` and add `--browser ` when starting the session. -For dsh, use its injected `browser_*` tools instead. +For dsh, use its injected `bsk_*` tools instead. For the WorkBuddy/CodeBuddy or child-reaping-host workflow, use separate tool calls for startup, status, session creation, navigation/observation and final diff --git a/CHANGELOG.md b/CHANGELOG.md index 73ee0ce06..f7231b3e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,8 +7,22 @@ Starting from 0.2.0, CLI / Extension / DSH Plugin share the same version number. ## [Unreleased] +### Changed + +- **Breaking — DSH Plugin:** replace `browser_session`, `browser_page`, + `browser_inspect`, `browser_interact`, `browser_tabs`, and `browser_assist` with + the corresponding `bsk_*` names to coexist with other browser plugins. + Actions, arguments, results, and the `browser-skill` skill name are unchanged. + Update hardcoded calls and tool policies, restart the host, and reload the skill + in existing conversations. See the [migration guide](packages/dsh-plugin-browserskill/README.md#breaking-tool-api-migration-unreleased). + ### Fixed +- DSH Plugin: roll back incomplete tool registration, surface activation failures, + and retry at skill/session lifecycle boundaries without leaving a partial suite. + Include tool schemas in the first `/browser-skill` request, and keep failure and + recovery notices synchronized with model skill results + ([#444](https://github.com/Tencent/BrowserSkill/issues/444)). - Extension: input to a background Agent Window tab no longer keeps failing with `input_not_ready` after Chrome drops the session's focus override without a detach ([#355](https://github.com/Tencent/BrowserSkill/issues/355)). The session's diff --git a/README.md b/README.md index fb8e9db96..15b9f3645 100644 --- a/README.md +++ b/README.md @@ -154,7 +154,7 @@ In WorkBuddy/CodeBuddy, or hosts that reap command children, the agent should re ## DeepSeek Harness plugin -The [DSH plugin](packages/dsh-plugin-browserskill/README.md) adds native `browser_*` tools, browser task previews, and screenshot results to the DeepSeek Harness Web UI. It uses the same `bsk` CLI and extension and includes its own BrowserSkill skill. +The [DSH plugin](packages/dsh-plugin-browserskill/README.md) adds native `bsk_*` tools, browser task previews, and screenshot results to the DeepSeek Harness Web UI. It uses the same `bsk` CLI and extension and includes its own BrowserSkill skill. With DeepSeek Harness, pnpm, and `bsk` installed and the extension connected, add the plugin to your profile: diff --git a/README.zh-CN.md b/README.zh-CN.md index ef7bcf78b..90f1f12b4 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -154,7 +154,7 @@ bsk session stop ## DeepSeek Harness 插件 -[DSH 插件](packages/dsh-plugin-browserskill/README.md) 在 DeepSeek Harness Web UI 中提供原生 `browser_*` 工具、浏览器任务预览和截图结果。它使用同一套 `bsk` CLI 与扩展,并自带 BrowserSkill skill。 +[DSH 插件](packages/dsh-plugin-browserskill/README.md) 在 DeepSeek Harness Web UI 中提供原生 `bsk_*` 工具、浏览器任务预览和截图结果。它使用同一套 `bsk` CLI 与扩展,并自带 BrowserSkill skill。 安装好 DeepSeek Harness、pnpm 和 `bsk`,连接扩展后,将插件加入你的 profile: diff --git a/apps/extension/src/entrypoints/popup/profile-instructions.test.tsx b/apps/extension/src/entrypoints/popup/profile-instructions.test.tsx index 327f31018..4aadd8687 100644 --- a/apps/extension/src/entrypoints/popup/profile-instructions.test.tsx +++ b/apps/extension/src/entrypoints/popup/profile-instructions.test.tsx @@ -23,7 +23,7 @@ describe("profile instructions", () => { const text = vi.mocked(navigator.clipboard.writeText).mock.calls[0]?.[0]; expect(text).toContain('browser "Work" (instance ID: a1234567)'); expect(text).toContain("bsk session start --browser a1234567 --json"); - expect(text).toContain('browser_session({ action: "start", browser: "a1234567" })'); + expect(text).toContain('bsk_session({ action: "start", browser: "a1234567" })'); expect(text).toContain("use the tool call instead of running the CLI command separately"); expect(text).toContain("every new session for this task"); expect(text).toContain("Do not omit --browser / browser or switch to another instance"); @@ -70,7 +70,7 @@ describe("profile instructions", () => { "bsk session start --browser b1234567 --json", ); expect(vi.mocked(navigator.clipboard.writeText).mock.calls[1]?.[0]).toContain( - 'browser_session({ action: "start", browser: "b1234567" })', + 'bsk_session({ action: "start", browser: "b1234567" })', ); }); it("reports clipboard failure and allows retry without claiming success", async () => { @@ -90,7 +90,7 @@ describe("profile instructions", () => { const text = vi.mocked(navigator.clipboard.writeText).mock.calls[0]?.[0]; expect(text).toContain(JSON.stringify(label)); expect(text).toContain("CLI: bsk session start --browser a1234567 --json"); - expect(text).toContain('browser_session({ action: "start", browser: "a1234567" })'); + expect(text).toContain('bsk_session({ action: "start", browser: "a1234567" })'); expect(await screen.findByRole("button", { name: "Copied" })).toBeTruthy(); }); it("discards pending feedback when the saved name changes and copies the new name", async () => { @@ -153,7 +153,7 @@ describe("profile instructions", () => { "bsk session start --browser a1234567 --json", ); expect(vi.mocked(navigator.clipboard.writeText).mock.calls[0]?.[0]).toContain( - 'browser_session({ action: "start", browser: "a1234567" })', + 'bsk_session({ action: "start", browser: "a1234567" })', ); expect(vi.mocked(navigator.clipboard.writeText).mock.calls[0]?.[0]).toContain( "--browser / browser", diff --git a/apps/extension/src/entrypoints/popup/profile-instructions.tsx b/apps/extension/src/entrypoints/popup/profile-instructions.tsx index ec229c8c0..029d291d7 100644 --- a/apps/extension/src/entrypoints/popup/profile-instructions.tsx +++ b/apps/extension/src/entrypoints/popup/profile-instructions.tsx @@ -20,7 +20,7 @@ export function ProfileInstructions({ name: JSON.stringify(label || t("popup.profile.unnamed")), instanceId, command: `bsk session start --browser ${instanceId} --json`, - toolCall: `browser_session({ action: "start", browser: ${JSON.stringify(instanceId)} })`, + toolCall: `bsk_session({ action: "start", browser: ${JSON.stringify(instanceId)} })`, }); useEffect(() => { diff --git a/apps/extension/src/video/capture.browser.test.ts b/apps/extension/src/video/capture.browser.test.ts index 9b2eac56f..ac678af56 100644 --- a/apps/extension/src/video/capture.browser.test.ts +++ b/apps/extension/src/video/capture.browser.test.ts @@ -730,12 +730,12 @@ describe.skipIf(!process.env.BSK_VIDEO_CHROME || !process.env.BSK_VIDEO_BSK)( // navigation and exports after its owned session is gone. const dsh = await createDshVideoFixture(executable, env, path.join(directory, "dsh")); try { - const task = await dsh.call<{ sessionId: string }>("browser_session", { + const task = await dsh.call<{ sessionId: string }>("bsk_session", { action: "start", }); const started = await dsh.call<{ recording: { recording_id: string; state: string; tab_id: number }; - }>("browser_inspect", { + }>("bsk_inspect", { action: "video", videoAction: "start", session: task.sessionId, @@ -743,7 +743,7 @@ describe.skipIf(!process.env.BSK_VIDEO_CHROME || !process.env.BSK_VIDEO_BSK)( }); expect(started.recording.state).toBe("recording"); const recordingId = started.recording.recording_id; - await dsh.call("browser_page", { + await dsh.call("bsk_page", { action: "navigate", session: task.sessionId, url: `http://127.0.0.1:${address.port}/red`, @@ -764,12 +764,12 @@ describe.skipIf(!process.env.BSK_VIDEO_CHROME || !process.env.BSK_VIDEO_BSK)( await new Promise((resolve) => setTimeout(resolve, 1200)); const finished = await dsh.call<{ recording: { state: string; completeness: string; byte_size: number }; - }>("browser_inspect", { action: "video", videoAction: "stop", recordingId }); + }>("bsk_inspect", { action: "video", videoAction: "stop", recordingId }); expect(finished.recording.state).toBe("ready"); expect(finished.recording.completeness).toBe("complete"); - await dsh.call("browser_session", { action: "stop", session: task.sessionId }); + await dsh.call("bsk_session", { action: "stop", session: task.sessionId }); const output = path.join(directory, "dsh.mp4"); - await dsh.call("browser_inspect", { + await dsh.call("bsk_inspect", { action: "video", videoAction: "save", recordingId, @@ -777,7 +777,7 @@ describe.skipIf(!process.env.BSK_VIDEO_CHROME || !process.env.BSK_VIDEO_BSK)( }); expect((await stat(output)).size).toBe(finished.recording.byte_size); await expect( - dsh.call("browser_inspect", { + dsh.call("bsk_inspect", { action: "video", videoAction: "save", recordingId, @@ -785,7 +785,7 @@ describe.skipIf(!process.env.BSK_VIDEO_CHROME || !process.env.BSK_VIDEO_BSK)( }), ).rejects.toThrow(/Output exists/); const list = await dsh.call<{ recordings: { recording_id: string }[] }>( - "browser_inspect", + "bsk_inspect", { action: "video", videoAction: "list" }, ); expect(list.recordings.map((value) => value.recording_id)).toEqual([recordingId]); diff --git a/docs/browser-profiles.md b/docs/browser-profiles.md index c9457e3b3..ce23a1d63 100644 --- a/docs/browser-profiles.md +++ b/docs/browser-profiles.md @@ -55,7 +55,7 @@ routing identifiers, not independent proof of a filesystem path. Use the verified popup instance ID in the plugin's session tool: ```text -browser_session({ action: "start", browser: "" }) +bsk_session({ action: "start", browser: "" }) ``` **Copy instructions** includes this tool call alongside the CLI command. diff --git a/docs/scroll-to.md b/docs/scroll-to.md index d8176d180..9d28fa4bf 100644 --- a/docs/scroll-to.md +++ b/docs/scroll-to.md @@ -9,7 +9,7 @@ distance or scroll direction. Use [wheel](wheel.md) for native directional wheel | --- | --- | | CLI | `bsk scroll-to` | | Wire protocol | `tool.scroll_to` | -| DeepSeek Harness | `browser_interact` with `action: "scroll-to"` | +| DeepSeek Harness | `bsk_interact` with `action: "scroll-to"` | ## CLI @@ -97,7 +97,7 @@ The plugin exposes the same action with its usual camelCase parameters: } ``` -Call this through `browser_interact` using a plugin-owned session. Its result +Call this through `bsk_interact` using a plugin-owned session. Its result contains `session`, `tabId`, `x`, `y`, `width` and `height` with the same bounds semantics. Omitted `session` uses the plugin's current session. diff --git a/docs/structured-extraction.md b/docs/structured-extraction.md index 102cb99d6..4e001859f 100644 --- a/docs/structured-extraction.md +++ b/docs/structured-extraction.md @@ -186,12 +186,12 @@ allows a consumer to detect a mismatched pair. ## DSH plugin -The existing **browser_inspect** tool gains **action: "extract"**: +The existing **bsk_inspect** tool gains **action: "extract"**: ~~~text -browser_inspect({ action: "extract", session: "", extractKind: "discover" }) -browser_inspect({ action: "extract", session: "", extractKind: "table", extractTarget: "" }) -browser_inspect({ action: "extract", session: "", extractKind: "table", selector: "#orders", +bsk_inspect({ action: "extract", session: "", extractKind: "discover" }) +bsk_inspect({ action: "extract", session: "", extractKind: "table", extractTarget: "" }) +bsk_inspect({ action: "extract", session: "", extractKind: "table", selector: "#orders", extractFormat: "csv", output: "/absolute/path/orders.csv", csvSafe: true }) ~~~ @@ -203,8 +203,8 @@ requires an output path so the plugin always receives structured JSON. The plugi normal session registry, runner and queue; it does not introduce arbitrary page-script evaluation. Output paths are on the CLI host; relative paths resolve against that process's working directory. Prefer absolute paths in harness calls. -Extraction shares browser_inspect's output parameter with debug export and video -save. Its model guidance lives in the browser_inspect description and parameter +Extraction shares bsk_inspect's output parameter with debug export and video +save. Its model guidance lives in the bsk_inspect description and parameter schema rather than a separate DSH skill reference, keeping the DSH skill entry within its 4,500-byte budget in both LF and CRLF checkouts. diff --git a/docs/video-recording.md b/docs/video-recording.md index b461a6702..a26fdc1ac 100644 --- a/docs/video-recording.md +++ b/docs/video-recording.md @@ -179,7 +179,7 @@ BSK_VIDEO_CHROME=/path/to/chrome BSK_VIDEO_BSK=../../target/debug/bsk \ ``` The extension's minimum Chrome version remains 125. Codec support is validated at -runtime. DSH uses `browser_inspect(action=video)` with `videoAction` set to start, status, +runtime. DSH uses `bsk_inspect(action=video)` with `videoAction` set to start, status, stop, save, list, or discard. Its six public tool schemas are retained. Start follows the session queue; artifact operations bypass that queue so status/stop remain available during human help. A plugin-local allowlist of returned recording @@ -190,11 +190,11 @@ this allowlist; the extension library remains available for recovery. CLI partia stop/save errors retain their recording metadata and saved path in the tool error. ```text -browser_inspect({ action: "video", videoAction: "start", session: "", durationMs: 60000 }) +bsk_inspect({ action: "video", videoAction: "start", session: "", durationMs: 60000 }) // Execute task operations after state=recording. -browser_inspect({ action: "video", videoAction: "stop", recordingId: "" }) +bsk_inspect({ action: "video", videoAction: "stop", recordingId: "" }) // End the task. Preview and Save As remain available in the extension. -browser_inspect({ action: "video", videoAction: "save", recordingId: "", output: "" }) +bsk_inspect({ action: "video", videoAction: "save", recordingId: "", output: "" }) ``` diff --git a/docs/website-debugging.md b/docs/website-debugging.md index c187d8e2c..4529725f2 100644 --- a/docs/website-debugging.md +++ b/docs/website-debugging.md @@ -67,7 +67,7 @@ Follow `next_offset` while present. Offsets count UTF-16 code units, matching th extension. RFC 6901 `--pointer` works only on a complete retained JSON body and is applied after redaction. No network request is repeated by these reads. -DSH uses `browser_inspect` with `action: "debug"`, `debugAction` matching the CLI +DSH uses `bsk_inspect` with `action: "debug"`, `debugAction` matching the CLI subcommand, and camelCase options (`runId`, `tabId`, `maxChars`). The six public tools, existing session ownership, cancellation and queue remain unchanged. The wire endpoint is `tool.debug`; schemas are in `crates/bsk-protocol/schema`. @@ -420,7 +420,7 @@ bsk debug replay --session --replay-file replay.json ``` `--rule` and `--replay` also accept inline JSON. DSH exposes these as JSON-string -`rule` / `replay` parameters on `browser_inspect(action: "debug")`, with the same +`rule` / `replay` parameters on `bsk_inspect(action: "debug")`, with the same `debugAction` values. File input avoids putting large bodies in command arguments. Replay sends a **new** request and may change server data. It uses a dedicated diff --git a/docs/wheel.md b/docs/wheel.md index 2de3d26fd..9ea4b55c3 100644 --- a/docs/wheel.md +++ b/docs/wheel.md @@ -8,7 +8,7 @@ when the goal is simply to bring an existing element into view. | --- | --- | | CLI | `bsk wheel` | | Wire protocol | `tool.wheel` | -| DeepSeek Harness | `browser_interact` with `action: "wheel"` | +| DeepSeek Harness | `bsk_interact` with `action: "wheel"` | ## Usage diff --git a/packages/dsh-plugin-browserskill/README.md b/packages/dsh-plugin-browserskill/README.md index b00f20159..9d1476d75 100644 --- a/packages/dsh-plugin-browserskill/README.md +++ b/packages/dsh-plugin-browserskill/README.md @@ -4,7 +4,7 @@ Use [BrowserSkill](https://github.com/Tencent/BrowserSkill) in [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (`dsh`) to browse -websites, fill forms, and capture screenshots through native `browser_*` tools. +websites, fill forms, and capture screenshots through native `bsk_*` tools. Browser tasks run in Agent Windows, with a live view in the dsh Web UI. ## Installation @@ -54,38 +54,81 @@ dsh plugin --profile web update @wxg-prc-cpg/browser-skill-dsh-plugin --latest Restart that dsh profile after upgrading. This command updates the plugin; update the `bsk` CLI and browser extension separately when a release requires it. +### Breaking tool API migration (unreleased) + +The next coordinated release replaces all six `browser_*` tool names with stable +BrowserSkill-specific names. This avoids collisions with other browser plugins +such as `dsh-builtin-browser`; both plugins keep their own tools and sessions. + +| Previous name | New name | +| --- | --- | +| `browser_session` | `bsk_session` | +| `browser_page` | `bsk_page` | +| `browser_inspect` | `bsk_inspect` | +| `browser_interact` | `bsk_interact` | +| `browser_tabs` | `bsk_tabs` | +| `browser_assist` | `bsk_assist` | + +Actions, parameters, results, and `/browser-skill` are unchanged. The old tool +names are not registered as aliases. After upgrading, restart the DSH profile and +invoke `/browser-skill` again in existing conversations to load the new instructions. +Update hardcoded tool calls, allow/deny lists, and `toolOrder` entries to the new +names. Do not replay old calls unchanged: another plugin may own those names. + +Existing conversation logs and screenshot attachments are left intact. New +`bsk_inspect` results use the screenshot view; old `browser_inspect` cards may use +DSH's generic renderer and do not retain the custom thumbnail/preview interaction. +This migration must ship as a breaking release, with the shared CLI/extension/plugin +version coordinated by the release process, rather than as a patch to 0.3.2. + ## Tools | Tool | Actions | Purpose | | --- | --- | --- | -| `browser_session` | `start`, `stop`, `list` | Manage plugin-owned Agent Window sessions. | -| `browser_page` | `navigate`, `back`, `forward`, `reload`, `wait`, `wait-for-element` | Navigate the active tab; wait for page lifecycle events or one element condition. | -| `browser_inspect` | `observe`, `snapshot`, `html`, `screenshot`, `console`, `network`, `debug`, `video`, `extract` | Inspect page state, debug websites, capture screenshots or requested task videos, and export structured tables/lists. | -| `browser_interact` | `click`, `hover`, `wheel`, `scroll-to`, `focus`, `blur`, `fill`, `select`, `press` | Interact with controls using fresh refs or selectors. | -| `browser_tabs` | `list`, `create`, `select`, `close`, `borrow`, `return` | Manage Agent Window tabs and temporarily borrow user tabs. | -| `browser_assist` | `resize`, `emulate`, `request-help` | Resize or emulate the browser and pause for human-only steps. | - -For `browser_page` with `action: "wait-for-element"`, see the +| `bsk_session` | `start`, `stop`, `list` | Manage plugin-owned Agent Window sessions. | +| `bsk_page` | `navigate`, `back`, `forward`, `reload`, `wait`, `wait-for-element` | Navigate the active tab; wait for page lifecycle events or one element condition. | +| `bsk_inspect` | `observe`, `snapshot`, `html`, `screenshot`, `console`, `network`, `debug`, `video`, `extract` | Inspect page state, debug websites, capture screenshots or requested task videos, and export structured tables/lists. | +| `bsk_interact` | `click`, `hover`, `wheel`, `scroll-to`, `focus`, `blur`, `fill`, `select`, `press` | Interact with controls using fresh refs or selectors. | +| `bsk_tabs` | `list`, `create`, `select`, `close`, `borrow`, `return` | Manage Agent Window tabs and temporarily borrow user tabs. | +| `bsk_assist` | `resize`, `emulate`, `request-help` | Resize or emulate the browser and pause for human-only steps. | + +For `bsk_page` with `action: "wait-for-element"`, see the [element-wait reference](skill/references/interaction-details.md#element-waits) for supported conditions, timeout results and recovery with existing single actions. For native wheel input (`action: "wheel"`), see the [wheel reference](../../docs/wheel.md) for signed deltas, optional targets, result semantics and interruption. -For `browser_interact` with `action: "scroll-to"`, see the +For `bsk_interact` with `action: "scroll-to"`, see the [scroll-to reference](../../docs/scroll-to.md) for parameters, visible bounds and errors. -For `browser_inspect` with `action: "extract"`, see +For `bsk_inspect` with `action: "extract"`, see [structured extraction](../../docs/structured-extraction.md) for discovery, list fields, JSON/CSV output and loaded-DOM completeness. Arbitrary page-script evaluation and interaction recording are not supported. +### Activation failures + +The six tools register as a complete suite. If any registration fails, the plugin +rolls back that attempt and reports the failing tool through DSH's logger. A model +invocation of `skill` returns an error instead of claiming successful activation; +slash-command and restored conversations receive a scoped notice. Unrelated +conversations continue normally, and repeated identical failures do not flood logs. + +Resolve the reported registration error, then invoke `/browser-skill` again or +start the next turn to retry. Session entry and service discovery also retry a +pending activation; streaming events do not. The affected conversation receives +one recovery notice. If the failed model call never delivered the skill body, +the notice asks the model to load it before using the tools. With `lazyTools: false`, +a registration failure fails plugin startup and releases its resources; reload +after fixing it. + ## Multi-session model One agent conversation can drive several browser sessions at once: -- `browser_session` with `action: start` returns the session id and makes it the **current session**. +- `bsk_session` with `action: start` returns the session id and makes it the **current session**. - Every operation tool accepts an optional `session` argument. When omitted, the call acts on the current session (the one most recently started or used); when given, that session becomes current. - Every tool result echoes the session it actually acted on, so the model never has to guess. @@ -93,7 +136,7 @@ One agent conversation can drive several browser sessions at once: - Unloading the plugin stops every session it started and kills in-flight bsk processes. Starts are journaled before creating a window. Lost replies and failed cleanup remain -recoverable on reload; `browser_session action=list` reports `pendingCleanup`, and stop +recoverable on reload; `bsk_session action=list` reports `pendingCleanup`, and stop can retry it even when there is no current session. This requires a CLI and daemon that support recoverable starts. See [the lifecycle contract](../../docs/recoverable-session-starts.md). @@ -108,7 +151,7 @@ until acknowledged and do not occupy browser capacity. **Ownership boundary**: the bsk daemon may be shared with other agents, terminals, or dsh instances. The plugin therefore only ever sees and operates on sessions it created itself — an explicit `session` argument naming a foreign or unknown id is rejected, the `list` action on -`browser_session` shows plugin-created sessions only (no daemon-wide view), and stop/unload cleanup +`bsk_session` shows plugin-created sessions only (no daemon-wide view), and stop/unload cleanup can never touch a session owned by another program. ## Configuration @@ -158,13 +201,14 @@ All fields are optional; omitted fields use the defaults below: | `lazyTools` | `true` | Reveal the browser tools when the skill is invoked. Set `false` to register them at startup. | With `lazyTools: true`, only the skill's catalog entry is initially advertised to -the model. The six `browser_*` tool schemas are added to the system prompt after -the `browser-skill` skill is successfully invoked, either by the model or through -`/browser-skill`. Set `lazyTools: false` to make the tools available immediately. +the model. A successful model `skill` call makes the six `bsk_*` schemas available +in the next step. A user `/browser-skill` gesture activates them when the host +claims the input, before prompt assembly, so the first request includes both the +skill instructions and tool schemas. Set `lazyTools: false` to register at startup. After a plugin reload, a live or resumed conversation's successful skill invocation restores the tools from its stored history. If an older plugin reports -`unknown tool "browser_session"`, invoke `skill browser-skill` again, or set +`unknown tool "bsk_session"`, invoke `skill browser-skill` again, or set `lazyTools: false` in the profile patch as a temporary workaround. ## Live browser view @@ -267,7 +311,7 @@ tab, confirms recording is active, performs the task, then stops video before ending the session. No manual Start click is required. Preview and Save As are in the extension's Features → Video recording → Recent recordings. -`browser_inspect` with `action: "video"` exposes `videoAction` start/status/stop/save/ +`bsk_inspect` with `action: "video"` exposes `videoAction` start/status/stop/save/ list/discard. The default is a silent, fixed-tab MP4 with a 60-second limit (up to 10 minutes). Export requires an explicit `output` path on the harness host; the extension's Save As writes on the browser computer. Partial recordings and limits diff --git a/packages/dsh-plugin-browserskill/docs/development.md b/packages/dsh-plugin-browserskill/docs/development.md index b93eb4ee4..faf579a8b 100644 --- a/packages/dsh-plugin-browserskill/docs/development.md +++ b/packages/dsh-plugin-browserskill/docs/development.md @@ -11,13 +11,27 @@ extension perform the browser operations. The published package name is also the Cordis plugin id, client bundle registration id, and `cordis.patch.yml` plugin name. Keep these identifiers aligned so dsh can load both halves of the plugin. +## Tool registration contract + +`src/tool-names.json` is the shared public-name contract for host registration, +client toolviews, and skill validation. Actions still dispatch to private operation +names such as `session.start`; keep those routes and the existing ownership, +cancellation, and observation behavior unchanged when editing schemas. + +The suite belongs to the plugin's global scope. Agent-scoped registration would +shadow another plugin's tools rather than make the tools coexist. All definitions +are built before the first registration. A registration failure disposes this +attempt's entries in reverse order and retains the failing name and cause. This +is rollback, not atomic publication: DSH emits `tools/change` for each entry. +Disposal attempts every owned release and is idempotent. + ## Agent skill Beyond the tools, the plugin publishes the **`browser-skill` agent skill** through the harness's official skill seam (`ctx.skills.register`): the catalog entry (name + routing description) is resident in ``, and the body is loaded only when the model invokes the `skill` tool. Its source is the DSH-specific `skill/` directory: a compact `SKILL.md` plus -conditional details in `references/`. Both document only structured `browser_*` calls +conditional details in `references/`. Both document only structured `bsk_*` calls and their plugin semantics. The crate-local CLI skill is intentionally not concatenated: its command examples belong to a different execution interface and would bypass the plugin's ownership, live observation UI, cancellation, and cleanup path if followed directly. @@ -49,6 +63,16 @@ Failed registration retains the invocation proof and retries on the next turn, session entry, service discovery, or successful skill invocation. Streaming events continue to fold without repeated registration attempts or warnings. +The live model trigger uses `tools/post-execute`, before final materialization, +and preserves errors, cancellations, and existing blocked decisions. Failed suite +activation blocks that skill result with recovery guidance. `agent/pre-step` +wraps the official skill injection to report gesture/restore failures in the +requesting conversation only. The later durable append of the same gesture does +not retry it. Notices are deduplicated per session and followed by a recovery +notice when activation succeeds; host errors are deduplicated until recovery. +Cleanup ownership is installed before eager registration so a failed startup +also disposes the start journal, runner, and observation service. + ## Observation subscriptions and routes - **Native presentation**: the client optionally injects `sidebarRight` and @@ -113,7 +137,7 @@ events continue to fold without repeated registration attempts or warnings. card). Screenshots additionally attach the image itself when the host mounts an attachment store and the active model route declares image input; otherwise the PNG path is returned. - **Web UI toolview (browser half)**: the package is dual-face. `dsh.client` (platform `web`) ships - `lib/client.cjs`, which registers a keyed `tool.call.toolview` view for `browser_inspect`. The + `lib/client.cjs`, which registers a keyed `tool.call.toolview` view for `bsk_inspect`. The custom view keeps a terminal block for every inspect action and, when a screenshot result carries an image block, resolves the durable attachment through the client session's authorized `readAttachment` RPC and renders it with the plugin-owned `ScreenshotImage` thumbnail and diff --git a/packages/dsh-plugin-browserskill/package.json b/packages/dsh-plugin-browserskill/package.json index e1df05ccb..b83befdb4 100644 --- a/packages/dsh-plugin-browserskill/package.json +++ b/packages/dsh-plugin-browserskill/package.json @@ -1,6 +1,6 @@ { "name": "@wxg-prc-cpg/browser-skill-dsh-plugin", - "description": "DeepSeek Harness tool plugin that exposes BrowserSkill browser automation (browser_* tools) to the model", + "description": "DeepSeek Harness tool plugin that exposes BrowserSkill browser automation (bsk_* tools) to the model", "version": "0.3.2", "license": "MIT", "publishConfig": { @@ -85,9 +85,6 @@ "@deepseek-ai/dsh-client-ui-tool": { "optional": true }, - "@deepseek-ai/dsh-llm": { - "optional": true - }, "react": { "optional": true } @@ -96,6 +93,7 @@ "@browser-skill/ui": "workspace:*", "@deepseek-ai/cordis": "4.0.2", "@deepseek-ai/dsh-agent": "0.1.5-rc.3", + "@deepseek-ai/dsh-agent-loop": "0.1.5-rc.3", "@deepseek-ai/dsh-api-session-controller": "0.1.5-rc.3", "@deepseek-ai/dsh-attachment": "0.1.5-rc.3", "@deepseek-ai/dsh-client-store": "0.1.5-rc.3", @@ -110,7 +108,10 @@ "@deepseek-ai/dsh-llm": "0.1.5-rc.3", "@deepseek-ai/dsh-scope": "0.1.5-rc.3", "@deepseek-ai/dsh-session": "0.1.5-rc.3", + "@deepseek-ai/dsh-session-projection": "0.1.5-rc.3", "@deepseek-ai/dsh-skill": "0.1.5-rc.3", + "@deepseek-ai/dsh-system-prompt": "0.1.5-rc.3", + "@deepseek-ai/dsh-tool-skill": "0.1.5-rc.3", "@deepseek-ai/dsh-tools": "0.1.5-rc.3", "@deepseek-ai/schemastery": "3.18.2", "@remixicon/react": "^4.9.0", diff --git a/packages/dsh-plugin-browserskill/scripts/validate-skill.mjs b/packages/dsh-plugin-browserskill/scripts/validate-skill.mjs index f66bde14e..80b4afbbc 100644 --- a/packages/dsh-plugin-browserskill/scripts/validate-skill.mjs +++ b/packages/dsh-plugin-browserskill/scripts/validate-skill.mjs @@ -58,7 +58,7 @@ export function validateSkillDirectory(directory, { maxEntryBytes, browserTools !/```(?:bash|sh|shell)\b/i.test(content), `DSH skill contains shell commands: ${file}`, ); - for (const tool of content.match(/\bbrowser_[a-z][a-z_]*\b/g) ?? []) { + for (const tool of content.match(/\b(?:bsk|browser)_[a-z][a-z_]*\b/g) ?? []) { assert(browserTools.includes(tool), `Unsupported DSH tool ${tool} in ${file}`); mentionedTools.add(tool); } @@ -73,11 +73,7 @@ export function validateSkillDirectory(directory, { maxEntryBytes, browserTools return { name, description, content: `${source.slice(frontmatter[0].length).trim()}\n`, files }; } -export const DSH_BROWSER_TOOLS = [ - "browser_session", - "browser_page", - "browser_inspect", - "browser_interact", - "browser_tabs", - "browser_assist", -]; +// Host schemas, client toolviews, and packaged instructions share one contract. +export const DSH_BROWSER_TOOLS = Object.values( + JSON.parse(readFileSync(new URL("../src/tool-names.json", import.meta.url), "utf8")), +); diff --git a/packages/dsh-plugin-browserskill/skill/SKILL.md b/packages/dsh-plugin-browserskill/skill/SKILL.md index 6ca72bc9d..8779593aa 100644 --- a/packages/dsh-plugin-browserskill/skill/SKILL.md +++ b/packages/dsh-plugin-browserskill/skill/SKILL.md @@ -1,6 +1,6 @@ --- name: browser-skill -description: Automate the user's logged-in Chromium through this plugin's injected browser_* tools. Use to read pages, fill forms, operate tabs, inspect page activity, debug a website, or test a UI. +description: Automate the user's logged-in Chromium through this plugin's injected bsk_* tools. Use to read pages, fill forms, operate tabs, inspect page activity, debug a website, or test a UI. --- # browser-skill for DeepSeek Harness @@ -26,16 +26,16 @@ For remote setup/pairing, follow the [remote guide](https://github.com/Tencent/B For a new page: ```text - browser_session({ action: "start" }) - browser_page({ action: "navigate", session: "", url: "https://example.com" }) - browser_inspect({ action: "observe", session: "" }) + bsk_session({ action: "start" }) + bsk_page({ action: "navigate", session: "", url: "https://example.com" }) + bsk_inspect({ action: "observe", session: "" }) ``` 2. For an existing user tab, read [tab borrowing](references/tabs-and-profiles.md) first. Replace example IDs/refs with actual results. Pass `session` when more than one exists; never use foreign IDs. 3. Observe after page changes; check ambiguous results once. Stop when success is visible. Stop requested video first, then on success or failure call - `browser_session({ action: "stop", session: "" })` unless keeping the session + `bsk_session({ action: "stop", session: "" })` unless keeping the session open is part of the user's request. Stopping returns borrowed tabs, leaving them open in the user's window. @@ -53,7 +53,7 @@ exact markup, and `screenshot` for visuals. To fill an observed field `@e3`: ```text -browser_interact({ action: "fill", session: "", target: "@e3", value: "text" }) +bsk_interact({ action: "fill", session: "", target: "@e3", value: "text" }) ``` Refs invalidate after navigation; large DOM changes may stale them too. Observe again. @@ -74,8 +74,8 @@ the working directory. Read the matching file before acting; do not preload all | When | Read | | --- | --- | | Website failure, request/performance investigation, reproduction evidence, or an HTTP experiment | [Website debugging](references/debugging.md) | -| Required profile, borrowing/returning user tabs with `browser_tabs`, or remote tab ownership | [Tabs and profiles](references/tabs-and-profiles.md) | -| Hover menus, scrolling, `nextCursor`, console/network, or window/device settings with `browser_assist` | [Interaction details](references/interaction-details.md) | +| Required profile, borrowing/returning user tabs with `bsk_tabs`, or remote tab ownership | [Tabs and profiles](references/tabs-and-profiles.md) | +| Hover menus, scrolling, `nextCursor`, console/network, or window/device settings with `bsk_assist` | [Interaction details](references/interaction-details.md) | | Screenshot or `[visual:screenshot]`/Canvas interaction | [Screenshots and Canvas](references/screenshots-and-canvas.md) | | Video recording or MP4 export | [Video](references/video.md) | | Login/CAPTCHA/OTP/consent/payment confirmation, disabled help, failed operations, or interrupted cleanup | [Human help and recovery](references/help-and-recovery.md) | diff --git a/packages/dsh-plugin-browserskill/skill/references/debugging.md b/packages/dsh-plugin-browserskill/skill/references/debugging.md index 9b0df7aee..03f797054 100644 --- a/packages/dsh-plugin-browserskill/skill/references/debugging.md +++ b/packages/dsh-plugin-browserskill/skill/references/debugging.md @@ -1,6 +1,6 @@ # Website debugging -Use `browser_inspect` with `action: "debug"` to record and investigate a website +Use `bsk_inspect` with `action: "debug"` to record and investigate a website problem. Keep ordinary browsing capture-free. All examples use the owning `session`; use returned IDs and the owned `tabId` when targeting a specific tab. Read loaded schemas for parameters; `debugAction: "capabilities"` reports supported @@ -13,9 +13,9 @@ actions, limits, filters and build information. navigating or reproducing; earlier traffic cannot be recovered. ```text - browser_inspect({ action: "debug", debugAction: "start", session: "", name: "Nickname does not persist" }) - browser_page({ action: "navigate", session: "", url: "https://example.com/profile" }) - browser_inspect({ action: "observe", session: "" }) + bsk_inspect({ action: "debug", debugAction: "start", session: "", name: "Nickname does not persist" }) + bsk_page({ action: "navigate", session: "", url: "https://example.com/profile" }) + bsk_inspect({ action: "observe", session: "" }) ``` 2. Retain the returned run ID; pass it as `runId` for subsequent reads. Reproduce @@ -28,9 +28,9 @@ actions, limits, filters and build information. 4. Use `stop` to save the final record, then export before stopping the session: ```text - browser_inspect({ action: "debug", debugAction: "stop", session: "" }) - browser_inspect({ action: "debug", debugAction: "export", session: "", runId: "", output: "" }) - browser_session({ action: "stop", session: "" }) + bsk_inspect({ action: "debug", debugAction: "stop", session: "" }) + bsk_inspect({ action: "debug", debugAction: "export", session: "", runId: "", output: "" }) + bsk_session({ action: "stop", session: "" }) ``` `export` writes a new file without overwriting and returns its path/size. Exporting diff --git a/packages/dsh-plugin-browserskill/skill/references/help-and-recovery.md b/packages/dsh-plugin-browserskill/skill/references/help-and-recovery.md index 499f2edb9..4249084a9 100644 --- a/packages/dsh-plugin-browserskill/skill/references/help-and-recovery.md +++ b/packages/dsh-plugin-browserskill/skill/references/help-and-recovery.md @@ -1,6 +1,6 @@ # Human help and recovery -With help enabled, use `browser_assist` action `request-help` for login, CAPTCHA, +With help enabled, use `bsk_assist` action `request-help` for login, CAPTCHA, OTP, payment confirmation, consent, or after two attempts without progress. Supply a precise prompt and fresh targets; completion criteria need a stable success signal. `all` and `any` support at most eight conditions in total. `urlMatches` accepts diff --git a/packages/dsh-plugin-browserskill/skill/references/interaction-details.md b/packages/dsh-plugin-browserskill/skill/references/interaction-details.md index cc4ab1db6..b656f5f6d 100644 --- a/packages/dsh-plugin-browserskill/skill/references/interaction-details.md +++ b/packages/dsh-plugin-browserskill/skill/references/interaction-details.md @@ -2,10 +2,10 @@ ## Element waits -`browser_page` supports `action: "wait-for-element"` for an explicit element +`bsk_page` supports `action: "wait-for-element"` for an explicit element condition. For example, if `@e2` is an observed loading indicator after the triggering action, use -`browser_page({ action: "wait-for-element", target: "@e2", state: "hidden" })`, +`bsk_page({ action: "wait-for-element", target: "@e2", state: "hidden" })`, then check `satisfied` and observe the result. Replace the example ref with the actual one. Skip waiting when the page is already ready. @@ -50,5 +50,5 @@ Continuation uses the same capture without refresh/depth changes. New observe/snapshot or changed page identity invalidates it. Console/network are bounded read-only diagnostics; follow sequence cursors. -Wait only for expected navigation. `browser_assist` resizes windows or emulates +Wait only for expected navigation. `bsk_assist` resizes windows or emulates a device for one tab. diff --git a/packages/dsh-plugin-browserskill/skill/references/screenshots-and-canvas.md b/packages/dsh-plugin-browserskill/skill/references/screenshots-and-canvas.md index 9277fced2..5347413fd 100644 --- a/packages/dsh-plugin-browserskill/skill/references/screenshots-and-canvas.md +++ b/packages/dsh-plugin-browserskill/skill/references/screenshots-and-canvas.md @@ -5,8 +5,8 @@ Canvas names/controls from nearby labels. If images cannot be understood, ask fo an image-capable model and continue with available semantics. ```text -browser_inspect({ action: "screenshot", session: "", ref: "@e3" }) -browser_interact({ action: "click", session: "", target: "@e3", captureId: "", imageX: 100, imageY: 50 }) +bsk_inspect({ action: "screenshot", session: "", ref: "@e3" }) +bsk_interact({ action: "click", session: "", target: "@e3", captureId: "", imageX: 100, imageY: 50 }) ``` Use the returned captureId with observed ORIGINAL PNG pixels, not resized diff --git a/packages/dsh-plugin-browserskill/skill/references/tabs-and-profiles.md b/packages/dsh-plugin-browserskill/skill/references/tabs-and-profiles.md index 3c280e7a0..f91b96e15 100644 --- a/packages/dsh-plugin-browserskill/skill/references/tabs-and-profiles.md +++ b/packages/dsh-plugin-browserskill/skill/references/tabs-and-profiles.md @@ -10,7 +10,7 @@ process arguments do not prove the profile. Use the verified ID (or verified unique BrowserSkill label) on every new session: ```text -browser_session({ action: "start", browser: "" }) +bsk_session({ action: "start", browser: "" }) ``` For copied command-line examples, use the instance ID in @@ -21,7 +21,7 @@ target unavailable, stop and ask the user to confirm/reconnect. Never omit ## Borrowing and settings -Use `browser_tabs` to list IDs before acting. Borrow for the immediate step and +Use `bsk_tabs` to list IDs before acting. Borrow for the immediate step and return promptly. Browser Automation settings govern confirmation and help; never change them to bypass a prompt or repeat pending/denied/expired borrows. Inspect unknown outcomes; follow version-error hints. diff --git a/packages/dsh-plugin-browserskill/skill/references/video.md b/packages/dsh-plugin-browserskill/skill/references/video.md index 36a4e50c2..5d96ebfb6 100644 --- a/packages/dsh-plugin-browserskill/skill/references/video.md +++ b/packages/dsh-plugin-browserskill/skill/references/video.md @@ -1,7 +1,7 @@ # Video recording When the user asks to record a task, control recording yourself through -`browser_inspect` with `action: "video"`. The user does not need to race to the +`bsk_inspect` with `action: "video"`. The user does not need to race to the extension's Start button. Record only when requested. Video is separate from semantic interaction recording, which remains unsupported by these tools. @@ -22,13 +22,13 @@ semantic interaction recording, which remains unsupported by these tools. `state`, `completeness`, `stop_reason` and `error`, then report the result. ```text -browser_session({ action: "start" }) -browser_inspect({ action: "video", videoAction: "start", session: "", durationMs: 60000, quality: "standard" }) +bsk_session({ action: "start" }) +bsk_inspect({ action: "video", videoAction: "start", session: "", durationMs: 60000, quality: "standard" }) // Retain recording.recording_id. Navigate and perform the task only after start succeeds. -browser_inspect({ action: "video", videoAction: "status", recordingId: "" }) +bsk_inspect({ action: "video", videoAction: "status", recordingId: "" }) // Wait for navigation and the expected final page state before stopping. -browser_inspect({ action: "video", videoAction: "stop", recordingId: "" }) -browser_session({ action: "stop", session: "" }) +bsk_inspect({ action: "video", videoAction: "stop", recordingId: "" }) +bsk_session({ action: "stop", session: "" }) ``` The result is a silent H.264 MP4. Default limit: 60 seconds; range: 1 second to @@ -49,7 +49,7 @@ start recording or keep its result for preview. Export through the tool only when the user specifies a destination; ask if needed: ```text -browser_inspect({ action: "video", videoAction: "save", recordingId: "", output: "" }) +bsk_inspect({ action: "video", videoAction: "save", recordingId: "", output: "" }) ``` Tool export writes on the harness host, which may be remote. The extension's Save diff --git a/packages/dsh-plugin-browserskill/src/archive-cleanup.ts b/packages/dsh-plugin-browserskill/src/archive-cleanup.ts index dc2a2db50..054289ec3 100644 --- a/packages/dsh-plugin-browserskill/src/archive-cleanup.ts +++ b/packages/dsh-plugin-browserskill/src/archive-cleanup.ts @@ -7,7 +7,7 @@ * are hidden from every surface, so their Agent Windows would otherwise * linger with no way back to them. * - * Ownership lineage: browser_session action=start records the calling agent's + * Ownership lineage: bsk_session action=start records the calling agent's * session id PLUS every ancestor along `header.parentSession` (a subagent's * browsers are reaped when any ancestor is archived, the root conversation * included). Lineage is resolved through the host session store; an diff --git a/packages/dsh-plugin-browserskill/src/browser-tools.ts b/packages/dsh-plugin-browserskill/src/browser-tools.ts index af719eda1..d43f326db 100644 --- a/packages/dsh-plugin-browserskill/src/browser-tools.ts +++ b/packages/dsh-plugin-browserskill/src/browser-tools.ts @@ -7,7 +7,9 @@ import { defineTool, type ParameterSchemaSpec, type ToolDefinition } from "@deepseek-ai/dsh-tools"; import { DEBUG_PARAMETERS } from "./debug-tool"; +import { disposeAll } from "./disposables"; import { EXTRACT_PARAMETERS } from "./extract-tool"; +import toolNames from "./tool-names.json"; import { BROWSER_PARAM, ELEMENT_WAIT_PARAMS, @@ -116,7 +118,7 @@ function defineBrowserTool( const BROWSER_TOOL_SPECS: BrowserToolSpec[] = [ { - name: "browser_session", + name: toolNames.session, description: "Manage plugin-owned browser sessions. Actions: start opens an Agent Window; stop closes an " + "owned session; list returns owned sessions. For start, url/device/width/height/noFocus are " + @@ -142,7 +144,7 @@ const BROWSER_TOOL_SPECS: BrowserToolSpec[] = [ }, }, { - name: "browser_page", + name: toolNames.page, description: "Navigate and wait on the active Agent Window tab. Actions: navigate, back, forward, reload, " + "wait, wait-for-element. navigate requires url; reload optionally accepts hard; navigation " + @@ -168,7 +170,7 @@ const BROWSER_TOOL_SPECS: BrowserToolSpec[] = [ }, }, { - name: "browser_inspect", + name: toolNames.inspect, description: "Inspect page state and explicitly control task-scoped debugging. Actions: observe, snapshot, html, " + "screenshot, console, network, video, extract. video with videoAction starts/stops a requested recording, checks status, lists, saves or discards MP4 artifacts. Start video before task operations and stop before session teardown. " + @@ -213,7 +215,7 @@ const BROWSER_TOOL_SPECS: BrowserToolSpec[] = [ }, }, { - name: "browser_interact", + name: toolNames.interact, description: "Interact with the active Agent Window tab. Actions: click, hover, wheel, scroll-to, focus, blur, fill, select, " + "press. click/hover/scroll-to/focus/blur/fill/select require target; fill also requires value; select requires " + @@ -268,7 +270,7 @@ const BROWSER_TOOL_SPECS: BrowserToolSpec[] = [ }, }, { - name: "browser_tabs", + name: toolNames.tabs, description: "Manage tabs visible to an owned session. Actions: list, create, select, close, borrow, return. " + "select/close/borrow/return require tabId from list/create. Borrow moves a user tab into the " + @@ -295,7 +297,7 @@ const BROWSER_TOOL_SPECS: BrowserToolSpec[] = [ }, }, { - name: "browser_assist", + name: toolNames.assist, description: "Display and human-assistance operations. Actions: resize, emulate, request-help. resize " + "requires width/height; emulate accepts device or width/height/mobile, or off alone; " + @@ -397,13 +399,26 @@ function indexOperations(definitions: ToolDefinition[]): ReadonlyMap void { - const definitions = indexOperations(createBrowserOperationDefinitions(deps)); - const disposers = BROWSER_TOOL_SPECS.map((spec) => - deps.ctx.tools.register(defineBrowserTool(spec, definitions)), - ).filter((dispose): dispose is () => void => typeof dispose === "function"); - return () => { - for (const dispose of disposers.splice(0)) dispose(); - }; + const operations = indexOperations(createBrowserOperationDefinitions(deps)); + // Validate every definition before publishing any schema. The host emits + // changes per registration; this is rollback, not an atomic registry update. + const definitions = BROWSER_TOOL_SPECS.map((spec) => defineBrowserTool(spec, operations)); + const disposers: (() => void)[] = []; + for (const definition of definitions) { + try { + disposers.push(deps.ctx.tools.register(definition)); + } catch (cause) { + const detail = cause instanceof Error ? cause.message : String(cause); + const failure = new Error(`Failed to register ${definition.name}: ${detail}`, { cause }); + try { + disposeAll(disposers); + } catch (cleanupError) { + throw new AggregateError([failure, cleanupError], failure.message, { cause }); + } + throw failure; + } + } + return () => disposeAll(disposers); } diff --git a/packages/dsh-plugin-browserskill/src/client/BrowserInspectToolView.module.css b/packages/dsh-plugin-browserskill/src/client/BrowserInspectToolView.module.css index bee86cfcf..84d6d441e 100644 --- a/packages/dsh-plugin-browserskill/src/client/BrowserInspectToolView.module.css +++ b/packages/dsh-plugin-browserskill/src/client/BrowserInspectToolView.module.css @@ -1,4 +1,4 @@ -/* browser_inspect screenshot toolview: disclosure row over a terminal block plus the +/* bsk_inspect screenshot toolview: disclosure row over a terminal block plus the screenshot image. Semantic tokens only (--dsw-alias-*), no literal colors. */ .card { diff --git a/packages/dsh-plugin-browserskill/src/client/BrowserInspectToolView.tsx b/packages/dsh-plugin-browserskill/src/client/BrowserInspectToolView.tsx index 43385d78b..e4176a3ab 100644 --- a/packages/dsh-plugin-browserskill/src/client/BrowserInspectToolView.tsx +++ b/packages/dsh-plugin-browserskill/src/client/BrowserInspectToolView.tsx @@ -1,4 +1,4 @@ -// browser_inspect keyed toolview: all inspect actions retain a terminal card; +// bsk_inspect keyed toolview: all inspect actions retain a terminal card; // screenshot results additionally render the image attachment. Pure function // of the frozen call/result slice, so live and replay paths stay identical. @@ -12,6 +12,7 @@ import { } from "@deepseek-ai/dsh-client-ui-primitives"; import type { ToolCallViewProps } from "@deepseek-ai/dsh-client-ui-tool/client"; import { useState } from "react"; +import toolNames from "../tool-names.json"; import css from "./BrowserInspectToolView.module.css"; import { ScreenshotImage } from "./ScreenshotImage"; @@ -120,7 +121,9 @@ function commandOf(argsRaw: string, callId: string): { command: string; title: s // Streaming can expose a truncated JSON prefix; it is still the best label. return { command: - argsRaw === "" ? `browser_inspect (${callId})` : `browser_inspect ${firstLine(argsRaw)}`, + argsRaw === "" + ? `${toolNames.inspect} (${callId})` + : `${toolNames.inspect} ${firstLine(argsRaw)}`, title: "Inspect", }; } @@ -157,7 +160,7 @@ function dotState(state: ViewState): StateDotState { } /** - * Render one browser_inspect call: a disclosure row over a terminal block, + * Render one bsk_inspect call: a disclosure row over a terminal block, * plus the screenshot image when that action returns an image attachment. */ export function BrowserInspectToolView({ @@ -171,7 +174,7 @@ export function BrowserInspectToolView({ const expandable = model.state === "running" || model.output !== null || model.image !== null; const open = expanded && expandable; return ( -
+
} title={model.title} diff --git a/packages/dsh-plugin-browserskill/src/client/index.ts b/packages/dsh-plugin-browserskill/src/client/index.ts index 226061924..8694793ed 100644 --- a/packages/dsh-plugin-browserskill/src/client/index.ts +++ b/packages/dsh-plugin-browserskill/src/client/index.ts @@ -1,5 +1,5 @@ /** - * dsh-plugin-browserskill browser half: the `browser_inspect` keyed toolview + * dsh-plugin-browserskill browser half: the `bsk_inspect` keyed toolview * plus the observation overlay (live thumbnails + interrupt). The * native right Sidebar is preferred when the host provides it; older hosts * keep the floating card. The user may switch to floating for this page. @@ -20,6 +20,7 @@ import { createElement, useCallback } from "react"; //