




















@@ -3,6 +3,8 @@ import {
33normalizeOptionalString,
44} from "../../shared/string-coerce.js";
55import { REALTIME_VOICE_AGENT_CONSULT_TOOL } from "../../talk/agent-consult-tool.js";
6+import { REALTIME_VOICE_AGENT_CONTROL_TOOL } from "../../talk/agent-run-control-shared.js";
7+import { controlRealtimeVoiceAgentRun } from "../../talk/agent-run-control.js";
68import { resolveConfiguredRealtimeVoiceProvider } from "../../talk/provider-resolver.js";
79import type { TalkBrain, TalkMode, TalkTransport } from "../../talk/talk-events.js";
810import { ADMIN_SCOPE } from "../operator-scopes.js";
@@ -16,6 +18,7 @@ import {
1618validateTalkSessionCloseParams,
1719validateTalkSessionCreateParams,
1820validateTalkSessionJoinParams,
21+validateTalkSessionSteerParams,
1922validateTalkSessionSubmitToolResultParams,
2023validateTalkSessionTurnParams,
2124} from "../protocol/index.js";
@@ -33,6 +36,7 @@ import {
3336cancelTalkRealtimeRelayTurn,
3437createTalkRealtimeRelaySession,
3538sendTalkRealtimeRelayAudio,
39+steerTalkRealtimeRelayAgentRun,
3640stopTalkRealtimeRelaySession,
3741submitTalkRealtimeRelayToolResult,
3842} from "../talk-realtime-relay.js";
@@ -270,8 +274,9 @@ export const talkSessionHandlers: GatewayRequestHandlers = {
270274provider: resolution.provider,
271275providerConfig: withRealtimeBrowserOverrides(resolution.providerConfig, launchOptions),
272276instructions: buildRealtimeInstructions(realtimeConfig.instructions),
273-tools: [REALTIME_VOICE_AGENT_CONSULT_TOOL],
277+tools: [REALTIME_VOICE_AGENT_CONSULT_TOOL, REALTIME_VOICE_AGENT_CONTROL_TOOL],
274278model: launchOptions.model,
279+sessionKey: normalizeOptionalString(params.sessionKey),
275280voice: launchOptions.voice,
276281forceAgentConsultOnFinalTranscript:
277282realtimeConfig.consultRouting === "force-agent-consult",
@@ -682,6 +687,80 @@ export const talkSessionHandlers: GatewayRequestHandlers = {
682687respond(false, undefined, errorShape(ErrorCodes.UNAVAILABLE, formatForLog(err)));
683688}
684689},
690+"talk.session.steer": async ({ params, respond, client }) => {
691+if (!validateTalkSessionSteerParams(params)) {
692+respond(
693+false,
694+undefined,
695+errorShape(
696+ErrorCodes.INVALID_REQUEST,
697+`invalid talk.session.steer params: ${formatValidationErrors(validateTalkSessionSteerParams.errors)}`,
698+),
699+);
700+return;
701+}
702+try {
703+const session = getUnifiedTalkSession(params.sessionId);
704+if (session.kind === "realtime-relay") {
705+const connId = requireUnifiedTalkSessionConn(session, client?.connId);
706+const result = await steerTalkRealtimeRelayAgentRun({
707+relaySessionId: session.relaySessionId,
708+ connId,
709+sessionKey: normalizeOptionalString(params.sessionKey),
710+text: params.text,
711+mode: normalizeOptionalString(params.mode),
712+});
713+respond(true, result, undefined);
714+return;
715+}
716+if (session.kind === "transcription-relay") {
717+respond(
718+false,
719+undefined,
720+errorShape(
721+ErrorCodes.INVALID_REQUEST,
722+"talk.session.steer requires an agent-backed Talk session",
723+),
724+);
725+return;
726+}
727+if (!isActiveManagedRoomClient(session, client?.connId)) {
728+respond(false, undefined, managedRoomOwnershipError("steer"));
729+return;
730+}
731+const handoff = getTalkHandoff(session.handoffId);
732+const sessionKey = handoff?.sessionKey;
733+if (!sessionKey) {
734+respond(
735+false,
736+undefined,
737+errorShape(ErrorCodes.INVALID_REQUEST, "talk.session.steer requires a session key"),
738+);
739+return;
740+}
741+const requestedSessionKey = normalizeOptionalString(params.sessionKey);
742+if (requestedSessionKey && requestedSessionKey !== sessionKey) {
743+respond(
744+false,
745+undefined,
746+errorShape(
747+ErrorCodes.INVALID_REQUEST,
748+"talk.session.steer sessionKey does not match the managed-room session",
749+),
750+);
751+return;
752+}
753+const result = await controlRealtimeVoiceAgentRun({
754+ sessionKey,
755+text: params.text,
756+mode: params.mode,
757+recentEvents: handoff?.room.talk.recentEvents,
758+});
759+respond(true, result, undefined);
760+} catch (err) {
761+respond(false, undefined, errorShape(ErrorCodes.UNAVAILABLE, formatForLog(err)));
762+}
763+},
685764"talk.session.close": async ({ params, respond, client, context }) => {
686765if (!validateTalkSessionCloseParams(params)) {
687766respond(
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。