From 672ac6df141fa875ebf743feedc5c15e526f1d48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E5=86=A0=E8=BE=B0?= Date: Mon, 25 May 2026 00:17:09 +0800 Subject: [PATCH] fix(runner): avoid duplicate system prompt on new OpenClaw --- index.ts | 2 +- package.json | 2 -- src/utils/clean-context-runner.test.ts | 20 +++++++++++++++ src/utils/clean-context-runner.ts | 34 +++++++++++++++++++++++--- 4 files changed, 51 insertions(+), 7 deletions(-) create mode 100644 src/utils/clean-context-runner.test.ts diff --git a/index.ts b/index.ts index b7f67ed..5b8e71e 100644 --- a/index.ts +++ b/index.ts @@ -129,7 +129,7 @@ function sweepStaleCaches(): void { export default function register(api: OpenClawPluginApi) { pluginStartTimestamp = Date.now(); - setPreferredEmbeddedAgentRuntime(api.runtime.agent); + setPreferredEmbeddedAgentRuntime(api.runtime.agent, (api.runtime as any)?.version); // Reset reporter singleton so config changes take effect on hot-reload. resetReporter(); const _require = createRequire(import.meta.url); diff --git a/package.json b/package.json index 0609611..ea6cb4e 100644 --- a/package.json +++ b/package.json @@ -34,14 +34,12 @@ "files": [ "dist/", "bin/", - "index.ts", "scripts/migrate-sqlite-to-tcvdb/dist/", "scripts/export-tencent-vdb/dist/", "scripts/read-local-memory/dist/", "scripts/memory-tencentdb-ctl.sh", "scripts/install_hermes_memory_tencentdb.sh", "scripts/README.memory-tencentdb-ctl.md", - "src/", "scripts/openclaw-after-tool-call-messages.patch.sh", "scripts/setup-offload.sh", "hermes-plugin/", diff --git a/src/utils/clean-context-runner.test.ts b/src/utils/clean-context-runner.test.ts new file mode 100644 index 0000000..6cda2d0 --- /dev/null +++ b/src/utils/clean-context-runner.test.ts @@ -0,0 +1,20 @@ +import { describe, expect, it } from "vitest"; + +import { shouldPassExtraSystemPrompt } from "./clean-context-runner.js"; + +describe("shouldPassExtraSystemPrompt", () => { + it("keeps the legacy fallback when the OpenClaw version is unknown", () => { + expect(shouldPassExtraSystemPrompt(undefined)).toBe(true); + expect(shouldPassExtraSystemPrompt("unknown")).toBe(true); + }); + + it("keeps the fallback for OpenClaw versions before 2026.4.7", () => { + expect(shouldPassExtraSystemPrompt("2026.4.6")).toBe(true); + }); + + it("omits the fallback for OpenClaw versions that support systemPromptOverride", () => { + expect(shouldPassExtraSystemPrompt("2026.4.7")).toBe(false); + expect(shouldPassExtraSystemPrompt("2026.4.7-beta.1")).toBe(false); + expect(shouldPassExtraSystemPrompt("2026.5.20")).toBe(false); + }); +}); diff --git a/src/utils/clean-context-runner.ts b/src/utils/clean-context-runner.ts index 868d787..fe70b07 100644 --- a/src/utils/clean-context-runner.ts +++ b/src/utils/clean-context-runner.ts @@ -65,11 +65,34 @@ export interface EmbeddedAgentRuntimeLike { } let _preferredAgentRuntime: EmbeddedAgentRuntimeLike | undefined; +let _preferredOpenClawVersion: unknown; export function setPreferredEmbeddedAgentRuntime( agentRuntime: EmbeddedAgentRuntimeLike | undefined, + openClawVersion?: unknown, ): void { _preferredAgentRuntime = agentRuntime; + _preferredOpenClawVersion = openClawVersion; +} + +export function shouldPassExtraSystemPrompt(openClawVersion: unknown): boolean { + const parsed = parseVersionXYZ(openClawVersion); + if (!parsed) return true; + return compareVersionXYZ(parsed, [2026, 4, 7]) < 0; +} + +function parseVersionXYZ(v: unknown): [number, number, number] | null { + if (typeof v !== "string") return null; + const m = v.match(/^(\d+)\.(\d+)\.(\d+)(?:[-.].*)?$/); + if (!m) return null; + return [Number(m[1]), Number(m[2]), Number(m[3])]; +} + +function compareVersionXYZ( + a: readonly [number, number, number], + b: readonly [number, number, number], +): number { + return a[0] - b[0] || a[1] - b[1] || a[2] - b[2]; } function resolveInjectedRunEmbeddedPiAgent( @@ -439,12 +462,15 @@ export class CleanContextRunner { // Phase 2: Embedded agent run (LLM call + tool calls) const agentStartMs = Date.now(); - // extraSystemPrompt: fallback for openclaw < 2026.4.7 which does not support - // config.agents.defaults.systemPromptOverride. On newer versions the - // override takes precedence and this becomes a no-op append. + // extraSystemPrompt is only needed for old OpenClaw builds that do not + // support config.agents.defaults.systemPromptOverride. Newer builds append + // it after the override, duplicating the full system prompt. const effectiveSystemPrompt = params.systemPrompt || "You are a precise data extraction and generation assistant. Follow the user instructions exactly. Respond only with the requested output format."; + const extraSystemPrompt = shouldPassExtraSystemPrompt(_preferredOpenClawVersion) + ? effectiveSystemPrompt + : undefined; const result = await runEmbeddedPiAgent({ sessionId, sessionFile, @@ -460,7 +486,7 @@ export class CleanContextRunner { // Instead rely on cleanConfig.tools.allow to restrict the tool set // to a minimal read-only tool (when enableTools=false). disableTools: false, - extraSystemPrompt: effectiveSystemPrompt, + ...(extraSystemPrompt ? { extraSystemPrompt } : {}), streamParams: { maxTokens: params.maxTokens, },