Skip to content

Commit e26988a

Browse files
sjhuclaude
andcommitted
fix(web-providers): reduce system prompt size for zero-token web providers
Web provider sessions were sending ~55k chars because: - buildAgentSystemPrompt() included all 30 sections (Tooling, Skills, Memory, OpenClaw Self-Update, Sandbox, Messaging, etc.) even though zero-token web providers have no tool exec / sandbox / messaging infra - Each web stream then appended a second copy of tool instructions with full JSON Schema serialization via JSON.stringify(tool.parameters) Changes: - Add "web" promptMode to buildAgentSystemPrompt: only Safety + Authorized Senders + Time + Runtime line (~500 chars vs ~20k+ for full mode) - attempt.ts + compact.ts: detect zero-token providers via listWebStreamApiIds() and set promptMode="web" automatically - All 11 web streams: replace verbose tool section with a simple "- tool_name: description" list; remove duplicate browser tool instructions and JSON Schema parameter serialization 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 692a548 commit e26988a

14 files changed

Lines changed: 71 additions & 208 deletions

src/agents/pi-embedded-runner/compact.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,10 @@ import {
6969
type SkillSnapshot,
7070
} from "../skills.js";
7171
import { resolveTranscriptPolicy } from "../transcript-policy.js";
72-
import { getWebStreamFactory } from "../web-stream-factories.js";
72+
import {
73+
getWebStreamFactory,
74+
listWebStreamApiIds,
75+
} from "../web-stream-factories.js";
7376
import {
7477
compactWithSafetyTimeout,
7578
EMBEDDED_COMPACTION_TIMEOUT_MS,
@@ -548,10 +551,12 @@ export async function compactEmbeddedPiSessionDirect(
548551
config: params.config,
549552
});
550553
const isDefaultAgent = sessionAgentId === defaultAgentId;
551-
const promptMode =
552-
isSubagentSessionKey(params.sessionKey) || isCronSessionKey(params.sessionKey)
554+
const promptMode = (() => {
555+
if (listWebStreamApiIds().includes(model.api as never)) {return "web";}
556+
return isSubagentSessionKey(params.sessionKey) || isCronSessionKey(params.sessionKey)
553557
? "minimal"
554558
: "full";
559+
})();
555560
const docsPath = await resolveOpenClawDocsPath({
556561
workspaceDir: effectiveWorkspace,
557562
argv1: process.argv[1],

src/agents/pi-embedded-runner/run/attempt.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,10 @@ import { sanitizeToolCallIdsForCloudCodeAssist } from "../../tool-call-id.js";
9292
import { resolveEffectiveToolFsWorkspaceOnly } from "../../tool-fs-policy.js";
9393
import { normalizeToolName } from "../../tool-policy.js";
9494
import { resolveTranscriptPolicy } from "../../transcript-policy.js";
95-
import { getWebStreamFactory } from "../../web-stream-factories.js";
95+
import {
96+
getWebStreamFactory,
97+
listWebStreamApiIds,
98+
} from "../../web-stream-factories.js";
9699
import { DEFAULT_BOOTSTRAP_FILENAME } from "../../workspace.js";
97100
import { isRunnerAbortError } from "../abort.js";
98101
import { appendCacheTtlTimestamp, isCacheTtlEligibleProvider } from "../cache-ttl.js";
@@ -994,7 +997,10 @@ export async function runEmbeddedAttempt(
994997
},
995998
});
996999
const isDefaultAgent = sessionAgentId === defaultAgentId;
997-
const promptMode = resolvePromptModeForSession(params.sessionKey);
1000+
const promptMode = (() => {
1001+
if (listWebStreamApiIds().includes(params.model.api as never)) {return "web";}
1002+
return resolvePromptModeForSession(params.sessionKey);
1003+
})();
9981004
const docsPath = await resolveOpenClawDocsPath({
9991005
workspaceDir: effectiveWorkspace,
10001006
argv1: process.argv[1],

src/agents/system-prompt.ts

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@ import { sanitizeForPromptLiteral } from "./sanitize-for-prompt.js";
1313
* - "full": All sections (default, for main agent)
1414
* - "minimal": Reduced sections (Tooling, Workspace, Runtime) - used for subagents
1515
* - "none": Just basic identity line, no sections
16+
* - "web": Stripped-down prompt for zero-token web providers (no tool exec guidance)
1617
*/
17-
export type PromptMode = "full" | "minimal" | "none";
18+
export type PromptMode = "full" | "minimal" | "none" | "web";
1819
type OwnerIdDisplay = "raw" | "hash";
1920

2021
function buildSkillsSection(params: { skillsPrompt?: string; readToolName: string }) {
@@ -378,6 +379,7 @@ export function buildAgentSystemPrompt(params: {
378379
const messageChannelOptions = listDeliverableMessageChannels().join("|");
379380
const promptMode = params.promptMode ?? "full";
380381
const isMinimal = promptMode === "minimal" || promptMode === "none";
382+
const isWeb = promptMode === "web";
381383
const sandboxContainerWorkspace = params.sandboxInfo?.containerWorkspaceDir?.trim();
382384
const sanitizedWorkspaceDir = sanitizeForPromptLiteral(params.workspaceDir);
383385
const sanitizedSandboxContainerWorkspace = sandboxContainerWorkspace
@@ -419,6 +421,35 @@ export function buildAgentSystemPrompt(params: {
419421
return "You are a personal assistant running inside OpenClaw.";
420422
}
421423

424+
// For "web" mode (zero-token web providers), return a stripped-down prompt
425+
if (isWeb) {
426+
const lines: string[] = [
427+
"You are a personal assistant running inside OpenClaw.",
428+
"",
429+
"## Safety",
430+
"You have no independent goals: do not pursue self-preservation, replication, or power-seeking.",
431+
"",
432+
...(params.ownerNumbers && params.ownerNumbers.length > 0
433+
? [
434+
"## Authorized Senders",
435+
`Authorized senders: ${params.ownerNumbers.join(", ")}.`,
436+
"",
437+
]
438+
: []),
439+
...(params.userTimezone ? ["## Current Date & Time", `Time zone: ${params.userTimezone}`, ""] : []),
440+
"## Runtime",
441+
buildRuntimeLine(
442+
params.runtimeInfo,
443+
undefined,
444+
[],
445+
params.defaultThinkLevel,
446+
),
447+
`Reasoning: ${params.reasoningLevel ?? "off"} (hidden unless on/stream).`,
448+
"",
449+
];
450+
return lines.filter(Boolean).join("\n");
451+
}
452+
422453
const lines = [
423454
"You are a personal assistant running inside OpenClaw.",
424455
"",

src/zero-token/streams/claude-web-stream.ts

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -42,27 +42,9 @@ export function createClaudeWebStreamFn(cookieOrJson: string): StreamFn {
4242
let toolPrompt = "";
4343

4444
if (tools.length > 0) {
45-
toolPrompt = "\n## Tool Use Instructions\n";
46-
toolPrompt +=
47-
"You are equipped with specialized tools to perform actions or retrieve information. " +
48-
'To use a tool, output a specific XML tag: <tool_call id="unique_id" name="tool_name">{"arg": "value"}</tool_call>. ' +
49-
"Rules for tool use:\n" +
50-
"1. ALWAYS think before calling a tool. Explain your reasoning inside <think> tags.\n" +
51-
"2. The 'id' attribute should be a unique 8-character string for each call.\n" +
52-
"3. Wait for the tool result before proceeding with further analysis.\n\n" +
53-
"### Special Instructions for Browser Tool\n" +
54-
"- **Profile 'openclaw' (Independent/Recommended)**: Opens a SEPARATE independent browser window. Use this for consistent, isolated sessions. Highly recommended for complex automation.\n" +
55-
"- Profile 'chrome' (Shared): Uses your existing Chrome tabs (requires extension). Use this if you need to access personal logins or already open tabs.\n" +
56-
"- **CONSISTENCY RULE**: Once you have started using a profile (or if you are switched to 'openclaw' due to connection errors), STAY with that profile for the remainder of the session. Do NOT switch back and forth as it will open redundant browser instances.\n\n" +
57-
"### Automation Policy\n" +
58-
"- DO NOT use the 'exec' tool to install secondary automation libraries like Playwright, Selenium, or Puppeteer if the 'browser' tool fails.\n" +
59-
"- Instead, inform the user about the connection issue or try the alternative browser profile ('openclaw').\n" +
60-
"- Installing automation tools via 'exec' is slow and redundant; the 'browser' tool is the primary way to interact with web content.\n\n" +
61-
"### Available Tools\n";
62-
45+
toolPrompt = "\n## Available Tools\n";
6346
for (const tool of tools) {
64-
toolPrompt += `#### ${tool.name}\n${tool.description}\n`;
65-
toolPrompt += `Parameters: ${JSON.stringify(tool.parameters)}\n\n`;
47+
toolPrompt += `- ${tool.name}: ${tool.description}\n`;
6648
}
6749
}
6850

src/zero-token/streams/deepseek-web-stream.ts

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -78,27 +78,9 @@ export function createDeepseekWebStreamFn(cookieOrJson: string): StreamFn {
7878
let systemPromptContent = systemPrompt;
7979

8080
if (tools.length > 0) {
81-
let toolPrompt = "\n## Tool Use Instructions\n";
82-
toolPrompt +=
83-
"You are equipped with specialized tools to perform actions or retrieve information. " +
84-
'To use a tool, output a specific XML tag: <tool_call id="unique_id" name="tool_name">{"arg": "value"}</tool_call>. ' +
85-
"Rules for tool use:\n" +
86-
"1. ALWAYS think before calling a tool. Explain your reasoning inside <think> tags.\n" +
87-
"2. The 'id' attribute should be a unique 8-character string for each call.\n" +
88-
"3. Output the tool call tag ONLY inside a <final> section if you are in reasoning mode.\n" +
89-
"4. Wait for the tool result before proceeding with further analysis.\n\n" +
90-
"### Special Instructions for Browser Tool\n" +
91-
"- **Profile 'openclaw' (Independent/Recommended)**: Opens a SEPARATE independent browser window. Use this for consistent, isolated sessions. Highly recommended for complex automation.\n" +
92-
"- Profile 'chrome' (Shared): Uses your existing Chrome tabs (requires extension). Use this if you need to access personal logins or already open tabs.\n" +
93-
"- **CONSISTENCY RULE**: Once you have started using a profile (or if you are switched to 'openclaw' due to connection errors), STAY with that profile for the remainder of the session. Do NOT switch back and forth as it will open redundant browser instances.\n\n" +
94-
"### Automation Policy\n" +
95-
"- DO NOT use the 'exec' tool to install secondary automation libraries like Playwright, Selenium, or Puppeteer if the 'browser' tool fails.\n" +
96-
"- Instead, inform the user about the connection issue or try the alternative browser profile ('openclaw').\n" +
97-
"- Installing automation tools via 'exec' is slow and redundant; the 'browser' tool is the primary way to interact with web content.\n\n" +
98-
"### Available Tools\n";
81+
let toolPrompt = "\n## Available Tools\n";
9982
for (const tool of tools) {
100-
toolPrompt += `#### ${tool.name}\n${tool.description}\n`;
101-
toolPrompt += `Parameters: ${JSON.stringify(tool.parameters)}\n\n`;
83+
toolPrompt += `- ${tool.name}: ${tool.description}\n`;
10284
}
10385
systemPromptContent += toolPrompt;
10486
}

src/zero-token/streams/doubao-web-stream.ts

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -41,27 +41,9 @@ export function createDoubaoWebStreamFn(cookieOrJson: string): StreamFn {
4141
let toolPrompt = "";
4242

4343
if (tools.length > 0) {
44-
toolPrompt = "\n## Tool Use Instructions\n";
45-
toolPrompt +=
46-
"You are equipped with specialized tools to perform actions or retrieve information. " +
47-
'To use a tool, output a specific XML tag: <tool_call id="unique_id" name="tool_name">{"arg": "value"}</tool_call>. ' +
48-
"Rules for tool use:\n" +
49-
"1. ALWAYS think before calling a tool. Explain your reasoning inside <think> tags.\n" +
50-
"2. The 'id' attribute should be a unique 8-character string for each call.\n" +
51-
"3. Wait for the tool result before proceeding with further analysis.\n\n" +
52-
"### Special Instructions for Browser Tool\n" +
53-
"- **Profile 'openclaw' (Independent/Recommended)**: Opens a SEPARATE independent browser window. Use this for consistent, isolated sessions. Highly recommended for complex automation.\n" +
54-
"- Profile 'chrome' (Shared): Uses your existing Chrome tabs (requires extension). Use this if you need to access personal logins or already open tabs.\n" +
55-
"- **CONSISTENCY RULE**: Once you have started using a profile (or if you are switched to 'openclaw' due to connection errors), STAY with that profile for the remainder of the session. Do NOT switch back and forth as it will open redundant browser instances.\n\n" +
56-
"### Automation Policy\n" +
57-
"- DO NOT use the 'exec' tool to install secondary automation libraries like Playwright, Selenium, or Puppeteer if the 'browser' tool fails.\n" +
58-
"- Instead, inform the user about the connection issue or try the alternative browser profile ('openclaw').\n" +
59-
"- Installing automation tools via 'exec' is slow and redundant; the 'browser' tool is the primary way to interact with web content.\n\n" +
60-
"### Available Tools\n";
61-
44+
toolPrompt = "\n## Available Tools\n";
6245
for (const tool of tools) {
63-
toolPrompt += `#### ${tool.name}\n${tool.description}\n`;
64-
toolPrompt += `Parameters: ${JSON.stringify(tool.parameters)}\n\n`;
46+
toolPrompt += `- ${tool.name}: ${tool.description}\n`;
6547
}
6648
}
6749

src/zero-token/streams/gemini-web-stream.ts

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -67,22 +67,9 @@ function buildXmlToolPromptSection(tools: unknown[]): string {
6767
if (!tools || tools.length === 0) {
6868
return "";
6969
}
70-
let section = "\n## Tool Use Instructions\n";
71-
section +=
72-
"You are equipped with specialized tools to perform actions or retrieve information. " +
73-
'To use a tool, output a specific XML tag: <tool_call id="unique_id" name="tool_name">{"arg": "value"}</tool_call>. ' +
74-
"Rules for tool use:\n" +
75-
"1. ALWAYS think before calling a tool. Explain your reasoning inside <think> tags.\n" +
76-
"2. The 'id' attribute should be a unique 8-character string for each call.\n" +
77-
"3. Wait for the tool result before proceeding with further analysis.\n\n" +
78-
"### Automation Policy\n" +
79-
"- DO NOT use the 'exec' tool to install secondary automation libraries like Playwright, Selenium, or Puppeteer if the 'browser' tool fails.\n" +
80-
"- Instead, inform the user about the connection issue or try the alternative browser profile.\n\n" +
81-
"### Available Tools\n";
82-
83-
for (const tool of tools as Array<{ name?: string; description?: string; parameters?: unknown }>) {
84-
section += `#### ${tool.name ?? "unknown"}\n${tool.description ?? ""}\n`;
85-
section += `Parameters: ${JSON.stringify(tool.parameters ?? {})}\n\n`;
70+
let section = "\n## Available Tools\n";
71+
for (const tool of tools as Array<{ name?: string; description?: string }>) {
72+
section += `- ${tool.name ?? "unknown"}: ${tool.description ?? ""}\n`;
8673
}
8774
return section;
8875
}

src/zero-token/streams/glm-intl-web-stream.ts

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -42,27 +42,9 @@ export function createGlmIntlWebStreamFn(cookieOrJson: string): StreamFn {
4242
let toolPrompt = "";
4343

4444
if (tools.length > 0) {
45-
toolPrompt = "\n## Tool Use Instructions\n";
46-
toolPrompt +=
47-
"You are equipped with specialized tools to perform actions or retrieve information. " +
48-
'To use a tool, output a specific XML tag: <tool_call id="unique_id" name="tool_name">{"arg": "value"}</tool_call>. ' +
49-
"Rules for tool use:\n" +
50-
"1. ALWAYS think before calling a tool. Explain your reasoning inside <think> tags.\n" +
51-
"2. The 'id' attribute should be a unique 8-character string for each call.\n" +
52-
"3. Wait for the tool result before proceeding with further analysis.\n\n" +
53-
"### Special Instructions for Browser Tool\n" +
54-
"- **Profile 'openclaw' (Independent/Recommended)**: Opens a SEPARATE independent browser window. Use this for consistent, isolated sessions. Highly recommended for complex automation.\n" +
55-
"- Profile 'chrome' (Shared): Uses your existing Chrome tabs (requires extension). Use this if you need to access personal logins or already open tabs.\n" +
56-
"- **CONSISTENCY RULE**: Once you have started using a profile (or if you are switched to 'openclaw' due to connection errors), STAY with that profile for the remainder of the session. Do NOT switch back and forth as it will open redundant browser instances.\n\n" +
57-
"### Automation Policy\n" +
58-
"- DO NOT use the 'exec' tool to install secondary automation libraries like Playwright, Selenium, or Puppeteer if the 'browser' tool fails.\n" +
59-
"- Instead, inform the user about the connection issue or try the alternative browser profile ('openclaw').\n" +
60-
"- Installing automation tools via 'exec' is slow and redundant; the 'browser' tool is the primary way to interact with web content.\n\n" +
61-
"### Available Tools\n";
62-
45+
toolPrompt = "\n## Available Tools\n";
6346
for (const tool of tools) {
64-
toolPrompt += `#### ${tool.name}\n${tool.description}\n`;
65-
toolPrompt += `Parameters: ${JSON.stringify(tool.parameters)}\n\n`;
47+
toolPrompt += `- ${tool.name}: ${tool.description}\n`;
6648
}
6749
}
6850

src/zero-token/streams/glm-web-stream.ts

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -44,27 +44,9 @@ export function createZWebStreamFn(cookieOrJson: string): StreamFn {
4444
let toolPrompt = "";
4545

4646
if (tools.length > 0) {
47-
toolPrompt = "\n## Tool Use Instructions\n";
48-
toolPrompt +=
49-
"You are equipped with specialized tools to perform actions or retrieve information. " +
50-
'To use a tool, output a specific XML tag: <tool_call id="unique_id" name="tool_name">{"arg": "value"}</tool_call>. ' +
51-
"Rules for tool use:\n" +
52-
"1. ALWAYS think before calling a tool. Explain your reasoning inside <think> tags.\n" +
53-
"2. The 'id' attribute should be a unique 8-character string for each call.\n" +
54-
"3. Wait for the tool result before proceeding with further analysis.\n\n" +
55-
"### Special Instructions for Browser Tool\n" +
56-
"- **Profile 'openclaw' (Independent/Recommended)**: Opens a SEPARATE independent browser window. Use this for consistent, isolated sessions. Highly recommended for complex automation.\n" +
57-
"- Profile 'chrome' (Shared): Uses your existing Chrome tabs (requires extension). Use this if you need to access personal logins or already open tabs.\n" +
58-
"- **CONSISTENCY RULE**: Once you have started using a profile (or if you are switched to 'openclaw' due to connection errors), STAY with that profile for the remainder of the session. Do NOT switch back and forth as it will open redundant browser instances.\n\n" +
59-
"### Automation Policy\n" +
60-
"- DO NOT use the 'exec' tool to install secondary automation libraries like Playwright, Selenium, or Puppeteer if the 'browser' tool fails.\n" +
61-
"- Instead, inform the user about the connection issue or try the alternative browser profile ('openclaw').\n" +
62-
"- Installing automation tools via 'exec' is slow and redundant; the 'browser' tool is the primary way to interact with web content.\n\n" +
63-
"### Available Tools\n";
64-
47+
toolPrompt = "\n## Available Tools\n";
6548
for (const tool of tools) {
66-
toolPrompt += `#### ${tool.name}\n${tool.description}\n`;
67-
toolPrompt += `Parameters: ${JSON.stringify(tool.parameters)}\n\n`;
49+
toolPrompt += `- ${tool.name}: ${tool.description}\n`;
6850
}
6951
}
7052

0 commit comments

Comments
 (0)