mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-12 07:20:45 +00:00
test(agents): cover exec non-zero exits
This commit is contained in:
@@ -59,6 +59,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Auto-reply/Subagents: propagate group context (`groupId`, `groupChannel`, `space`) when spawning via `/subagents spawn`, matching tool-triggered subagent spawn behavior.
|
||||
- Subagents: cap announce retry loops with max attempts and expiry to prevent infinite retry spam after deferred announces. (#18444)
|
||||
- Agents/Tools/exec: add a preflight guard that detects likely shell env var injection (e.g. `$DM_JSON`, `$TMPDIR`) in Python/Node scripts before execution, preventing recurring cron failures and wasted tokens when models emit mixed shell+language source. (#12836)
|
||||
- Agents/Tools/exec: treat normal non-zero exit codes as completed and append the exit code to tool output to avoid false tool-failure warnings. (#18425)
|
||||
- Agents/Tools: make loop detection progress-aware and phased by hard-blocking known `process(action=poll|log)` no-progress loops, warning on generic identical-call repeats, warning + no-progress-blocking ping-pong alternation loops (10/20), coalescing repeated warning spam into threshold buckets (including canonical ping-pong pairs), adding a global circuit breaker at 30 no-progress repeats, and emitting structured diagnostic `tool.loop` warning/error events for loop actions. (#16808) Thanks @akramcodez and @beca-oc.
|
||||
- Agents/Tools: scope the `message` tool schema to the active channel so Telegram uses `buttons` and Discord uses `components`. (#18215) Thanks @obviyus.
|
||||
- Agents/Image tool: replace Anthropic-incompatible union schema with explicit `image` (single) and `images` (multi) parameters, keeping tool schemas `anyOf`/`oneOf`/`allOf`-free while preserving multi-image analysis support. (#18551, #18566) Thanks @aldoeliacim.
|
||||
|
||||
@@ -315,6 +315,36 @@ describe("exec tool backgrounding", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("exec exit codes", () => {
|
||||
const originalShell = process.env.SHELL;
|
||||
|
||||
beforeEach(() => {
|
||||
if (!isWin && defaultShell) {
|
||||
process.env.SHELL = defaultShell;
|
||||
}
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
if (!isWin) {
|
||||
process.env.SHELL = originalShell;
|
||||
}
|
||||
});
|
||||
|
||||
it("treats non-zero exits as completed and appends exit code", async () => {
|
||||
const command = isWin
|
||||
? joinCommands(["Write-Output nope", "exit 1"])
|
||||
: joinCommands(["echo nope", "exit 1"]);
|
||||
const result = await execTool.execute("call1", { command });
|
||||
|
||||
expect(result.details.status).toBe("completed");
|
||||
expect(result.details.exitCode).toBe(1);
|
||||
|
||||
const text = normalizeText(result.content.find((c) => c.type === "text")?.text);
|
||||
expect(text).toContain("nope");
|
||||
expect(text).toContain("Command exited with code 1");
|
||||
});
|
||||
});
|
||||
|
||||
describe("exec notifyOnExit", () => {
|
||||
it("enqueues a system event when a backgrounded exec exits", async () => {
|
||||
const tool = createExecTool({
|
||||
|
||||
Reference in New Issue
Block a user