openclaw / src /agents /cli-runner /execute-plugin.test-support.ts
SaylorTwift's picture
SaylorTwift HF Staff
Add files using upload-large-folder tool
e249c6d verified
Raw
History Blame Contribute Delete
5.24 kB
import type { OpenClawConfig } from "../../config/types.openclaw.js";
import type {
CliBackendExecute,
CliBackendExecuteContext,
} from "../../plugins/cli-backend.types.js";
import { prepareSystemAgentRunAdmission } from "../admitted-run-context.js";
import { buildPreparedCliRunContext } from "../cli-runner.test-helpers.js";
import { executePluginOwnedProcess } from "./execute-plugin.js";
import type { PreparedCliRunContext, RunCliAgentParams } from "./types.js";
const activeAdmissions: Array<ReturnType<typeof prepareSystemAgentRunAdmission>> = [];
let nextRunId = 0;
export const SUCCESS_RESULT = {
type: "result",
subtype: "success",
is_error: false,
result: "completed",
session_id: "sdk-session",
};
export async function createExecution(
options: {
config?: OpenClawConfig;
sessionEntry?: RunCliAgentParams["sessionEntry"];
nativeTools?: string[];
abortSignal?: AbortSignal;
timeoutMs?: number;
runId?: string;
resumeArgs?: string[];
} = {},
) {
const runId = options.runId ?? `plugin-owner-${++nextRunId}`;
const config = options.config ?? { tools: { exec: { security: "full", ask: "off" } } };
const admission = prepareSystemAgentRunAdmission(config, runId, "main", "plugin-test");
activeAdmissions.push(admission);
const context = buildPreparedCliRunContext({
provider: "claude-cli",
model: "claude-sonnet-4-6",
agentId: "main",
runId,
sessionId: "sdk-session",
sessionKey: "agent:main:main",
prompt: "hello",
config,
executionMode: "agent",
timeoutMs: options.timeoutMs ?? 5_000,
sessionEntry: options.sessionEntry,
...(options.nativeTools
? { cliToolAvailability: { native: options.nativeTools, openClaw: [] } }
: {}),
systemPrompt: " Follow host policy. ",
backend: {
command: "/bin/sh",
args: [],
...(options.resumeArgs ? { resumeArgs: options.resumeArgs } : {}),
},
});
context.params.admittedRunContext = await admission.admit("plugin-harness");
if (options.abortSignal) {
context.params.abortSignal = options.abortSignal;
}
return { admission, context };
}
export function runPlugin(
context: PreparedCliRunContext,
execute: CliBackendExecute,
options: {
noOutputTimeoutMs?: number;
consumeStdout?: (chunk: string) => void;
sessionId?: string;
useResume?: boolean;
forceNewSession?: boolean;
liveSession?: boolean;
mcpCapture?: Parameters<typeof executePluginOwnedProcess>[0]["mcpCapture"];
requiredGeneration?: string;
onNoOutputTimeout?: NonNullable<
Parameters<typeof executePluginOwnedProcess>[0]["onNoOutputTimeout"]
>;
onOutstandingWorkChange?: (active: boolean) => void;
activeToolCount?: () => number;
getActiveLoopbackAskUserDeadline?: () => number | undefined;
onActiveLoopbackAskUserDeadlineChange?: (listener: () => void) => () => void;
onInterrupted?: (reason: "aborted" | "timeout") => boolean;
} = {},
) {
return executePluginOwnedProcess({
context,
execute,
executionCommand: "/bin/sh",
executionArgs: ["-p", "--permission-mode", "bypassPermissions"],
env: { PATH: "/bin:/usr/bin", OPENCLAW_TEST_MARKER: "host-owned" },
prompt: context.params.prompt,
promptContext: context.promptContext,
useResume: options.useResume ?? Boolean(options.requiredGeneration),
sessionId: options.sessionId ?? "sdk-session",
mcpCapture: options.mcpCapture,
...(options.forceNewSession ? { forceNewSession: true } : {}),
...(options.liveSession || options.requiredGeneration
? {
liveSession: { requiredGeneration: options.requiredGeneration },
}
: {}),
...(options.onNoOutputTimeout ? { onNoOutputTimeout: options.onNoOutputTimeout } : {}),
onOutstandingWorkChange: options.onOutstandingWorkChange,
activeToolCount: options.activeToolCount,
getActiveLoopbackAskUserDeadline: options.getActiveLoopbackAskUserDeadline,
onActiveLoopbackAskUserDeadlineChange: options.onActiveLoopbackAskUserDeadlineChange,
...(options.onInterrupted ? { onInterrupted: options.onInterrupted } : {}),
noOutputTimeoutMs: options.noOutputTimeoutMs ?? 2_000,
consumeStdout: options.consumeStdout ?? (() => {}),
});
}
export function requestNativeTool(
execution: CliBackendExecuteContext,
toolName = "Bash",
toolInput: Record<string, unknown> = { command: "echo approved" },
) {
return execution.requestToolPermission({
toolName,
toolInput,
toolCallId: `native-${toolName}`,
...(execution.abortSignal ? { abortSignal: execution.abortSignal } : {}),
});
}
export function closePluginTestAdmissions(): void {
for (const admission of activeAdmissions.splice(0)) {
admission.close();
}
}
export function waitUntilAborted(execution: CliBackendExecuteContext): Promise<void> {
const signal = execution.abortSignal;
if (!signal) {
throw new Error("Host execution did not expose its abort signal.");
}
return new Promise((_, reject) => {
signal.addEventListener(
"abort",
() =>
reject(
signal.reason instanceof Error ? signal.reason : new Error("CLI test run was aborted."),
),
{ once: true },
);
});
}