openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
133 lines (132 loc) • 6 kB
JavaScript
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 };