openhands / src /utils /automation-run-display.ts
SaylorTwift's picture
SaylorTwift HF Staff
Add files using upload-large-folder tool
5f40163 verified
Raw History Blame Contribute Delete
4.92 kB
import { I18nKey } from "#/i18n/declaration";
import {
AutomationRunStatus,
type AutomationRun,
type AutomationTaskOutcomeStatus,
} from "#/types/automation";
export type AutomationRunBadgeStatus =
| AutomationRunStatus
| AutomationTaskOutcomeStatus;
export interface AutomationRunTaskOutcome {
status: AutomationTaskOutcomeStatus;
outcomeSummary: string | null;
}
export interface AutomationRunDisplay {
badgeStatus: AutomationRunBadgeStatus;
summary: string | null;
taskOutcome: AutomationRunTaskOutcome | null;
customTaskMetadata: unknown | null;
customTaskMetadataText: string | null;
}
const TASK_OUTCOME_STATUSES: readonly AutomationTaskOutcomeStatus[] = [
"success",
"partial_success",
"blocked",
"failed",
"unknown",
];
function isRecord(value: unknown): value is Record<string, unknown> {
return typeof value === "object" && value !== null && !Array.isArray(value);
}
export function isTaskOutcomeStatus(
value: unknown,
): value is AutomationTaskOutcomeStatus {
return (
typeof value === "string" &&
TASK_OUTCOME_STATUSES.includes(value as AutomationTaskOutcomeStatus)
);
}
function trimString(value: unknown): string | null {
if (typeof value !== "string") return null;
return value.trim() || null;
}
const DEFAULT_FINISH_TOOL_RESPONSE_KEYS = new Set([
"status",
"outcome_summary",
]);
export function getAutomationRunFinishToolResponse(
run: AutomationRun,
): unknown | null {
const response = run.run_metadata?.finish_tool_response;
return response === undefined || response === null ? null : response;
}
export function formatAutomationRunTaskMetadata(
metadata: unknown,
): string | null {
const trimmed = trimString(metadata);
if (trimmed) return trimmed;
if (typeof metadata === "number" || typeof metadata === "boolean") {
return String(metadata);
}
if (metadata === null || metadata === undefined) return null;
try {
return JSON.stringify(metadata, null, 2);
} catch {
return String(metadata);
}
}
function getCustomFinishToolMetadata(response: unknown): unknown | null {
if (response === null || response === undefined) return null;
if (!isRecord(response)) return response;
const customEntries = Object.entries(response).filter(
([key]) => !DEFAULT_FINISH_TOOL_RESPONSE_KEYS.has(key),
);
if (customEntries.length > 0) return Object.fromEntries(customEntries);
if ("status" in response && !isTaskOutcomeStatus(response.status)) {
return { status: response.status };
}
return null;
}
export function getAutomationRunTaskOutcome(
run: AutomationRun,
): AutomationRunTaskOutcome | null {
const response = getAutomationRunFinishToolResponse(run);
if (!isRecord(response)) return null;
const outcomeSummary = trimString(response.outcome_summary);
const hasStatus = typeof response.status === "string";
if (!hasStatus && !outcomeSummary) return null;
return {
status: isTaskOutcomeStatus(response.status) ? response.status : "unknown",
outcomeSummary,
};
}
export function getAutomationRunDisplay(
run: AutomationRun,
): AutomationRunDisplay {
const finishToolResponse = getAutomationRunFinishToolResponse(run);
const customTaskMetadata = getCustomFinishToolMetadata(finishToolResponse);
const customTaskMetadataText =
formatAutomationRunTaskMetadata(customTaskMetadata);
const taskOutcome = getAutomationRunTaskOutcome(run);
const systemSummary = trimString(run.error_detail);
if (run.status === AutomationRunStatus.COMPLETED) {
return {
badgeStatus:
taskOutcome?.status ??
(finishToolResponse !== null ? "unknown" : "success"),
summary: taskOutcome?.outcomeSummary ?? null,
taskOutcome,
customTaskMetadata,
customTaskMetadataText,
};
}
return {
badgeStatus: run.status,
summary: systemSummary,
taskOutcome,
customTaskMetadata,
customTaskMetadataText,
};
}
export function getAutomationRunBadgeLabelKey(
status: AutomationRunBadgeStatus | string,
): I18nKey {
switch (status) {
case AutomationRunStatus.COMPLETED:
case "success":
return I18nKey.AUTOMATIONS$DETAIL$SUCCESSFUL;
case AutomationRunStatus.FAILED:
case "failed":
return I18nKey.AUTOMATIONS$DETAIL$FAILED;
case AutomationRunStatus.PENDING:
return I18nKey.AUTOMATIONS$DETAIL$PENDING;
case AutomationRunStatus.RUNNING:
return I18nKey.AUTOMATIONS$DETAIL$RUNNING;
case AutomationRunStatus.CANCELLED:
return I18nKey.AUTOMATIONS$DETAIL$CANCELLED;
case AutomationRunStatus.SKIPPED:
return I18nKey.AUTOMATIONS$DETAIL$SKIPPED;
case "blocked":
return I18nKey.AUTOMATIONS$DETAIL$BLOCKED;
case "partial_success":
return I18nKey.AUTOMATIONS$DETAIL$PARTIAL;
case "unknown":
return I18nKey.AUTOMATIONS$DETAIL$NEEDS_REVIEW;
default:
return I18nKey.FEATURED_AUTOMATIONS$STATUS_UNKNOWN;
}
}