mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-29 10:50:58 +00:00
The Claude CLI backend uses `--output-format json`, which produces no
stdout until the entire request completes. When session context is large
(100K+ tokens) or API response is slow, the no-output watchdog timer
(max 180s for resume sessions) kills the process before it finishes,
resulting in "CLI produced no output for 180s and was terminated" errors.
Switch to `--output-format stream-json --verbose` so Claude CLI emits
NDJSON events throughout processing (init, assistant, rate_limit, result).
Each event resets the watchdog timer, which is the intended behavior —
the watchdog detects truly stuck processes, not slow-but-progressing ones.
Changes:
- cli-backends.ts: `json` → `stream-json --verbose`, `output: "jsonl"`
- helpers.ts: teach parseCliJsonl to extract text from Claude's
`{"type":"result","result":"..."}` NDJSON line
Note: `--verbose` is required for stream-json in `-p` (print) mode.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
121 lines
3.3 KiB
TypeScript
121 lines
3.3 KiB
TypeScript
import type { CliBackendPlugin, CliBackendConfig } from "openclaw/plugin-sdk/cli-backend";
|
|
import {
|
|
CLI_FRESH_WATCHDOG_DEFAULTS,
|
|
CLI_RESUME_WATCHDOG_DEFAULTS,
|
|
} from "openclaw/plugin-sdk/cli-backend";
|
|
|
|
const CLAUDE_MODEL_ALIASES: Record<string, string> = {
|
|
opus: "opus",
|
|
"opus-4.6": "opus",
|
|
"opus-4.5": "opus",
|
|
"opus-4": "opus",
|
|
"claude-opus-4-6": "opus",
|
|
"claude-opus-4-5": "opus",
|
|
"claude-opus-4": "opus",
|
|
sonnet: "sonnet",
|
|
"sonnet-4.6": "sonnet",
|
|
"sonnet-4.5": "sonnet",
|
|
"sonnet-4.1": "sonnet",
|
|
"sonnet-4.0": "sonnet",
|
|
"claude-sonnet-4-6": "sonnet",
|
|
"claude-sonnet-4-5": "sonnet",
|
|
"claude-sonnet-4-1": "sonnet",
|
|
"claude-sonnet-4-0": "sonnet",
|
|
haiku: "haiku",
|
|
"haiku-3.5": "haiku",
|
|
"claude-haiku-3-5": "haiku",
|
|
};
|
|
|
|
const CLAUDE_LEGACY_SKIP_PERMISSIONS_ARG = "--dangerously-skip-permissions";
|
|
const CLAUDE_PERMISSION_MODE_ARG = "--permission-mode";
|
|
const CLAUDE_BYPASS_PERMISSIONS_MODE = "bypassPermissions";
|
|
|
|
function normalizeClaudePermissionArgs(args?: string[]): string[] | undefined {
|
|
if (!args) {
|
|
return args;
|
|
}
|
|
const normalized: string[] = [];
|
|
let sawLegacySkip = false;
|
|
let hasPermissionMode = false;
|
|
for (let i = 0; i < args.length; i += 1) {
|
|
const arg = args[i];
|
|
if (arg === CLAUDE_LEGACY_SKIP_PERMISSIONS_ARG) {
|
|
sawLegacySkip = true;
|
|
continue;
|
|
}
|
|
if (arg === CLAUDE_PERMISSION_MODE_ARG) {
|
|
hasPermissionMode = true;
|
|
normalized.push(arg);
|
|
const maybeValue = args[i + 1];
|
|
if (typeof maybeValue === "string") {
|
|
normalized.push(maybeValue);
|
|
i += 1;
|
|
}
|
|
continue;
|
|
}
|
|
if (arg.startsWith(`${CLAUDE_PERMISSION_MODE_ARG}=`)) {
|
|
hasPermissionMode = true;
|
|
}
|
|
normalized.push(arg);
|
|
}
|
|
if (sawLegacySkip && !hasPermissionMode) {
|
|
normalized.push(CLAUDE_PERMISSION_MODE_ARG, CLAUDE_BYPASS_PERMISSIONS_MODE);
|
|
}
|
|
return normalized;
|
|
}
|
|
|
|
function normalizeClaudeBackendConfig(config: CliBackendConfig): CliBackendConfig {
|
|
return {
|
|
...config,
|
|
args: normalizeClaudePermissionArgs(config.args),
|
|
resumeArgs: normalizeClaudePermissionArgs(config.resumeArgs),
|
|
};
|
|
}
|
|
|
|
export function buildAnthropicCliBackend(): CliBackendPlugin {
|
|
return {
|
|
id: "claude-cli",
|
|
bundleMcp: true,
|
|
config: {
|
|
command: "claude",
|
|
args: [
|
|
"-p",
|
|
"--output-format",
|
|
"stream-json",
|
|
"--verbose",
|
|
"--permission-mode",
|
|
"bypassPermissions",
|
|
],
|
|
resumeArgs: [
|
|
"-p",
|
|
"--output-format",
|
|
"stream-json",
|
|
"--verbose",
|
|
"--permission-mode",
|
|
"bypassPermissions",
|
|
"--resume",
|
|
"{sessionId}",
|
|
],
|
|
output: "jsonl",
|
|
input: "arg",
|
|
modelArg: "--model",
|
|
modelAliases: CLAUDE_MODEL_ALIASES,
|
|
sessionArg: "--session-id",
|
|
sessionMode: "always",
|
|
sessionIdFields: ["session_id", "sessionId", "conversation_id", "conversationId"],
|
|
systemPromptArg: "--append-system-prompt",
|
|
systemPromptMode: "append",
|
|
systemPromptWhen: "first",
|
|
clearEnv: ["ANTHROPIC_API_KEY", "ANTHROPIC_API_KEY_OLD"],
|
|
reliability: {
|
|
watchdog: {
|
|
fresh: { ...CLI_FRESH_WATCHDOG_DEFAULTS },
|
|
resume: { ...CLI_RESUME_WATCHDOG_DEFAULTS },
|
|
},
|
|
},
|
|
serialize: true,
|
|
},
|
|
normalizeConfig: normalizeClaudeBackendConfig,
|
|
};
|
|
}
|