fix: extend hwlab web probe sampling timeout
This commit is contained in:
+131
-10
@@ -32,6 +32,8 @@ interface NodeWebProbeRunOptions {
|
||||
freshSession: boolean;
|
||||
cancelRunning: boolean;
|
||||
commandTimeoutSeconds: number;
|
||||
commandTimeoutAutoSeconds: number;
|
||||
commandTimeoutUserProvided: boolean;
|
||||
}
|
||||
|
||||
interface NodeWebProbeScriptOptions {
|
||||
@@ -4784,14 +4786,16 @@ function parseNodeWebProbeOptions(args: string[]): NodeWebProbeOptions {
|
||||
}
|
||||
const scriptText = scriptFile === undefined ? readFileSync(0, "utf8") : readFileSync(scriptFile, "utf8");
|
||||
if (scriptText.trim().length === 0) throw new Error("web-probe script received an empty script");
|
||||
const timeoutMs = positiveIntegerOption(args, "--timeout-ms", 30000, 60000);
|
||||
const commandTimeoutSeconds = positiveIntegerOption(args, "--command-timeout-seconds", Math.max(60, Math.ceil(timeoutMs / 1000) + 30), 3600);
|
||||
return {
|
||||
action: "script",
|
||||
node,
|
||||
lane,
|
||||
url: optionValue(args, "--url") ?? spec.publicWebUrl,
|
||||
timeoutMs: positiveIntegerOption(args, "--timeout-ms", 30000, 60000),
|
||||
timeoutMs,
|
||||
viewport: optionValue(args, "--viewport") ?? "1440x900",
|
||||
commandTimeoutSeconds: positiveIntegerOption(args, "--command-timeout-seconds", 60, 60),
|
||||
commandTimeoutSeconds,
|
||||
scriptText,
|
||||
scriptSource: {
|
||||
kind: scriptFile === undefined ? "stdin" : "file",
|
||||
@@ -4818,25 +4822,69 @@ function parseNodeWebProbeOptions(args: string[]): NodeWebProbeOptions {
|
||||
"--fresh-session",
|
||||
"--no-cancel-running",
|
||||
]));
|
||||
const timeoutMs = positiveIntegerOption(args, "--timeout-ms", 30000, 60000);
|
||||
const waitAfterSubmitMs = positiveIntegerOption(args, "--wait-after-submit-ms", 1500, 60000);
|
||||
const waitMessagesMs = positiveIntegerOption(args, "--wait-messages-ms", 2500, 60000);
|
||||
const waitAgentTerminalMs = positiveIntegerOption(args, "--wait-agent-terminal-ms", 0, 600000);
|
||||
const traceSampleCount = positiveIntegerOption(args, "--trace-sample-count", 0, 200);
|
||||
const traceSampleIntervalMs = positiveIntegerOption(args, "--trace-sample-interval-ms", 0, 60000);
|
||||
const commandTimeoutAutoSeconds = nodeWebProbeAutoCommandTimeoutSeconds({
|
||||
timeoutMs,
|
||||
waitAfterSubmitMs,
|
||||
waitMessagesMs,
|
||||
waitAgentTerminalMs,
|
||||
traceSampleCount,
|
||||
traceSampleIntervalMs,
|
||||
freshSession: args.includes("--fresh-session"),
|
||||
hasMessage: optionValue(args, "--message") !== undefined,
|
||||
});
|
||||
const commandTimeoutRaw = optionValue(args, "--command-timeout-seconds");
|
||||
const commandTimeoutUserProvided = commandTimeoutRaw !== undefined;
|
||||
const commandTimeoutSeconds = commandTimeoutUserProvided
|
||||
? Math.max(positiveIntegerOption(args, "--command-timeout-seconds", commandTimeoutAutoSeconds, 3600), commandTimeoutAutoSeconds)
|
||||
: commandTimeoutAutoSeconds;
|
||||
return {
|
||||
action: "run",
|
||||
node,
|
||||
lane,
|
||||
url: optionValue(args, "--url") ?? spec.publicWebUrl,
|
||||
timeoutMs: positiveIntegerOption(args, "--timeout-ms", 30000, 60000),
|
||||
waitAfterSubmitMs: positiveIntegerOption(args, "--wait-after-submit-ms", 1500, 60000),
|
||||
waitMessagesMs: positiveIntegerOption(args, "--wait-messages-ms", 2500, 60000),
|
||||
waitAgentTerminalMs: positiveIntegerOption(args, "--wait-agent-terminal-ms", 0, 600000),
|
||||
traceSampleCount: positiveIntegerOption(args, "--trace-sample-count", 0, 200),
|
||||
traceSampleIntervalMs: positiveIntegerOption(args, "--trace-sample-interval-ms", 0, 60000),
|
||||
timeoutMs,
|
||||
waitAfterSubmitMs,
|
||||
waitMessagesMs,
|
||||
waitAgentTerminalMs,
|
||||
traceSampleCount,
|
||||
traceSampleIntervalMs,
|
||||
message: optionValue(args, "--message") ?? null,
|
||||
conversationId: optionValue(args, "--conversation-id") ?? null,
|
||||
freshSession: args.includes("--fresh-session"),
|
||||
cancelRunning: !args.includes("--no-cancel-running"),
|
||||
commandTimeoutSeconds: positiveIntegerOption(args, "--command-timeout-seconds", 60, 60),
|
||||
commandTimeoutSeconds,
|
||||
commandTimeoutAutoSeconds,
|
||||
commandTimeoutUserProvided,
|
||||
};
|
||||
}
|
||||
|
||||
function nodeWebProbeAutoCommandTimeoutSeconds(input: {
|
||||
timeoutMs: number;
|
||||
waitAfterSubmitMs: number;
|
||||
waitMessagesMs: number;
|
||||
waitAgentTerminalMs: number;
|
||||
traceSampleCount: number;
|
||||
traceSampleIntervalMs: number;
|
||||
freshSession: boolean;
|
||||
hasMessage: boolean;
|
||||
}): number {
|
||||
const traceWindowMs = input.traceSampleCount > 0
|
||||
? Math.max(0, input.traceSampleCount - 1) * input.traceSampleIntervalMs
|
||||
: 0;
|
||||
const startupBudgetMs = input.timeoutMs + 30_000;
|
||||
const freshnessBudgetMs = input.freshSession ? Math.min(input.timeoutMs, 30_000) : 0;
|
||||
const submitBudgetMs = input.hasMessage ? input.waitAfterSubmitMs + input.waitMessagesMs + 15_000 : 0;
|
||||
const terminalBudgetMs = input.waitAgentTerminalMs > 0 ? input.waitAgentTerminalMs : 0;
|
||||
const totalMs = startupBudgetMs + freshnessBudgetMs + submitBudgetMs + terminalBudgetMs + traceWindowMs + 15_000;
|
||||
return Math.min(3600, Math.max(60, Math.ceil(totalMs / 1000)));
|
||||
}
|
||||
|
||||
function assertKnownOptions(args: string[], valueOptions: Set<string>, flagOptions: Set<string>): void {
|
||||
for (let index = 0; index < args.length; index += 1) {
|
||||
const arg = args[index] ?? "";
|
||||
@@ -4894,6 +4942,11 @@ function runNodeWebProbe(options: NodeWebProbeOptions): Record<string, unknown>
|
||||
const result = runTransWorkspaceStdinScript(options.node, spec.workspace, script, options.commandTimeoutSeconds);
|
||||
const probe = compactWebProbeResult(parseJsonObject(result.stdout));
|
||||
const passed = result.exitCode === 0 && probe?.status === "pass";
|
||||
const degradedReason = result.timedOut
|
||||
? "web-probe-command-timeout"
|
||||
: typeof probe?.degradedReason === "string"
|
||||
? probe.degradedReason
|
||||
: null;
|
||||
return {
|
||||
ok: passed,
|
||||
status: passed ? "pass" : "blocked",
|
||||
@@ -4903,6 +4956,13 @@ function runNodeWebProbe(options: NodeWebProbeOptions): Record<string, unknown>
|
||||
workspace: spec.workspace,
|
||||
url: options.url,
|
||||
credential,
|
||||
commandTimeout: {
|
||||
seconds: options.commandTimeoutSeconds,
|
||||
autoSeconds: options.commandTimeoutAutoSeconds,
|
||||
userProvided: options.commandTimeoutUserProvided,
|
||||
timedOut: result.timedOut,
|
||||
},
|
||||
degradedReason,
|
||||
probe,
|
||||
result: compactCommandResult(result),
|
||||
valuesRedacted: true,
|
||||
@@ -9212,16 +9272,25 @@ function parseJsonObject(text: string): Record<string, unknown> | null {
|
||||
function compactWebProbeResult(report: Record<string, unknown> | null): Record<string, unknown> | null {
|
||||
if (report === null) return null;
|
||||
const dom = record(report.dom);
|
||||
const performance = record(report.performance);
|
||||
const trace = record(report.trace);
|
||||
const session = record(report.session);
|
||||
return {
|
||||
ok: report.ok === true,
|
||||
status: typeof report.status === "string" ? report.status : null,
|
||||
finalUrl: typeof report.finalUrl === "string" ? report.finalUrl : null,
|
||||
error: typeof report.error === "string" ? report.error : null,
|
||||
actions: Array.isArray(report.actions) ? report.actions : [],
|
||||
degradedReason: typeof report.degradedReason === "string" ? report.degradedReason : null,
|
||||
actions: compactWebProbeActions(report.actions),
|
||||
session,
|
||||
trace,
|
||||
performance,
|
||||
traceSamples: Array.isArray(report.traceSamples) ? report.traceSamples : [],
|
||||
dom: {
|
||||
authState: typeof dom.authState === "string" ? dom.authState : null,
|
||||
requiredSelectors: record(dom.requiredSelectors),
|
||||
messageCount: typeof dom.messageCount === "number" ? dom.messageCount : null,
|
||||
sessionRail: record(dom.sessionRail),
|
||||
},
|
||||
failureDom: record(report.failureDom),
|
||||
artifacts: record(report.artifacts),
|
||||
@@ -9229,6 +9298,58 @@ function compactWebProbeResult(report: Record<string, unknown> | null): Record<s
|
||||
};
|
||||
}
|
||||
|
||||
function compactWebProbeActions(value: unknown): Record<string, unknown>[] {
|
||||
if (!Array.isArray(value)) return [];
|
||||
return value.map(record).map((action) => {
|
||||
const name = typeof action.action === "string" ? action.action : "unknown";
|
||||
if (name === "fresh-session") {
|
||||
const alignment = record(action.alignment);
|
||||
const check = record(alignment.check);
|
||||
const repair = record(alignment.repair);
|
||||
return {
|
||||
action: name,
|
||||
settled: action.settled === true,
|
||||
aligned: action.aligned === true,
|
||||
reason: alignment.reason ?? check.reason ?? null,
|
||||
conversationId: check.conversationId ?? null,
|
||||
routeConversationId: check.routeConversationId ?? null,
|
||||
selectedConversationId: check.selectedConversationId ?? null,
|
||||
repaired: Object.keys(repair).length > 0,
|
||||
repairConversationId: repair.conversationId ?? null,
|
||||
attempts: Array.isArray(alignment.attempts) ? alignment.attempts.length : null,
|
||||
};
|
||||
}
|
||||
if (name === "trace-interval-samples") {
|
||||
return {
|
||||
action: name,
|
||||
count: action.count ?? null,
|
||||
intervalMs: action.intervalMs ?? null,
|
||||
};
|
||||
}
|
||||
if (name === "submit-prompt") {
|
||||
return {
|
||||
action: name,
|
||||
chars: action.chars ?? null,
|
||||
submittedAt: action.submittedAt ?? null,
|
||||
};
|
||||
}
|
||||
if (name === "wait-agent-terminal") {
|
||||
return {
|
||||
action: name,
|
||||
terminal: action.terminal === true,
|
||||
timeoutMs: action.timeoutMs ?? null,
|
||||
};
|
||||
}
|
||||
return {
|
||||
action: name,
|
||||
skipped: action.skipped ?? null,
|
||||
ready: action.ready ?? null,
|
||||
found: action.found ?? null,
|
||||
timeoutMs: action.timeoutMs ?? null,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function compactCommand(command: string[]): string[] {
|
||||
const scriptIndex = command.indexOf("--");
|
||||
if (scriptIndex >= 0 && scriptIndex + 1 < command.length) return [...command.slice(0, scriptIndex + 1), "<script omitted>"];
|
||||
|
||||
Reference in New Issue
Block a user