mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 05:20:43 +00:00
fix(exec): honor default timeout for background runs
This commit is contained in:
@@ -19,6 +19,7 @@ Docs: https://docs.openclaw.ai
|
||||
### Fixes
|
||||
|
||||
- Memory-core/dreaming: treat request-scoped narrative fallback as expected, skip session cleanup when no subagent run was created, and remove duplicate phase-level cleanup so fallback no longer emits warning noise. Fixes #67152. Thanks @jsompis.
|
||||
- Agents/exec: apply configured `tools.exec.timeoutSec` to background and `yieldMs` commands when no per-call timeout is set, preventing auto-backgrounded commands from running indefinitely. Fixes #67600; supersedes #67603. Thanks @dlmpx and @kagura-agent.
|
||||
- Config/doctor: stop masking unknown-key validation diagnostics such as `agents.defaults.llm`, and have `openclaw doctor --fix` remove the retired `agents.defaults.llm` timeout block. Thanks @aidiffuser.
|
||||
- CLI/plugins: preserve unversioned ClawHub install specs so `plugins update` can follow newer ClawHub releases instead of pinning to the initially resolved version. Fixes #63010; supersedes #58426. Thanks @kangsen1234 and @robinspt.
|
||||
- Memory-core/subagents: tag plugin-created subagent sessions with their plugin owner so dreaming narrative cleanup can delete its own ephemeral sessions without granting broad admin session deletion. Fixes #72712. Thanks @BSG2000.
|
||||
|
||||
@@ -177,12 +177,18 @@ async function expectBackgroundSessionTimesOut(params: {
|
||||
executeParams: ExecToolExecuteParams;
|
||||
signal?: AbortSignal;
|
||||
abortAfterStart?: boolean;
|
||||
expectedTimeoutSec?: number;
|
||||
}) {
|
||||
const abortController = new AbortController();
|
||||
const signal = params.signal ?? abortController.signal;
|
||||
const result = await params.tool.execute("toolcall", params.executeParams, signal);
|
||||
expect(result.details.status).toBe("running");
|
||||
const sessionId = (result.details as { sessionId: string }).sessionId;
|
||||
if (typeof params.expectedTimeoutSec === "number") {
|
||||
expect(supervisorMockState.spawnInputs.at(-1)?.timeoutMs).toBe(
|
||||
Math.floor(params.expectedTimeoutSec * 1000),
|
||||
);
|
||||
}
|
||||
|
||||
if (params.abortAfterStart) {
|
||||
abortController.abort();
|
||||
@@ -223,23 +229,21 @@ test("background exec still times out after tool signal abort", async () => {
|
||||
timeout: BACKGROUND_TIMEOUT_SEC,
|
||||
},
|
||||
abortAfterStart: true,
|
||||
expectedTimeoutSec: BACKGROUND_TIMEOUT_SEC,
|
||||
});
|
||||
});
|
||||
|
||||
test("background exec without explicit timeout ignores default timeout", async () => {
|
||||
test("background exec without explicit timeout applies default timeout", async () => {
|
||||
const tool = createTestExecTool({
|
||||
allowBackground: true,
|
||||
backgroundMs: 0,
|
||||
timeoutSec: BACKGROUND_TIMEOUT_SEC,
|
||||
});
|
||||
const result = await tool.execute("toolcall", { command: BACKGROUND_HOLD_CMD, background: true });
|
||||
expect(result.details.status).toBe("running");
|
||||
const sessionId = (result.details as { sessionId: string }).sessionId;
|
||||
expect(supervisorMockState.spawnInputs.at(-1)?.timeoutMs).toBeUndefined();
|
||||
expect(getFinishedSession(sessionId)).toBeUndefined();
|
||||
expect(getSession(sessionId)?.exited).toBe(false);
|
||||
|
||||
cleanupRunningSession(sessionId);
|
||||
await expectBackgroundSessionTimesOut({
|
||||
tool,
|
||||
executeParams: { command: BACKGROUND_HOLD_CMD, background: true },
|
||||
expectedTimeoutSec: BACKGROUND_TIMEOUT_SEC,
|
||||
});
|
||||
});
|
||||
|
||||
test("yielded background exec still times out", async () => {
|
||||
@@ -251,5 +255,22 @@ test("yielded background exec still times out", async () => {
|
||||
yieldMs: 5,
|
||||
timeout: BACKGROUND_TIMEOUT_SEC,
|
||||
},
|
||||
expectedTimeoutSec: BACKGROUND_TIMEOUT_SEC,
|
||||
});
|
||||
});
|
||||
|
||||
test("yieldMs exec without explicit timeout applies default timeout", async () => {
|
||||
const tool = createTestExecTool({
|
||||
allowBackground: true,
|
||||
backgroundMs: 10,
|
||||
timeoutSec: BACKGROUND_TIMEOUT_SEC,
|
||||
});
|
||||
await expectBackgroundSessionTimesOut({
|
||||
tool,
|
||||
executeParams: {
|
||||
command: BACKGROUND_HOLD_CMD,
|
||||
yieldMs: 5,
|
||||
},
|
||||
expectedTimeoutSec: BACKGROUND_TIMEOUT_SEC,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1676,11 +1676,7 @@ export function createExecTool(
|
||||
}
|
||||
|
||||
const explicitTimeoutSec = typeof params.timeout === "number" ? params.timeout : null;
|
||||
const backgroundTimeoutBypass =
|
||||
allowBackground && explicitTimeoutSec === null && (backgroundRequested || yieldRequested);
|
||||
const effectiveTimeout = backgroundTimeoutBypass
|
||||
? null
|
||||
: (explicitTimeoutSec ?? defaultTimeoutSec);
|
||||
const effectiveTimeout = explicitTimeoutSec ?? defaultTimeoutSec;
|
||||
const getWarningText = () => (warnings.length ? `${warnings.join("\n")}\n\n` : "");
|
||||
const usePty = params.pty === true && !sandbox;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user