fix: code/cli acpx reliability 20260304 (#34020)

* agents: switch claude-cli defaults to bypassPermissions

* agents: add claude-cli default args coverage

* agents: emit watchdog stall system event for cli runs

* agents: test cli watchdog stall system event

* acpx: fallback to sessions new when ensure returns no ids

* acpx tests: mock sessions new fallback path

* acpx tests: cover ensure-empty fallback flow

* skills: clarify claude print mode without pty

* docs: update cli-backends claude default args

* docs: refresh cli live test default args

* gateway tests: align live claude args defaults

* changelog: credit claude/acpx reliability fixes

* Agents: normalize legacy Claude permission flag overrides

* Tests: cover legacy Claude permission override normalization

* Changelog: note legacy Claude permission flag auto-normalization

* ACPX: fail fast when ensure/new return no session IDs

* ACPX tests: support empty sessions new fixture output

* ACPX tests: assert ensureSession failure when IDs missing

* CLI runner: scope watchdog heartbeat wake to session

* CLI runner tests: assert session-scoped watchdog wake

* Update CHANGELOG.md
This commit is contained in:
Vincent Koc
2026-03-03 22:15:28 -08:00
committed by GitHub
parent dfb4cb87f9
commit 4d183af0cf
12 changed files with 362 additions and 30 deletions

View File

@@ -4,8 +4,11 @@ import type { ThinkLevel } from "../auto-reply/thinking.js";
import type { OpenClawConfig } from "../config/config.js";
import { shouldLogVerbose } from "../globals.js";
import { isTruthyEnvValue } from "../infra/env.js";
import { requestHeartbeatNow } from "../infra/heartbeat-wake.js";
import { enqueueSystemEvent } from "../infra/system-events.js";
import { createSubsystemLogger } from "../logging/subsystem.js";
import { getProcessSupervisor } from "../process/supervisor/index.js";
import { scopedHeartbeatWakeOptions } from "../routing/session-key.js";
import { resolveSessionAgentIds } from "./agent-scope.js";
import {
analyzeBootstrapBudget,
@@ -341,6 +344,17 @@ export async function runCliAgent(params: {
log.warn(
`cli watchdog timeout: provider=${params.provider} model=${modelId} session=${resolvedSessionId ?? params.sessionId} noOutputTimeoutMs=${noOutputTimeoutMs} pid=${managedRun.pid ?? "unknown"}`,
);
if (params.sessionKey) {
const stallNotice = [
`CLI agent (${params.provider}) produced no output for ${Math.round(noOutputTimeoutMs / 1000)}s and was terminated.`,
"It may have been waiting for interactive input or an approval prompt.",
"For Claude Code, prefer --permission-mode bypassPermissions --print.",
].join(" ");
enqueueSystemEvent(stallNotice, { sessionKey: params.sessionKey });
requestHeartbeatNow(
scopedHeartbeatWakeOptions(params.sessionKey, { reason: "cli:watchdog:stall" }),
);
}
throw new FailoverError(timeoutReason, {
reason: "timeout",
provider: params.provider,