Add second batch master agent fast paths
This commit is contained in:
@@ -43,6 +43,8 @@ import {
|
||||
createHermesBackend,
|
||||
getHermesBackendSelectionState,
|
||||
} from "@/lib/execution/backends/hermes-backend";
|
||||
import { getClawBackendAvailability } from "@/lib/execution/backends/claw-config";
|
||||
import { getHermesBackendAvailability } from "@/lib/execution/backends/hermes-config";
|
||||
import { getOmxTeamBackendSelectionState } from "@/lib/execution/backends/omx-team-backend";
|
||||
import type { OrchestrationBackendId } from "@/lib/execution/orchestration-backend";
|
||||
import { listExecutionBackendChoices, selectExecutionBackend } from "@/lib/execution/backend-selector";
|
||||
@@ -1723,6 +1725,21 @@ type MasterAgentFastIntentContext = {
|
||||
effectiveDeepTaskPolicy: ReturnType<typeof resolveMasterAgentModelPolicy>;
|
||||
};
|
||||
|
||||
function buildMasterAgentRuntimeBackendLabel(context: MasterAgentFastIntentContext) {
|
||||
return context.agentControls?.backendOverride?.trim() || "master-codex-node";
|
||||
}
|
||||
|
||||
function getMasterAgentRuntimeDevice(context: MasterAgentFastIntentContext) {
|
||||
const deviceId =
|
||||
context.runtime.account.nodeId?.trim() ||
|
||||
context.state.user.boundDeviceId?.trim() ||
|
||||
"";
|
||||
if (!deviceId) {
|
||||
return null;
|
||||
}
|
||||
return context.state.devices.find((device) => device.id === deviceId) ?? null;
|
||||
}
|
||||
|
||||
function detectMasterAgentModelCommandScope(requestText: string): MasterAgentModelCommandScope {
|
||||
const normalized = normalizeLexicalText(requestText);
|
||||
if (
|
||||
@@ -1791,11 +1808,76 @@ function isBackendStatusRequest(requestText: string) {
|
||||
if (!normalized || isModelSwitchRequest(requestText)) {
|
||||
return false;
|
||||
}
|
||||
return /(什么后端|哪个后端|当前后端|现在后端|正在用什么后端|当前用什么后端|gui还是cli|hermes还是claw|claw还是hermes)/i.test(
|
||||
return /(什么后端|哪个后端|当前后端|现在后端|正在用什么后端|当前用什么后端|hermes还是claw|claw还是hermes)/i.test(
|
||||
normalized,
|
||||
);
|
||||
}
|
||||
|
||||
function isBackendSwitchRequest(requestText: string) {
|
||||
const normalized = normalizeLexicalText(requestText);
|
||||
if (!normalized) {
|
||||
return false;
|
||||
}
|
||||
return /(后端|runtime)/i.test(normalized) && /(切到|切换到|换成|改成|改为|用|使用)/i.test(normalized);
|
||||
}
|
||||
|
||||
function detectRequestedBackend(requestText: string) {
|
||||
const normalized = normalizeLexicalText(requestText);
|
||||
if (normalized.includes("hermes")) {
|
||||
return HERMES_BACKEND_ID;
|
||||
}
|
||||
if (normalized.includes("claw")) {
|
||||
return CLAW_BACKEND_ID;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
function isTakeoverStatusRequest(requestText: string) {
|
||||
const normalized = normalizeLexicalText(requestText);
|
||||
if (!normalized) {
|
||||
return false;
|
||||
}
|
||||
return /(接管|协同接管)/i.test(normalized) && /(有没有开启|是否开启|开了吗|状态|现在开着吗|当前开着吗)/i.test(normalized);
|
||||
}
|
||||
|
||||
function isTakeoverSwitchRequest(requestText: string) {
|
||||
const normalized = normalizeLexicalText(requestText);
|
||||
if (!normalized) {
|
||||
return false;
|
||||
}
|
||||
if (/(有没有开启|是否开启|开了吗|状态|现在开着吗|当前开着吗)/i.test(normalized)) {
|
||||
return false;
|
||||
}
|
||||
return /(接管|协同接管)/i.test(normalized) && /(开启|打开|关闭|关掉|停用|禁用)/i.test(normalized);
|
||||
}
|
||||
|
||||
function detectRequestedTakeoverEnabled(requestText: string) {
|
||||
const normalized = normalizeLexicalText(requestText);
|
||||
if (/(关闭|关掉|停用|禁用)/i.test(normalized)) {
|
||||
return false;
|
||||
}
|
||||
if (/(开启|打开)/i.test(normalized)) {
|
||||
return true;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function isExecutionModeStatusRequest(requestText: string) {
|
||||
const normalized = normalizeLexicalText(requestText);
|
||||
if (!normalized) {
|
||||
return false;
|
||||
}
|
||||
return /(gui\s*还是\s*cli|默认走.*gui.*cli|默认执行模式|执行模式|gui\s*cli)/i.test(normalized);
|
||||
}
|
||||
|
||||
function isBoundDeviceStatusRequest(requestText: string) {
|
||||
const normalized = normalizeLexicalText(requestText);
|
||||
if (!normalized) {
|
||||
return false;
|
||||
}
|
||||
return /(绑定设备|主节点|master节点|codex节点)/i.test(normalized) && /(在线吗|在不在线|是否在线|状态)/i.test(normalized);
|
||||
}
|
||||
|
||||
async function buildMasterAgentFastIntentContext(
|
||||
requestedByAccount: string,
|
||||
): Promise<MasterAgentFastIntentContext | null> {
|
||||
@@ -1934,6 +2016,140 @@ async function tryHandleMasterAgentBackendStatusQuery(params: {
|
||||
);
|
||||
}
|
||||
|
||||
async function tryHandleMasterAgentBackendSwitchCommand(params: {
|
||||
requestText: string;
|
||||
requestedByAccount: string;
|
||||
context: MasterAgentFastIntentContext;
|
||||
}) {
|
||||
if (!isBackendSwitchRequest(params.requestText)) {
|
||||
return null;
|
||||
}
|
||||
const requestedBackend = detectRequestedBackend(params.requestText);
|
||||
if (!requestedBackend) {
|
||||
return appendFastPathError(
|
||||
"我收到的是后端切换请求,但没有识别到具体后端。你可以直接说“切到 Hermes 后端”或“切到 Claw 后端”。",
|
||||
"BACKEND_NAME_REQUIRED",
|
||||
buildMasterAgentModelSenderLabel(params.context.effectiveChatPolicy.model),
|
||||
);
|
||||
}
|
||||
|
||||
if (requestedBackend === HERMES_BACKEND_ID) {
|
||||
const availability = await getHermesBackendAvailability();
|
||||
if (!availability.selectable) {
|
||||
return appendFastPathError(
|
||||
`Hermes Runtime 当前不可切换:${availability.reasonLabel}`,
|
||||
"BACKEND_NOT_AVAILABLE",
|
||||
buildMasterAgentModelSenderLabel(params.context.effectiveChatPolicy.model),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (requestedBackend === CLAW_BACKEND_ID) {
|
||||
const availability = await getClawBackendAvailability();
|
||||
if (!availability.selectable) {
|
||||
return appendFastPathError(
|
||||
`Claw Runtime 当前不可切换:${availability.reasonLabel}`,
|
||||
"BACKEND_NOT_AVAILABLE",
|
||||
buildMasterAgentModelSenderLabel(params.context.effectiveChatPolicy.model),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
await updateProjectAgentControls(
|
||||
"master-agent",
|
||||
{ backendOverride: requestedBackend },
|
||||
params.requestedByAccount,
|
||||
);
|
||||
return appendFastPathReply(
|
||||
`已把默认后端切到 ${requestedBackend}。`,
|
||||
buildMasterAgentModelSenderLabel(params.context.effectiveChatPolicy.model),
|
||||
);
|
||||
}
|
||||
|
||||
async function tryHandleMasterAgentTakeoverCommand(params: {
|
||||
requestText: string;
|
||||
requestedByAccount: string;
|
||||
context: MasterAgentFastIntentContext;
|
||||
}) {
|
||||
const isStatus = isTakeoverStatusRequest(params.requestText);
|
||||
const isSwitch = isTakeoverSwitchRequest(params.requestText);
|
||||
if (!isStatus && !isSwitch) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const currentEnabled = Boolean(params.context.agentControls?.globalTakeoverEnabled);
|
||||
if (isStatus && !isSwitch) {
|
||||
return appendFastPathReply(
|
||||
`全局接管:${currentEnabled ? "开启" : "关闭"}。`,
|
||||
buildMasterAgentModelSenderLabel(params.context.effectiveChatPolicy.model),
|
||||
);
|
||||
}
|
||||
|
||||
const nextEnabled = detectRequestedTakeoverEnabled(params.requestText);
|
||||
if (nextEnabled === null) {
|
||||
return appendFastPathError(
|
||||
"我收到的是接管切换请求,但没有识别到要开启还是关闭。你可以直接说“开启全局接管”或“关闭全局接管”。",
|
||||
"TAKEOVER_ACTION_REQUIRED",
|
||||
buildMasterAgentModelSenderLabel(params.context.effectiveChatPolicy.model),
|
||||
);
|
||||
}
|
||||
|
||||
await updateProjectAgentControls(
|
||||
"master-agent",
|
||||
{ globalTakeoverEnabled: nextEnabled },
|
||||
params.requestedByAccount,
|
||||
);
|
||||
return appendFastPathReply(
|
||||
nextEnabled ? "已开启全局接管。" : "已关闭全局接管。",
|
||||
buildMasterAgentModelSenderLabel(params.context.effectiveChatPolicy.model),
|
||||
);
|
||||
}
|
||||
|
||||
async function tryHandleMasterAgentExecutionModeStatusQuery(params: {
|
||||
requestText: string;
|
||||
context: MasterAgentFastIntentContext;
|
||||
}) {
|
||||
if (!isExecutionModeStatusRequest(params.requestText)) {
|
||||
return null;
|
||||
}
|
||||
const device = getMasterAgentRuntimeDevice(params.context);
|
||||
if (!device) {
|
||||
return appendFastPathReply(
|
||||
"当前没有绑定可识别的主节点设备,所以还不能判断默认执行模式。",
|
||||
buildMasterAgentModelSenderLabel(params.context.effectiveChatPolicy.model),
|
||||
);
|
||||
}
|
||||
const preferredMode = device.preferredExecutionMode || "unknown";
|
||||
const guiStatus = device.capabilities?.gui?.connected ? "在线" : "离线";
|
||||
const cliStatus = device.capabilities?.cli?.connected ? "在线" : "离线";
|
||||
return appendFastPathReply(
|
||||
`默认执行模式:${preferredMode}。设备:${device.name || device.id}。GUI:${guiStatus}。CLI:${cliStatus}。`,
|
||||
buildMasterAgentModelSenderLabel(params.context.effectiveChatPolicy.model),
|
||||
);
|
||||
}
|
||||
|
||||
async function tryHandleMasterAgentBoundDeviceStatusQuery(params: {
|
||||
requestText: string;
|
||||
context: MasterAgentFastIntentContext;
|
||||
}) {
|
||||
if (!isBoundDeviceStatusRequest(params.requestText)) {
|
||||
return null;
|
||||
}
|
||||
const device = getMasterAgentRuntimeDevice(params.context);
|
||||
if (!device) {
|
||||
return appendFastPathReply(
|
||||
"当前没有找到绑定的主节点设备记录。",
|
||||
buildMasterAgentModelSenderLabel(params.context.effectiveChatPolicy.model),
|
||||
);
|
||||
}
|
||||
const guiStatus = device.capabilities?.gui?.connected ? "在线" : "离线";
|
||||
const cliStatus = device.capabilities?.cli?.connected ? "在线" : "离线";
|
||||
return appendFastPathReply(
|
||||
`当前主节点设备:${device.name || device.id}。设备状态:${device.status}。GUI:${guiStatus}。CLI:${cliStatus}。`,
|
||||
buildMasterAgentModelSenderLabel(params.context.effectiveChatPolicy.model),
|
||||
);
|
||||
}
|
||||
|
||||
function isModelListRequest(requestText: string) {
|
||||
return /(哪些模型|什么模型|模型清单|可用模型|有哪些可用|available models?)/i.test(requestText);
|
||||
}
|
||||
@@ -2024,6 +2240,10 @@ async function tryHandleMasterAgentFastIntent(params: {
|
||||
return null;
|
||||
}
|
||||
const handlers = [
|
||||
() => tryHandleMasterAgentTakeoverCommand({ ...params, context }),
|
||||
() => tryHandleMasterAgentBackendSwitchCommand({ ...params, context }),
|
||||
() => tryHandleMasterAgentExecutionModeStatusQuery({ requestText: params.requestText, context }),
|
||||
() => tryHandleMasterAgentBoundDeviceStatusQuery({ requestText: params.requestText, context }),
|
||||
() => tryHandleMasterAgentModelCommand({ ...params, context }),
|
||||
() => tryHandleMasterAgentStatusQuery({ requestText: params.requestText, context }),
|
||||
() => tryHandleMasterAgentBackendStatusQuery({ requestText: params.requestText, context }),
|
||||
|
||||
Reference in New Issue
Block a user