import { Q as REALTIME_VOICE_AUDIO_FORMAT_G711_ULAW_8KHZ, tt as realtimeVoiceAudioDurationMs } from "./realtime-session-harness-Bar0SzWc.js";
import "./realtime-voice-3l4nbarj.js";
import { D as parsePlaybackMarkSequence, g as buildOpenAIRealtimeTurnDetectionConfig, h as buildOpenAIRealtimeGaSessionPolicy, w as normalizeOpenAIRealtimeTools } from "./realtime-voice-session-policy-CyB3WkFT.js";
import { randomUUID } from "node:crypto";
//#region extensions/openai/realtime-voice-protocol.ts
var OpenAIRealtimeProtocol = class {
	static {
		this.MAX_TOOL_ARGUMENT_BYTES = 256e3;
	}
	static {
		this.MAX_COMPLETED_TOOL_CALL_IDS = 1024;
	}
	constructor(config) {
		this.config = config;
		this.supportsToolResultContinuation = true;
		this.supportsToolResultSuppression = true;
		this.nextMarkSequence = 1;
		this.oldestOutstandingMarkSequence = null;
		this.latestOutstandingMarkSequence = null;
		this.responseActive = false;
		this.responseCreateInFlight = false;
		this.manualResponseCreateEventId = null;
		this.responseCancelInFlight = false;
		this.manualResponseCancelEventId = null;
		this.responseCreatePending = false;
		this.autoRespondSuppressedForManualResponse = false;
		this.continuingToolCallIds = /* @__PURE__ */ new Set();
		this.pendingToolCallIds = /* @__PURE__ */ new Set();
		this.latestMediaTimestamp = 0;
		this.assistantAudioItem = null;
		this.completedToolCallIds = /* @__PURE__ */ new Set();
		this.standaloneSpeechQueue = [];
		this.standaloneSpeechActive = false;
		this.standaloneSpeechEventId = null;
		this.audioFormat = config.audioFormat ?? REALTIME_VOICE_AUDIO_FORMAT_G711_ULAW_8KHZ;
	}
	setMediaTimestamp(ts) {
		this.latestMediaTimestamp = ts;
	}
	acknowledgeMark(markName) {
		const oldest = this.oldestOutstandingMarkSequence;
		const latest = this.latestOutstandingMarkSequence;
		if (oldest === null || latest === null) return;
		const acknowledgedSequence = markName === void 0 ? oldest : parsePlaybackMarkSequence(markName);
		if (acknowledgedSequence === void 0 || acknowledgedSequence < oldest || acknowledgedSequence > latest) return;
		if (acknowledgedSequence === latest) {
			this.oldestOutstandingMarkSequence = null;
			this.latestOutstandingMarkSequence = null;
			return;
		}
		this.oldestOutstandingMarkSequence = acknowledgedSequence + 1;
	}
	sendSessionUpdate() {
		if (this.usesAzureDeploymentRealtimeApi()) {
			this.sendEvent(this.buildAzureDeploymentSessionUpdate());
			return;
		}
		this.sendEvent(this.buildGaSessionUpdate());
	}
	buildGaSessionUpdate() {
		const cfg = this.config;
		return {
			type: "session.update",
			session: cfg.gaSessionPolicy ?? buildOpenAIRealtimeGaSessionPolicy({
				audioFormat: this.audioFormat,
				autoRespondToAudio: cfg.autoRespondToAudio,
				instructions: cfg.instructions,
				interruptResponseOnInputAudio: cfg.interruptResponseOnInputAudio,
				language: cfg.language,
				model: cfg.model ?? "gpt-realtime-2.1",
				noiseReduction: null,
				prefixPaddingMs: cfg.prefixPaddingMs,
				reasoningEffort: cfg.reasoningEffort,
				silenceDurationMs: cfg.silenceDurationMs,
				tools: normalizeOpenAIRealtimeTools(cfg.tools),
				vadThreshold: cfg.vadThreshold,
				voice: cfg.voice ?? "alloy"
			})
		};
	}
	usesAzureDeploymentRealtimeApi() {
		return Boolean(this.config.azureEndpoint && this.config.azureDeployment);
	}
	buildAzureDeploymentSessionUpdate() {
		const cfg = this.config;
		const format = this.resolveLegacyRealtimeAudioFormat();
		const tools = normalizeOpenAIRealtimeTools(cfg.tools, 64);
		return {
			type: "session.update",
			session: {
				modalities: ["text", "audio"],
				instructions: cfg.instructions,
				voice: cfg.voice ?? "alloy",
				input_audio_format: format,
				output_audio_format: format,
				input_audio_transcription: {
					model: "whisper-1",
					...cfg.language ? { language: cfg.language } : {}
				},
				turn_detection: this.buildTurnDetectionConfig(),
				temperature: cfg.temperature ?? .8,
				...tools ? {
					tools,
					tool_choice: "auto"
				} : {}
			}
		};
	}
	buildTurnDetectionConfig(options) {
		return buildOpenAIRealtimeTurnDetectionConfig({
			autoRespondToAudio: this.config.autoRespondToAudio,
			createResponse: options?.createResponse,
			includeInterruptResponse: options?.includeInterruptResponse,
			interruptResponseOnInputAudio: this.config.interruptResponseOnInputAudio,
			prefixPaddingMs: this.config.prefixPaddingMs,
			silenceDurationMs: this.config.silenceDurationMs,
			vadThreshold: this.config.vadThreshold
		});
	}
	sendAutoResponseSessionUpdate(createResponse) {
		const azureDeployment = this.usesAzureDeploymentRealtimeApi();
		const turnDetection = this.buildTurnDetectionConfig({
			createResponse,
			includeInterruptResponse: !azureDeployment
		});
		if (azureDeployment) {
			this.sendEvent({
				type: "session.update",
				session: { turn_detection: turnDetection }
			});
			return;
		}
		this.sendEvent({
			type: "session.update",
			session: {
				type: "realtime",
				audio: { input: { turn_detection: turnDetection } }
			}
		});
	}
	resolveLegacyRealtimeAudioFormat() {
		return this.audioFormat.encoding === "pcm16" ? "pcm16" : "g711_ulaw";
	}
	releaseResponseState(options = {}) {
		this.responseActive = false;
		this.responseCreateInFlight = false;
		this.manualResponseCreateEventId = null;
		this.responseCancelInFlight = false;
		this.manualResponseCancelEventId = null;
		if (this.standaloneSpeechActive) {
			this.standaloneSpeechActive = false;
			this.standaloneSpeechEventId = null;
		}
		if (options.drain === false) return;
		if (this.standaloneSpeechQueue.length > 0) this.flushStandaloneSpeech();
		else if (this.responseCreatePending) this.flushPendingResponseCreate();
		else this.restoreAutoRespondAfterManualResponse();
	}
	handleBargeIn(options) {
		const assistantAudioItem = this.assistantAudioItem;
		const force = options?.force === true;
		const shouldInterruptProvider = assistantAudioItem !== null && (this.oldestOutstandingMarkSequence !== null || options?.audioPlaybackActive === true || force);
		const audioEndMs = shouldInterruptProvider && assistantAudioItem ? Math.min(Math.floor(realtimeVoiceAudioDurationMs(this.audioFormat, assistantAudioItem.bytes)), Math.max(0, this.latestMediaTimestamp - assistantAudioItem.startTimestamp)) : null;
		const minBargeInAudioEndMs = this.config.minBargeInAudioEndMs ?? 250;
		if (!force && audioEndMs !== null && audioEndMs < minBargeInAudioEndMs) {
			this.config.onEvent?.({
				direction: "client",
				type: "conversation.item.truncate.skipped",
				detail: `reason=barge-in audioEndMs=${audioEndMs} minAudioEndMs=${minBargeInAudioEndMs}`
			});
			return;
		}
		if (options?.audioPlaybackActive === true && this.responseActive && !this.responseCancelInFlight) {
			const eventId = `openclaw-response-cancel-${randomUUID()}`;
			this.manualResponseCancelEventId = eventId;
			this.sendEvent({
				type: "response.cancel",
				event_id: eventId
			}, "reason=barge-in");
			this.responseCancelInFlight = true;
		}
		if (shouldInterruptProvider && assistantAudioItem) {
			this.sendEvent({
				type: "conversation.item.truncate",
				item_id: assistantAudioItem.itemId,
				content_index: 0,
				audio_end_ms: audioEndMs
			}, `reason=barge-in audioEndMs=${audioEndMs}`);
			this.config.onClearAudio("barge-in");
			this.clearOutstandingMarks();
			this.assistantAudioItem = null;
			return;
		}
		this.config.onClearAudio("barge-in");
	}
	requestResponseCreate(options) {
		if (this.responseActive || this.responseCreateInFlight || this.responseCancelInFlight || this.continuingToolCallIds.size > 0 || this.pendingToolCallIds.size > 0) {
			this.responseCreatePending = true;
			return;
		}
		this.responseCreatePending = false;
		this.responseCreateInFlight = true;
		this.suppressAutoRespondForManualResponse();
		const eventId = `openclaw-response-create-${randomUUID()}`;
		this.manualResponseCreateEventId = eventId;
		this.sendEvent({
			type: "response.create",
			event_id: eventId,
			...options?.toolChoice ? { response: {
				output_modalities: ["audio"],
				tool_choice: options.toolChoice
			} } : {}
		});
	}
	flushStandaloneSpeech() {
		if (this.standaloneSpeechActive || this.responseActive || this.responseCreateInFlight || this.responseCancelInFlight) return;
		const text = this.standaloneSpeechQueue.shift();
		if (!text) return;
		const eventId = `openclaw-standalone-speech-${randomUUID()}`;
		this.standaloneSpeechActive = true;
		this.standaloneSpeechEventId = eventId;
		this.responseCreateInFlight = true;
		this.sendEvent({
			type: "response.create",
			event_id: eventId,
			response: {
				conversation: "none",
				output_modalities: ["audio"],
				input: [{
					type: "message",
					role: "user",
					content: [{
						type: "input_text",
						text
					}]
				}]
			}
		});
	}
	suppressAutoRespondForManualResponse() {
		if (this.config.autoRespondToAudio === false || this.autoRespondSuppressedForManualResponse) return;
		this.autoRespondSuppressedForManualResponse = true;
		this.sendAutoResponseSessionUpdate(false);
	}
	restoreAutoRespondAfterManualResponse() {
		if (!this.autoRespondSuppressedForManualResponse) return;
		this.autoRespondSuppressedForManualResponse = false;
		this.sendAutoResponseSessionUpdate(true);
	}
	flushPendingResponseCreate() {
		if (!this.responseCreatePending) return;
		this.responseCreatePending = false;
		this.requestResponseCreate();
	}
	resetRealtimeSessionState() {
		this.clearOutstandingMarks();
		this.assistantAudioItem = null;
		this.responseActive = false;
		this.responseCreateInFlight = false;
		this.manualResponseCreateEventId = null;
		this.responseCancelInFlight = false;
		this.manualResponseCancelEventId = null;
		this.responseCreatePending = false;
		this.autoRespondSuppressedForManualResponse = false;
		this.continuingToolCallIds.clear();
		this.pendingToolCallIds.clear();
		this.completedToolCallIds.clear();
		this.standaloneSpeechQueue = [];
		this.standaloneSpeechActive = false;
		this.standaloneSpeechEventId = null;
	}
	sendMark() {
		const sequence = this.nextMarkSequence;
		this.nextMarkSequence += 1;
		if (this.oldestOutstandingMarkSequence === null) this.oldestOutstandingMarkSequence = sequence;
		this.latestOutstandingMarkSequence = sequence;
		const markName = `audio-${sequence}`;
		this.config.onMark?.(markName);
	}
	clearOutstandingMarks() {
		this.oldestOutstandingMarkSequence = null;
		this.latestOutstandingMarkSequence = null;
	}
};
//#endregion
export { OpenAIRealtimeProtocol as t };
