mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-03 20:21:33 +00:00
120 lines
3.5 KiB
TypeScript
120 lines
3.5 KiB
TypeScript
// Projects detached exec processes into the durable task ledger used by clients.
|
|
import { createSubsystemLogger } from "../logging/subsystem.js";
|
|
import { BACKGROUND_EXEC_TASK_KIND } from "../tasks/background-exec-task-contract.js";
|
|
import { createRunningTaskRun, finalizeTaskRunByRunId } from "../tasks/detached-task-runtime.js";
|
|
import type { ExecProcessOutcome } from "./bash-tools.exec-runtime.js";
|
|
|
|
const log = createSubsystemLogger("agents/bash-exec-task-tracking");
|
|
|
|
export type BackgroundExecTaskHandle = {
|
|
taskId: string;
|
|
runId: string;
|
|
sessionKey: string;
|
|
};
|
|
|
|
export function createBackgroundExecTask(params: {
|
|
processSessionId: string;
|
|
sessionKey?: string;
|
|
agentId?: string;
|
|
startedAt: number;
|
|
}): BackgroundExecTaskHandle | null {
|
|
const sessionKey = params.sessionKey?.trim();
|
|
if (!sessionKey) {
|
|
return null;
|
|
}
|
|
const runId = `exec:${params.processSessionId}`;
|
|
try {
|
|
const task = createRunningTaskRun({
|
|
runtime: "cli",
|
|
taskKind: BACKGROUND_EXEC_TASK_KIND,
|
|
sourceId: params.processSessionId,
|
|
requesterSessionKey: sessionKey,
|
|
ownerKey: sessionKey,
|
|
scopeKind: "session",
|
|
agentId: params.agentId,
|
|
requesterAgentId: params.agentId,
|
|
runId,
|
|
label: "CLI command",
|
|
task: "Background CLI command",
|
|
notifyPolicy: "silent",
|
|
deliveryStatus: "not_applicable",
|
|
startedAt: params.startedAt,
|
|
lastEventAt: params.startedAt,
|
|
progressSummary: "Command running",
|
|
});
|
|
if (!task) {
|
|
return null;
|
|
}
|
|
return { taskId: task.taskId, runId, sessionKey };
|
|
} catch (error) {
|
|
log.warn("Failed to register background exec task", {
|
|
processSessionId: params.processSessionId,
|
|
error,
|
|
});
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export function finalizeBackgroundExecTask(params: {
|
|
handle: BackgroundExecTaskHandle | null;
|
|
outcome: ExecProcessOutcome;
|
|
}): void {
|
|
if (!params.handle) {
|
|
return;
|
|
}
|
|
const endedAt = Date.now();
|
|
const status =
|
|
params.outcome.status === "completed"
|
|
? params.outcome.exitCode === 0
|
|
? "succeeded"
|
|
: "failed"
|
|
: params.outcome.timedOut
|
|
? "timed_out"
|
|
: params.outcome.exitReason === "manual-cancel"
|
|
? "cancelled"
|
|
: "failed";
|
|
try {
|
|
finalizeTaskRunByRunId({
|
|
runId: params.handle.runId,
|
|
runtime: "cli",
|
|
sessionKey: params.handle.sessionKey,
|
|
status,
|
|
endedAt,
|
|
lastEventAt: endedAt,
|
|
terminalSummary:
|
|
status === "succeeded"
|
|
? "Command completed"
|
|
: status === "failed"
|
|
? "Command failed"
|
|
: "Command stopped",
|
|
...(status === "succeeded" ? { clearError: true } : { error: execTaskError(params.outcome) }),
|
|
detail: {
|
|
exitCode: params.outcome.exitCode,
|
|
...(params.outcome.exitSignal != null
|
|
? { exitSignal: String(params.outcome.exitSignal) }
|
|
: {}),
|
|
...(params.outcome.status === "failed" ? { failureKind: params.outcome.failureKind } : {}),
|
|
},
|
|
});
|
|
} catch (error) {
|
|
log.warn("Failed to finalize background exec task", {
|
|
taskId: params.handle.taskId,
|
|
runId: params.handle.runId,
|
|
error,
|
|
});
|
|
}
|
|
}
|
|
|
|
function execTaskError(outcome: ExecProcessOutcome): string {
|
|
if (outcome.status === "completed") {
|
|
return `Command failed (exit code ${outcome.exitCode ?? "unknown"})`;
|
|
}
|
|
if (outcome.timedOut) {
|
|
return "Command timed out";
|
|
}
|
|
if (outcome.exitReason === "manual-cancel") {
|
|
return "Cancelled by operator";
|
|
}
|
|
return `Command failed (${outcome.failureKind})`;
|
|
}
|