fix(browser): soften aggressive retry hint and add anti-hallucination prompts (#910)
This commit is contained in:
@@ -32,6 +32,7 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"postinstall": "node scripts/patch-browser-hint.mjs",
|
||||||
"init": "pnpm install && pnpm run uv:download",
|
"init": "pnpm install && pnpm run uv:download",
|
||||||
"predev": "node scripts/generate-ext-bridge.mjs && zx scripts/prepare-preinstalled-skills-dev.mjs",
|
"predev": "node scripts/generate-ext-bridge.mjs && zx scripts/prepare-preinstalled-skills-dev.mjs",
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
## ClawX Environment
|
## ClawX Environment
|
||||||
|
|
||||||
You are ClawX, a desktop AI assistant application based on OpenClaw. See TOOLS.md for ClawX-specific tool notes (uv, browser automation, etc.).
|
You are ClawX, a desktop AI assistant application based on OpenClaw. See TOOLS.md for ClawX-specific tool notes (uv, browser automation, etc.).
|
||||||
|
|
||||||
|
**Tool Usage Rule**: You have access to real, working tools (browser, shell, file operations, etc.). Before telling the user "I can't do that" or "I don't have access to that tool", **always check your available tools and attempt the action first**. Only report inability after receiving an actual error from the tool. Do not refuse based on assumptions from your training data.
|
||||||
|
|||||||
@@ -11,3 +11,5 @@
|
|||||||
- Flow: `action="start"` → `action="snapshot"` (see page + get element refs like `e12`) → `action="act"` (click/type using refs).
|
- Flow: `action="start"` → `action="snapshot"` (see page + get element refs like `e12`) → `action="act"` (click/type using refs).
|
||||||
- Open new tabs: `action="open"` with `targetUrl`.
|
- Open new tabs: `action="open"` with `targetUrl`.
|
||||||
- To just open a URL for the user to view, use `shell:openExternal` instead.
|
- To just open a URL for the user to view, use `shell:openExternal` instead.
|
||||||
|
- If a browser action fails, transient errors (timeout, network) can often be resolved by retrying once or navigating to a different URL.
|
||||||
|
- When asked to search, look up, or interact with a web page, use the browser tool. Do not substitute with guesses or training data when real-time web access is requested.
|
||||||
|
|||||||
@@ -789,6 +789,42 @@ function patchBundledRuntime(outputDir) {
|
|||||||
if (ptyCount > 0) {
|
if (ptyCount > 0) {
|
||||||
echo` 🩹 Patched ${ptyCount} bundled PTY site(s)`;
|
echo` 🩹 Patched ${ptyCount} bundled PTY site(s)`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Browser tool hint patch ---
|
||||||
|
// OpenClaw's BROWSER_TOOL_MODEL_HINT tells the model "Do NOT retry the
|
||||||
|
// browser tool — it will keep failing" after ANY error, causing the model
|
||||||
|
// to permanently refuse browser usage even on transient failures.
|
||||||
|
// Replace with a gentler hint that allows retries on transient errors.
|
||||||
|
const ORIGINAL_HINT =
|
||||||
|
'Do NOT retry the browser tool \u2014 it will keep failing. Use an alternative approach or inform the user that the browser is currently unavailable.';
|
||||||
|
const PATCHED_HINT =
|
||||||
|
'If this was a transient error (timeout, network), you may retry once. If the same error persists after retry, try an alternative approach and let the user know.';
|
||||||
|
const ORIGINAL_SHORT = 'Do NOT retry the browser tool.';
|
||||||
|
const PATCHED_SHORT = 'You may retry once if this was a transient error.';
|
||||||
|
|
||||||
|
const distDir = path.join(outputDir, 'dist');
|
||||||
|
let hintCount = 0;
|
||||||
|
if (fs.existsSync(distDir)) {
|
||||||
|
for (const file of fs.readdirSync(distDir)) {
|
||||||
|
if (!file.endsWith('.js')) continue;
|
||||||
|
const filePath = path.join(distDir, file);
|
||||||
|
try {
|
||||||
|
const content = fs.readFileSync(filePath, 'utf8');
|
||||||
|
if (!content.includes(ORIGINAL_HINT) && !content.includes(ORIGINAL_SHORT)) continue;
|
||||||
|
const patched = content
|
||||||
|
.replaceAll(ORIGINAL_HINT, PATCHED_HINT)
|
||||||
|
.replaceAll(ORIGINAL_SHORT, PATCHED_SHORT);
|
||||||
|
if (patched !== content) {
|
||||||
|
fs.writeFileSync(filePath, patched, 'utf8');
|
||||||
|
hintCount++;
|
||||||
|
}
|
||||||
|
} catch { /* skip on error */ }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hintCount > 0) {
|
||||||
|
echo` 🩹 Patched ${hintCount} browser tool hint(s) to allow transient error retry`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
patchBrokenModules(outputNodeModules);
|
patchBrokenModules(outputNodeModules);
|
||||||
|
|||||||
53
scripts/patch-browser-hint.mjs
Normal file
53
scripts/patch-browser-hint.mjs
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
/**
|
||||||
|
* Patch OpenClaw's BROWSER_TOOL_MODEL_HINT to allow retries on transient errors.
|
||||||
|
*
|
||||||
|
* The original hint ("Do NOT retry the browser tool — it will keep failing")
|
||||||
|
* causes models to permanently refuse browser usage after a single transient error.
|
||||||
|
*
|
||||||
|
* This runs as postinstall to patch node_modules for dev mode.
|
||||||
|
* Production builds are separately patched in bundle-openclaw.mjs.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { readFileSync, writeFileSync, readdirSync } from 'fs';
|
||||||
|
import { join } from 'path';
|
||||||
|
|
||||||
|
const REPLACEMENTS = [
|
||||||
|
[
|
||||||
|
'Do NOT retry the browser tool \u2014 it will keep failing. Use an alternative approach or inform the user that the browser is currently unavailable.',
|
||||||
|
'If this was a transient error (timeout, network), you may retry once. If the same error persists after retry, try an alternative approach and let the user know.',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'Do NOT retry the browser tool.',
|
||||||
|
'You may retry once if this was a transient error.',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
const distDir = join(process.cwd(), 'node_modules', 'openclaw', 'dist');
|
||||||
|
|
||||||
|
let patchedCount = 0;
|
||||||
|
try {
|
||||||
|
for (const file of readdirSync(distDir)) {
|
||||||
|
if (!file.endsWith('.js')) continue;
|
||||||
|
const filePath = join(distDir, file);
|
||||||
|
let content = readFileSync(filePath, 'utf-8');
|
||||||
|
let changed = false;
|
||||||
|
for (const [search, replace] of REPLACEMENTS) {
|
||||||
|
if (content.includes(search)) {
|
||||||
|
content = content.replaceAll(search, replace);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (changed) {
|
||||||
|
writeFileSync(filePath, content, 'utf-8');
|
||||||
|
console.log(`[patch-browser-hint] Patched: ${file}`);
|
||||||
|
patchedCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// openclaw not installed yet or dist not found — skip silently
|
||||||
|
}
|
||||||
|
|
||||||
|
if (patchedCount > 0) {
|
||||||
|
console.log(`[patch-browser-hint] Done. Patched ${patchedCount} file(s).`);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user