Skip to content

Commit 44fa6ce

Browse files
cyrusagentcyrusagent[bot]Connoropolous
authored
feat(edge-worker): optional browser-use system prompt addendum (CYHOST-991) (#1257)
* feat(edge-worker): optional browser-use system prompt addendum (CYHOST-991) When CYRUS_BROWSER_USE_ENABLED is set to a truthy value, append a <browser_use> section to the system prompt telling the agent it has access to the `agent-browser` CLI and a local Chromium for screenshots and browser automation. Off by default; cyrus-hosted sets it on cloud-runtime droplets. * feat(edge-worker): drop chromium mention from browser-use addendum (CYHOST-991) Per payton's feedback on PR #1257. * docs: remove Common Commands section from CLAUDE.md * Revert "feat(edge-worker): drop chromium mention from browser-use addendum (CYHOST-991)" This reverts commit 4cf3b0a. * feat(edge-worker): remove common commands section from browser-use addendum (CYHOST-991) Per Connor's feedback on PR #1257. * Revert "feat(edge-worker): remove common commands section from browser-use addendum (CYHOST-991)" This reverts commit fffebb3. * Revert "docs: remove Common Commands section from CLAUDE.md" This reverts commit dea094f. * feat(edge-worker): remove common commands section from browser-use addendum (CYHOST-991) --------- Co-authored-by: cyrusagent <237105008+cyrusagent[bot]@users.noreply.github.com> Co-authored-by: Connor Turland <1409121+Connoropolous@users.noreply.github.com>
1 parent cbb1ca4 commit 44fa6ce

4 files changed

Lines changed: 127 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ All notable changes to this project will be documented in this file.
44

55
## [Unreleased]
66

7+
### Added
8+
- Optional browser-use system prompt addendum that tells the agent it has access to the `agent-browser` CLI and a local Chromium for screenshots and browser automation. Enabled by setting the `CYRUS_BROWSER_USE_ENABLED` environment variable to `true` (off by default for self-host). ([CYHOST-991](https://linear.app/ceedar/issue/CYHOST-991))
9+
710
## [0.2.59] - 2026-05-28
811

912
### Added

packages/edge-worker/src/RunnerConfigBuilder.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import type {
2020
} from "cyrus-core";
2121
import { buildIntentToAddHook } from "./hooks/IntentToAddHook.js";
2222
import { buildPrMarkerHook } from "./hooks/PrMarkerHook.js";
23+
import { appendBrowserUseAddendum } from "./prompts/browserUsePromptAddendum.js";
2324
import { appendFailureModeAddendum } from "./prompts/failureModePromptAddendum.js";
2425

2526
/**
@@ -241,7 +242,9 @@ export class RunnerConfigBuilder {
241242
workspaceName: input.workspaceName,
242243
cyrusHome: input.cyrusHome,
243244
autoMemoryDirectory,
244-
appendSystemPrompt: appendFailureModeAddendum(input.systemPrompt),
245+
appendSystemPrompt: appendBrowserUseAddendum(
246+
appendFailureModeAddendum(input.systemPrompt),
247+
),
245248
...(mcpConfig ? { mcpConfig } : {}),
246249
...(mcpConfigPath ? { mcpConfigPath } : {}),
247250
...(input.resumeSessionId
@@ -363,7 +366,9 @@ export class RunnerConfigBuilder {
363366
cyrusHome: input.cyrusHome,
364367
mcpConfigPath,
365368
mcpConfig,
366-
appendSystemPrompt: appendFailureModeAddendum(input.systemPrompt),
369+
appendSystemPrompt: appendBrowserUseAddendum(
370+
appendFailureModeAddendum(input.systemPrompt),
371+
),
367372
// Priority order: label override > repository config > global default
368373
model: finalModel,
369374
fallbackModel:
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/**
2+
* Optional system-prompt addendum that tells the agent it has access to the
3+
* `agent-browser` CLI (Playwright-backed) and a local Chromium for taking
4+
* screenshots and driving real browsers.
5+
*
6+
* Only injected when the environment variable `CYRUS_BROWSER_USE_ENABLED` is
7+
* set to a truthy value. cyrus-hosted sets this on cloud-runtime droplets
8+
* (where chromium + agent-browser are pre-installed) and leaves it unset for
9+
* self-host runtimes (where the binaries may not be available).
10+
*/
11+
export const BROWSER_USE_PROMPT_ADDENDUM = `
12+
<browser_use>
13+
You have access to the \`agent-browser\` CLI (a Playwright-backed browser
14+
automation tool) and a local Chromium install. Use it to verify frontend
15+
changes, capture screenshots for the user, and drive real browser flows.
16+
17+
**When to use it:**
18+
- After making UI or frontend changes, open the running dev server in a
19+
browser and capture a screenshot to confirm the change renders as
20+
expected. Attach the screenshot when summarizing your work.
21+
- When the user asks "what does this look like?" or requests visual proof.
22+
- When reproducing a bug that involves browser behavior (clicks, forms,
23+
navigation, rendering).
24+
25+
**Tips:**
26+
- Add \`sleep 0.5\` between rapid commands — each invocation spawns its own
27+
process and the browser needs a moment to settle.
28+
- Use \`snapshot -i\` to find a reliable \`@ref\` before clicking; visible
29+
text alone can be ambiguous.
30+
- For screenshots you intend to attach to a PR or Linear comment, write
31+
them to the workspace (e.g. \`./screenshot.png\`) so they're picked up by
32+
the upload flow.
33+
</browser_use>
34+
`.trim();
35+
36+
/**
37+
* Append the browser-use addendum to a system prompt fragment, but only when
38+
* the `CYRUS_BROWSER_USE_ENABLED` env var is truthy. Returns the existing
39+
* prompt unchanged otherwise.
40+
*/
41+
export function appendBrowserUseAddendum(
42+
existing: string | undefined | null,
43+
): string {
44+
const base = (existing ?? "").trimEnd();
45+
if (!isBrowserUseEnabled()) {
46+
return existing ?? "";
47+
}
48+
if (base.length === 0) return BROWSER_USE_PROMPT_ADDENDUM;
49+
return `${base}\n\n${BROWSER_USE_PROMPT_ADDENDUM}`;
50+
}
51+
52+
function isBrowserUseEnabled(): boolean {
53+
const raw = process.env.CYRUS_BROWSER_USE_ENABLED;
54+
if (!raw) return false;
55+
const normalized = raw.trim().toLowerCase();
56+
return normalized === "1" || normalized === "true" || normalized === "yes";
57+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { afterEach, beforeEach, describe, expect, it } from "vitest";
2+
import {
3+
appendBrowserUseAddendum,
4+
BROWSER_USE_PROMPT_ADDENDUM,
5+
} from "../src/prompts/browserUsePromptAddendum.js";
6+
7+
describe("browser-use prompt addendum", () => {
8+
const original = process.env.CYRUS_BROWSER_USE_ENABLED;
9+
10+
beforeEach(() => {
11+
delete process.env.CYRUS_BROWSER_USE_ENABLED;
12+
});
13+
14+
afterEach(() => {
15+
if (original === undefined) delete process.env.CYRUS_BROWSER_USE_ENABLED;
16+
else process.env.CYRUS_BROWSER_USE_ENABLED = original;
17+
});
18+
19+
it("includes the agent-browser CLI name and a screenshot hint", () => {
20+
expect(BROWSER_USE_PROMPT_ADDENDUM).toContain("agent-browser");
21+
expect(BROWSER_USE_PROMPT_ADDENDUM).toMatch(/screenshot/i);
22+
});
23+
24+
it("returns the existing prompt unchanged when the env var is unset", () => {
25+
expect(appendBrowserUseAddendum("You are Cyrus.")).toBe("You are Cyrus.");
26+
expect(appendBrowserUseAddendum(undefined)).toBe("");
27+
expect(appendBrowserUseAddendum(null)).toBe("");
28+
});
29+
30+
it("returns the existing prompt unchanged when the env var is falsy", () => {
31+
process.env.CYRUS_BROWSER_USE_ENABLED = "false";
32+
expect(appendBrowserUseAddendum("You are Cyrus.")).toBe("You are Cyrus.");
33+
process.env.CYRUS_BROWSER_USE_ENABLED = "0";
34+
expect(appendBrowserUseAddendum("You are Cyrus.")).toBe("You are Cyrus.");
35+
});
36+
37+
it("appends the addendum with a blank-line separator when enabled", () => {
38+
process.env.CYRUS_BROWSER_USE_ENABLED = "true";
39+
const result = appendBrowserUseAddendum("You are Cyrus.");
40+
expect(result.startsWith("You are Cyrus.\n\n")).toBe(true);
41+
expect(result.endsWith(BROWSER_USE_PROMPT_ADDENDUM)).toBe(true);
42+
});
43+
44+
it("returns the addendum verbatim when enabled with no base prompt", () => {
45+
process.env.CYRUS_BROWSER_USE_ENABLED = "1";
46+
expect(appendBrowserUseAddendum(undefined)).toBe(
47+
BROWSER_USE_PROMPT_ADDENDUM,
48+
);
49+
expect(appendBrowserUseAddendum("")).toBe(BROWSER_USE_PROMPT_ADDENDUM);
50+
});
51+
52+
it("accepts common truthy spellings", () => {
53+
for (const value of ["true", "1", "yes", "TRUE", " Yes "]) {
54+
process.env.CYRUS_BROWSER_USE_ENABLED = value;
55+
expect(appendBrowserUseAddendum("base")).toContain(
56+
BROWSER_USE_PROMPT_ADDENDUM,
57+
);
58+
}
59+
});
60+
});

0 commit comments

Comments
 (0)