From 99f0ea8d43faaf3140c7add423cd9267c3a69f71 Mon Sep 17 00:00:00 2001 From: dhi13man Date: Sat, 14 Mar 2026 19:35:11 +0530 Subject: [PATCH] fix(agents): remove unconditional "Tools are disabled" prompt injection in CLI runner `runCliAgent()` unconditionally appended "Tools are disabled in this session. Do not call tools." to `extraSystemPrompt` for every CLI backend session. The intent was to prevent the LLM from calling OpenClaw's embedded API tools (since CLI backends manage their own tools natively). However, CLI agents like Claude Code interpret this text as a blanket prohibition on ALL tools, including their own native Bash, Read, and Write tools. This caused silent failures across cron jobs, group chats, and DM sessions when using any CLI backend: the agent would see the injected text in the system prompt and refuse to execute tools, returning text responses instead. Cron jobs reported `lastStatus: "ok"` despite the agent failing to run scripts. The fix removes the hardcoded string entirely. CLI backends already receive `tools: []` (no OpenClaw embedded tools in the API call), so the text was redundant at best. Closes #44135 Co-Authored-By: Dhiman's Agentic Suite --- src/agents/cli-runner.test.ts | 39 +++++++++++++++++++++++++++++++++++ src/agents/cli-runner.ts | 7 +------ 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/src/agents/cli-runner.test.ts b/src/agents/cli-runner.test.ts index 6b2564d891c..3574604049d 100644 --- a/src/agents/cli-runner.test.ts +++ b/src/agents/cli-runner.test.ts @@ -231,6 +231,45 @@ describe("runCliAgent with process supervisor", () => { await loadFreshCliRunnerModuleForTest(); }); + it("does not inject hardcoded 'Tools are disabled' text into CLI arguments", async () => { + supervisorSpawnMock.mockResolvedValueOnce( + createManagedRun({ + reason: "exit", + exitCode: 0, + exitSignal: null, + durationMs: 50, + stdout: "ok", + stderr: "", + timedOut: false, + noOutputTimedOut: false, + }), + ); + + await runCliAgent({ + sessionId: "s1", + sessionFile: "/tmp/session.jsonl", + workspaceDir: "/tmp", + prompt: "Run: node script.mjs", + provider: "codex-cli", + model: "gpt-5.2-codex", + timeoutMs: 1_000, + runId: "run-no-tools-disabled", + extraSystemPrompt: "You are a helpful assistant.", + }); + + expect(supervisorSpawnMock).toHaveBeenCalledTimes(1); + const input = supervisorSpawnMock.mock.calls[0]?.[0] as { + argv?: string[]; + input?: string; + }; + // The CLI runner must not inject "Tools are disabled" into the system + // prompt passed to CLI backends. CLI backends (e.g., Claude Code CLI) + // manage their own native tools; the injected text caused them to + // refuse using their own tools. See: openclaw/openclaw#44135 + const allArgs = (input.argv ?? []).join("\n"); + expect(allArgs).not.toContain("Tools are disabled in this session"); + }); + it("runs CLI through supervisor and returns payload", async () => { supervisorSpawnMock.mockResolvedValueOnce( createManagedRun({ diff --git a/src/agents/cli-runner.ts b/src/agents/cli-runner.ts index 17127d81724..21d7d71cf5b 100644 --- a/src/agents/cli-runner.ts +++ b/src/agents/cli-runner.ts @@ -128,12 +128,7 @@ export async function runCliAgent(params: { const normalizedModel = normalizeCliModel(modelId, backend); const modelDisplay = `${params.provider}/${modelId}`; - const extraSystemPrompt = [ - params.extraSystemPrompt?.trim(), - "Tools are disabled in this session. Do not call tools.", - ] - .filter(Boolean) - .join("\n"); + const extraSystemPrompt = params.extraSystemPrompt?.trim() ?? ""; const sessionLabel = params.sessionKey ?? params.sessionId; const { bootstrapFiles, contextFiles } = await resolveBootstrapContextForRun({