import { BestAgentError } from "@best-agent/foundation";
export function classifyRuntimeFailure(error) {
    return classifyRuntimeFailureBase(error);
}
function classifyRuntimeFailureBase(error) {
    const bestAgentError = asBestAgentErrorLike(error);
    if (bestAgentError) {
        return classifyBestAgentErrorBase(bestAgentError);
    }
    if (error instanceof Error) {
        const normalized = error.message.toLowerCase();
        if (error.name === "AbortError" ||
            normalized.includes("interrupted") ||
            normalized.includes("shutdown")) {
            return {
                failureKind: "interrupted",
                recoverability: "interrupted",
                scope: "turn",
            };
        }
        if (isRepairableToolValidationMessage(normalized)) {
            return {
                errorCode: inferRepairableToolValidationCode(normalized),
                failureKind: "validation-failed",
                recoverability: "repairable",
                scope: "tool",
            };
        }
        if (isRepairableToolExecutionMessage(normalized)) {
            return {
                errorCode: "EXEC_FAILED",
                failureKind: "execution-failed",
                recoverability: "repairable",
                scope: "tool",
            };
        }
        if (isProviderContextOverflowMessage(normalized)) {
            return {
                errorCode: "PROVIDER_CONTEXT_OVERFLOW",
                failureKind: "dispatch-failed",
                recoverability: "blocked",
                scope: "turn",
            };
        }
        if (isRetryableTransportMessage(normalized)) {
            return {
                failureKind: "dispatch-failed",
                recoverability: "retryable",
                scope: "provider",
            };
        }
        if (normalized.includes("insufficient_quota") ||
            normalized.includes("quota") ||
            normalized.includes("api key") ||
            normalized.includes("unauthorized") ||
            normalized.includes("forbidden") ||
            normalized.includes("401") ||
            normalized.includes("403")) {
            return {
                failureKind: "denied",
                recoverability: "blocked",
                scope: "provider",
            };
        }
    }
    return {
        failureKind: "execution-failed",
        recoverability: "unknown",
        scope: "turn",
    };
}
export function isBlockedRuntimeFailure(error) {
    return classifyRuntimeFailure(error).recoverability === "blocked";
}
export function isRepairableToolFailure(error) {
    return classifyRuntimeFailure(error).recoverability === "repairable";
}
function classifyBestAgentErrorBase(error) {
    switch (error.code) {
        case "CAPABILITY_DENIED":
            return {
                failureKind: "denied",
                errorCode: error.code,
                recoverability: "blocked",
                scope: "approval",
            };
        case "TOOL_CAPABILITY_DENIED":
            return {
                failureKind: "denied",
                errorCode: error.code,
                recoverability: "repairable",
                scope: "tool",
            };
        case "ACTION_EXPIRED":
            return {
                failureKind: "denied",
                errorCode: error.code,
                recoverability: "blocked",
                scope: "approval",
            };
        case "TOOL_HEARTBEAT_STALLED":
            return {
                failureKind: "heartbeat-timeout",
                errorCode: error.code,
                recoverability: "repairable",
                scope: "tool",
            };
        case "ADVANCED_PHASE_BUDGET_EXCEEDED":
            return {
                failureKind: "execution-failed",
                errorCode: error.code,
                recoverability: "blocked",
                scope: "turn",
            };
        case "REQUEST_BUDGET_EXCEEDED":
        case "PROVIDER_TURN_BUDGET_EXCEEDED":
        case "TURN_BLOCKED":
            return {
                failureKind: "dispatch-failed",
                errorCode: error.code,
                recoverability: "blocked",
                scope: "turn",
            };
        case "CUSTOM_LOOP_FAILED":
            return {
                failureKind: isToolFailureKind(error.failureKind) ? error.failureKind : "execution-failed",
                errorCode: error.code,
                recoverability: isFailureRecoverability(error.recoverability)
                    ? error.recoverability
                    : "unknown",
                scope: isFailureScope(error.scope) ? error.scope : "turn",
            };
        case "CHILD_TASK_PARALLEL_REJECTED":
            return {
                failureKind: "dispatch-failed",
                errorCode: error.code,
                recoverability: "blocked",
                scope: "workflow",
            };
        case "PROVIDER_MISSING":
            return {
                failureKind: "dispatch-failed",
                errorCode: error.code,
                recoverability: "blocked",
                scope: "provider",
            };
        case "PROVIDER_DECISION_INVALID":
        case "PROVIDER_NO_ACTION":
            return {
                failureKind: "validation-failed",
                errorCode: error.code,
                recoverability: "repairable",
                scope: "provider",
            };
        case "TOOL_INPUT_INVALID":
        case "TOOL_INPUT_NOT_FOUND":
        case "TOOL_NOT_ALLOWED":
        case "WORKSPACE_STALE_VIEW":
        case "EXEC_INVALID":
            return {
                failureKind: "validation-failed",
                errorCode: error.code,
                recoverability: "repairable",
                scope: "tool",
            };
        case "EXEC_UNSUPPORTED":
            return {
                failureKind: "validation-failed",
                errorCode: error.code,
                recoverability: "repairable",
                scope: "tool",
            };
        case "PROVIDER_REQUEST_FAILED": {
            const normalized = error.message.toLowerCase();
            if (normalized.includes("insufficient_quota") ||
                normalized.includes("quota") ||
                normalized.includes("api key") ||
                normalized.includes("unauthorized") ||
                normalized.includes("forbidden") ||
                normalized.includes("401") ||
                normalized.includes("403")) {
                return {
                    failureKind: "denied",
                    errorCode: error.code,
                    recoverability: "blocked",
                    scope: "provider",
                };
            }
            if (isRetryableTransportMessage(normalized)) {
                return {
                    failureKind: "dispatch-failed",
                    errorCode: error.code,
                    recoverability: "retryable",
                    scope: "provider",
                };
            }
            if (isProviderEmptyOutputMessage(normalized)) {
                return {
                    failureKind: "validation-failed",
                    errorCode: "PROVIDER_NO_ACTION",
                    recoverability: "repairable",
                    scope: "provider",
                };
            }
            if (isProviderContextOverflowMessage(normalized)) {
                return {
                    failureKind: "dispatch-failed",
                    errorCode: "PROVIDER_CONTEXT_OVERFLOW",
                    recoverability: "blocked",
                    scope: "turn",
                };
            }
            return {
                failureKind: "dispatch-failed",
                errorCode: error.code,
                recoverability: "terminal",
                scope: "provider",
            };
        }
        case "FETCH_FAILED":
            return {
                failureKind: "execution-failed",
                errorCode: error.code,
                recoverability: "retryable",
                scope: "tool",
            };
        case "EXEC_FAILED":
        case "EXEC_COMMAND_NOT_FOUND":
            return {
                failureKind: "execution-failed",
                errorCode: error.code,
                recoverability: "repairable",
                scope: "tool",
            };
        case "TERMINAL_OUTPUT_INVALID":
            return {
                failureKind: "execution-failed",
                errorCode: error.code,
                recoverability: "repairable",
                scope: "turn",
            };
        case "TOOL_RUNTIME":
            return {
                failureKind: "execution-failed",
                errorCode: error.code,
                recoverability: "terminal",
                scope: "tool",
            };
        case "MCP_CALL_FAILED":
            return {
                failureKind: "execution-failed",
                errorCode: error.code,
                recoverability: "retryable",
                scope: "tool",
            };
        case "HOSTED_TOOL_NOT_FOUND":
            return {
                failureKind: "dispatch-failed",
                errorCode: error.code,
                recoverability: "terminal",
                scope: "tool",
            };
        default:
            return {
                failureKind: "execution-failed",
                errorCode: error.code,
                recoverability: "unknown",
                scope: "turn",
            };
    }
}
function isRetryableTransportMessage(normalized) {
    return (normalized.includes("fetch failed") ||
        normalized.includes("timed out") ||
        normalized.includes("timeout") ||
        normalized.includes("time-out") ||
        normalized.includes("aborted") ||
        normalized.includes("connection reset") ||
        normalized.includes("econnreset") ||
        normalized.includes("503") ||
        normalized.includes("502") ||
        normalized.includes("500") ||
        normalized.includes("429") ||
        normalized.includes("rate limit"));
}
function isProviderEmptyOutputMessage(normalized) {
    return normalized.includes("no output generated") && normalized.includes("stream for errors");
}
function isProviderContextOverflowMessage(normalized) {
    return (normalized.includes("context_length_exceeded") ||
        normalized.includes("context length exceeded") ||
        normalized.includes("maximum context length") ||
        (normalized.includes("context window") && normalized.includes("exceed")) ||
        normalized.includes("prompt is too long") ||
        normalized.includes("too many tokens") ||
        normalized.includes("reduce the length of the messages") ||
        (normalized.includes("input tokens") && normalized.includes("exceed")));
}
function isRepairableToolValidationMessage(normalized) {
    return (normalized.includes("received shell syntax") ||
        normalized.includes("does not run shell syntax") ||
        normalized.includes("direct argv only") ||
        normalized.includes("argv[0]") ||
        normalized.includes("requires command as a string") ||
        normalized.includes("requires argv as an array of strings") ||
        normalized.includes("requires an object input with an argv field") ||
        normalized.includes("requires command as a string or argv as an array of strings") ||
        normalized.includes("requires an object input with a command or argv field") ||
        normalized.includes("timeoutms must be a positive integer"));
}
function inferRepairableToolValidationCode(normalized) {
    if (normalized.includes("requires command as a string") ||
        normalized.includes("requires argv as an array of strings") ||
        normalized.includes("requires an object input with an argv field") ||
        normalized.includes("requires command as a string or argv as an array of strings") ||
        normalized.includes("requires an object input with a command or argv field") ||
        normalized.includes("timeoutms must be a positive integer")) {
        return "TOOL_INPUT_INVALID";
    }
    return "EXEC_INVALID";
}
function isRepairableToolExecutionMessage(normalized) {
    return (/command \S+ is not available in this environment/u.test(normalized) ||
        /\bspawn \S+ enoent\b/u.test(normalized) ||
        /(?:^|\n)(?:\/bin\/sh:\s*\d+:\s*|sh:\s*|bash:\s*)\S+:\s*(?:not found|command not found)\b/u.test(normalized) ||
        /(?:^|\n)(?:[^:\n]+:\s+line\s+\d+:\s+)?\S+:\s*command not found\b/u.test(normalized) ||
        /(?:^|\n)env:\s+\S+:\s+no such file or directory\b/u.test(normalized) ||
        /(?:^|\n)[^:\n]+:\s+line\s+\d+:\s+\S*env:\s+no such file or directory\b/u.test(normalized));
}
function asBestAgentErrorLike(error) {
    if (error instanceof BestAgentError) {
        return error;
    }
    if (!error || typeof error !== "object") {
        return undefined;
    }
    const code = error.code;
    const message = error.message;
    if (typeof code !== "string" || typeof message !== "string") {
        return undefined;
    }
    return {
        code,
        failureKind: error.failureKind,
        message,
        recoverability: error.recoverability,
        scope: error.scope,
    };
}
function isToolFailureKind(value) {
    return (value === "interrupted" ||
        value === "denied" ||
        value === "validation-failed" ||
        value === "dispatch-failed" ||
        value === "execution-failed" ||
        value === "heartbeat-timeout" ||
        value === "stale-result-rejected" ||
        value === "replay-disallowed" ||
        value === "verification-failed");
}
function isFailureRecoverability(value) {
    return (value === "retryable" ||
        value === "repairable" ||
        value === "blocked" ||
        value === "interrupted" ||
        value === "terminal" ||
        value === "unknown");
}
function isFailureScope(value) {
    return (value === "turn" ||
        value === "provider" ||
        value === "tool" ||
        value === "approval" ||
        value === "workflow" ||
        value === "child-thread");
}
//# sourceMappingURL=failure-classification.js.map