UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

133 lines (132 loc) 6 kB
import { n as isAbortError } from "./abort-signal-D2k14JsD.js"; import { t as formatErrorMessage } from "./errors-Db3Ymjlb.js"; import { o as getDiagnosticSessionActivitySnapshot } from "./diagnostic-run-activity-CJrEba4R.js"; import { a as buildRealtimeVoiceAgentCancelProviderResult, l as formatRealtimeVoiceAgentQueueRejection, p as resolveRealtimeVoiceAgentControlIntent, s as buildRealtimeVoiceAgentFollowupSteeringText, u as formatRealtimeVoiceAgentStatus } from "./agent-run-control-shared-zVaKVJuy.js"; //#region src/talk/agent-run-control.ts const controlResultPresentation = { speak: true, show: true, suppress: false }; /** Host error projection needs server-side redaction, outside browser-shared contracts. */ function buildRealtimeVoiceAgentErrorProviderResult(error) { return isAbortError(error) ? buildRealtimeVoiceAgentCancelProviderResult() : { error: formatErrorMessage(error) }; } /** Apply a spoken status, cancel, steer, or follow-up request to an active run. */ async function controlRealtimeVoiceAgentRun(params, providedDeps) { const sessionKey = params.sessionKey.trim(); const text = params.text.trim(); const mode = resolveRealtimeVoiceAgentControlIntent({ text, mode: params.mode }).mode; const controlResultContext = { mode, sessionKey }; const target = params.runTarget; let commands = providedDeps; if (!commands && target && !target.signal.aborted && target.isCurrent()) commands = (await import("./agent-run-control.runtime.js")).realtimeVoiceControlRuntime; const projections = commands ?? (target === void 0 ? await import("./active-run-projections-gG4OCrrt.js") : void 0); const resolveCurrentRun = () => { const candidate = target && !target.signal.aborted && target.isCurrent() ? commands?.resolveActiveEmbeddedRunOwnerByRunId?.(target.runId) ?? commands?.resolveActiveReplyRunOwnerForSignal?.(target.signal) : void 0; const exactOwner = candidate?.sessionKey === sessionKey && target?.isCurrent(candidate.sessionId) ? candidate : void 0; return { sessionId: target === void 0 ? projections?.resolveActiveEmbeddedRunSessionId(sessionKey) : exactOwner?.sessionId, exactOwner }; }; let current = resolveCurrentRun(); const readActivity = providedDeps?.getDiagnosticSessionActivitySnapshot ?? getDiagnosticSessionActivitySnapshot; const activity = target === void 0 ? readActivity({ sessionId: current.sessionId, sessionKey }) : current.sessionId ? readActivity({ sessionId: current.sessionId }) : void 0; const active = Boolean(current.sessionId || activity?.activeWorkKind || activity?.hasActiveEmbeddedRun); if (mode === "status") return { ok: true, ...controlResultContext, ...current.sessionId ? { sessionId: current.sessionId } : {}, active, message: formatRealtimeVoiceAgentStatus({ active, recentEvents: params.recentEvents, activity }), ...controlResultPresentation }; const noActiveRun = () => ({ ok: false, ...controlResultContext, active: false, ...mode === "cancel" ? { aborted: false } : { queued: false }, reason: "no_active_run", message: `There is no active OpenClaw run to ${mode === "cancel" ? "cancel" : "steer"}.`, ...controlResultPresentation }); if (!current.sessionId) return noActiveRun(); if (!commands) { commands = (await import("./agent-run-control.runtime.js")).realtimeVoiceControlRuntime; current = resolveCurrentRun(); } const { sessionId, exactOwner } = current; if (!sessionId) return noActiveRun(); if (mode === "cancel") { const aborted = target === void 0 ? commands.abortEmbeddedAgentRun(sessionId) : exactOwner?.abort() === true; const message = aborted ? "Cancelled the active OpenClaw run." : "OpenClaw could not cancel the active run."; return { ok: aborted, ...controlResultContext, sessionId, active: true, aborted, ...aborted ? {} : { reason: "abort_rejected" }, message, ...controlResultPresentation, ...aborted ? { providerResult: buildRealtimeVoiceAgentCancelProviderResult(message) } : {} }; } const toolAuthorityOverlay = params.getToolAuthorityOverlay?.(); if (resolveCurrentRun().sessionId !== sessionId || target && !target.isCurrent(sessionId)) return noActiveRun(); const steerText = mode === "followup" ? buildRealtimeVoiceAgentFollowupSteeringText(text) : text; const options = { steeringMode: "all", debounceMs: 0, isInboundUserMessage: true, toolAuthorityOverlay, taskSuggestionDeliveryMode: void 0 }; const outcome = target ? commands.queueGuardedEmbeddedAgentMessageWithOutcomeAsync ? await commands.queueGuardedEmbeddedAgentMessageWithOutcomeAsync(sessionId, steerText, options, () => !target.signal.aborted && target.isCurrent(sessionId)) : { queued: false, sessionId, gatewayHealth: "live", reason: "guarded_injection_unsupported" } : await commands.queueEmbeddedAgentMessageWithOutcomeAsync(sessionId, steerText, options); if (!outcome.queued) return { ok: false, ...controlResultContext, sessionId: outcome.sessionId, active: true, queued: false, reason: outcome.reason, message: formatRealtimeVoiceAgentQueueRejection(mode, outcome.reason), ...controlResultPresentation }; const unconfirmed = outcome.transcriptCommit === "unconfirmed"; const message = unconfirmed ? "OpenClaw could not confirm that input. It was not sent again; check the conversation before retrying." : mode === "followup" ? "Queued that follow-up for the active OpenClaw run." : "Got it. I steered the active run."; return { ok: !unconfirmed, ...controlResultContext, sessionId: outcome.sessionId, active: true, queued: true, target: outcome.target, ...unconfirmed ? { reason: "delivery_unconfirmed" } : {}, message, ...controlResultPresentation, ...outcome.enqueuedAtMs !== void 0 ? { enqueuedAtMs: outcome.enqueuedAtMs } : {}, ...outcome.deliveredAtMs !== void 0 ? { deliveredAtMs: outcome.deliveredAtMs } : {} }; } //#endregion export { controlRealtimeVoiceAgentRun as n, buildRealtimeVoiceAgentErrorProviderResult as t };