import { isTimeoutAbortError } from "../media-shared/http/deadline.js";
import { ProviderHttpError } from "../media-shared/http/provider-http-errors.js";
import "../media-shared/http/index.js";
//#region src/agent/failover-error.ts
/**
* FailoverError — uniform terminal error after all candidate provider/model
* attempts have failed.
*
* Used by capability runtimes (image / audio / video) so that:
*   - the agent surface gets a single error message
*   - the tool layer can serialize structured `attempts` for the LLM and UI
*   - downstream code can reason about a "reason" enum instead of parsing
*     vendor-specific status codes.
*
* Step 1: pure model. Step 2 wires it into the new image-generation runtime.
*/
var FailoverError = class extends Error {
	capability;
	attempts;
	/** Convenience: reason from the last attempt, or 'unknown' if empty. */
	reason;
	/** Convenience: status from the last attempt. */
	status;
	/** Convenience: code from the last attempt. */
	code;
	/** Convenience: provider from the last attempt. */
	provider;
	/** Convenience: model from the last attempt. */
	model;
	constructor(init) {
		const last = init.attempts[init.attempts.length - 1];
		const message = init.message ?? defaultMessage(init.capability, init.attempts);
		super(message);
		this.name = "FailoverError";
		this.capability = init.capability;
		this.attempts = Object.freeze([...init.attempts]);
		this.reason = last?.reason ?? "unknown";
		this.status = last?.status;
		this.code = last?.code;
		this.provider = last?.provider;
		this.model = last?.model;
		if (init.cause !== void 0) this.cause = init.cause;
	}
};
/** Cross-realm-safe predicate (instanceof breaks across vm boundaries). */
function isFailoverError(e) {
	if (e instanceof FailoverError) return true;
	if (!e || typeof e !== "object") return false;
	const obj = e;
	return obj.name === "FailoverError" && typeof obj.capability === "string" && Array.isArray(obj.attempts);
}
/**
* Pretty multi-line description for logs / CLI output. Each line is
* `<i>. <provider>/<model> [<reason>] (status=<n>): <error>`.
*/
function describeFailoverError(e) {
	return [`[${e.capability}] ${e.attempts.length} attempt(s) failed`, ...e.attempts.map((a, i) => {
		const parts = [`${i + 1}. ${a.provider}/${a.model}`, `[${a.reason}]`];
		if (a.status !== void 0) parts.push(`status=${a.status}`);
		if (a.code) parts.push(`code=${a.code}`);
		parts.push(`- ${a.error}`);
		return parts.join(" ");
	})].join("\n");
}
/**
* Map an HTTP status to a {@link FailoverReason}.
*/
function reasonFromHttpStatus(status) {
	if (typeof status !== "number" || !Number.isFinite(status)) return "unknown";
	if (status === 401 || status === 403) return "auth";
	if (status === 404) return "not_found";
	if (status === 408) return "timeout";
	if (status === 429) return "rate_limit";
	if (status >= 400 && status < 500) return "bad_request";
	if (status >= 500 && status < 600) return "server_error";
	return "unknown";
}
/**
* Best-effort classifier from an arbitrary thrown value into a
* {@link FallbackAttempt}-friendly shape.
*/
function classifyAttemptError(e) {
	if (e instanceof ProviderHttpError) return {
		reason: reasonFromHttpStatus(e.status),
		status: e.status,
		code: e.code,
		message: e.message
	};
	if (isTimeoutAbortError(e)) return {
		reason: "timeout",
		message: e.message
	};
	if (isAbortError(e)) return {
		reason: "aborted",
		message: "Request aborted by caller"
	};
	if (isFetchTransportError(e)) return {
		reason: "network",
		message: e instanceof Error ? e.message : String(e)
	};
	return {
		reason: "unknown",
		message: e instanceof Error ? e.message : String(e)
	};
}
function defaultMessage(capability, attempts) {
	if (attempts.length === 0) return `Capability "${capability}" failed: no candidates were attempted.`;
	const last = attempts[attempts.length - 1];
	const summary = `${last.provider}/${last.model} failed with ${last.reason}`;
	return `Capability "${capability}" failed after ${attempts.length} attempt(s); last: ${summary}: ${last.error}`;
}
function isAbortError(e) {
	if (!e || typeof e !== "object") return false;
	return e.name === "AbortError";
}
function isFetchTransportError(e) {
	if (!(e instanceof Error)) return false;
	const msg = e.message.toLowerCase();
	return msg.includes("fetch failed") || msg.includes("network") || msg.includes("econnrefused") || msg.includes("econnreset") || msg.includes("enotfound");
}
//#endregion
export { FailoverError, classifyAttemptError, describeFailoverError, isFailoverError, reasonFromHttpStatus };

//# sourceMappingURL=failover-error.js.map