//#region src/agent/orchestration/llm-turn-retry.ts
const TRANSIENT_LLM_ERROR_SUBSTRINGS = [
	"fetch failed",
	"econnreset",
	"econnrefused",
	"enotfound",
	"socket hang up",
	"getaddrinfo",
	"networkerror",
	"etimedout",
	"certificate",
	"ssl",
	"tls"
];
function isTransientLlmErrorMessage(message) {
	const lower = message.toLowerCase();
	return TRANSIENT_LLM_ERROR_SUBSTRINGS.some((s) => lower.includes(s));
}
function getLastAssistantMessage(messages) {
	for (let i = messages.length - 1; i >= 0; i--) if (messages[i].role === "assistant") return messages[i];
}
/** Raw provider/LLM error from the last failed assistant message, if any. */
function getAssistantTurnErrorMessage(agent) {
	const last = getLastAssistantMessage(agent.state.messages);
	if (!last) return void 0;
	if (last.stopReason !== "error") return void 0;
	const errMsg = last.errorMessage;
	if (typeof errMsg === "string" && errMsg.trim()) return errMsg.trim();
}
/** After waitForIdle + transient retries, true if the last assistant turn ended in error. */
function isAssistantTurnFailed(agent) {
	const last = getLastAssistantMessage(agent.state.messages);
	if (!last) return true;
	return last.stopReason === "error";
}
/** User or client aborted the assistant turn — do not try another model. */
function isAssistantTurnAborted(agent) {
	const last = getLastAssistantMessage(agent.state.messages);
	if (!last) return false;
	return last.stopReason === "aborted";
}
/**
* Remove trailing assistant messages that ended in error/aborted (typically one).
*/
function stripTrailingErrorAssistantMessages(messages) {
	const out = [...messages];
	while (out.length > 0) {
		const last = out[out.length - 1];
		if (last.role !== "assistant") break;
		const sr = last.stopReason;
		if (sr === "error" || sr === "aborted") {
			out.pop();
			continue;
		}
		break;
	}
	return out;
}
/**
* After waitForIdle(), call this to optionally re-run the last user turn when the
* assistant message only contains a transient provider/network error.
*/
async function maybeRetryTurnAfterTransientLlmFailure(agent, options) {
	const maxContinues = options.maxContinues ?? 2;
	let continues = 0;
	while (continues < maxContinues) {
		const last = getLastAssistantMessage(agent.state.messages);
		if (!last) return;
		if (last.stopReason !== "error") return;
		const errMsg = String(last.errorMessage || "");
		if (!isTransientLlmErrorMessage(errMsg)) {
			options.log.warn({
				sessionKey: options.sessionKey,
				errorMessage: errMsg
			}, "Assistant turn ended with error (not retrying as transient)");
			return;
		}
		continues += 1;
		options.log.warn({
			sessionKey: options.sessionKey,
			errorMessage: errMsg,
			continueAttempt: continues,
			maxContinues
		}, "LLM request failed with a transient network error; retrying the same turn. If this persists, check outbound HTTPS to the provider API and HTTP(S)_PROXY.");
		const trimmed = stripTrailingErrorAssistantMessages(agent.state.messages);
		agent.state.messages = trimmed;
		await agent.continue();
		await agent.waitForIdle();
	}
}
//#endregion
export { getAssistantTurnErrorMessage, getLastAssistantMessage, isAssistantTurnAborted, isAssistantTurnFailed, isTransientLlmErrorMessage, maybeRetryTurnAfterTransientLlmFailure, stripTrailingErrorAssistantMessages };

//# sourceMappingURL=llm-turn-retry.js.map