Merge origin/feature/N7Web into feature/N7Web
Integrate the remote firmware workbench, OTA delivery, and timed mode schedules while preserving the local N7 scene and runtime changes.
This commit is contained in:
+247
-21
@@ -5166,7 +5166,18 @@ function modeOperationParameters(operation) {
|
||||
return Object.entries(parameters);
|
||||
}
|
||||
|
||||
function formatModeOperationValue(name, value) {
|
||||
function formatModeOperationValue(name, value, capability = "") {
|
||||
if (name === "level" && ["seat.set_driver_ventilation_native", "seat.set_driver_heating_native"].includes(capability)) {
|
||||
return { 1: "高档", 2: "低档" }[value] || formatConfigValue(name, value);
|
||||
}
|
||||
if (capability === "seat.set_driver_massage_native") {
|
||||
const labels = {
|
||||
action: { mode: "切换按摩模式", strength: "调节按摩力度", off: "关闭" },
|
||||
mode: { wave: "波浪", pulse: "脉冲", stretch: "舒展", slack: "舒缓", relax: "放松" },
|
||||
strength: { 1: "轻柔", 2: "中等", 3: "较强" },
|
||||
};
|
||||
if (labels[name]?.[value]) return labels[name][value];
|
||||
}
|
||||
const valueLabels = {
|
||||
on: "开启",
|
||||
off: "关闭",
|
||||
@@ -5193,7 +5204,7 @@ function modeOperationView(operation) {
|
||||
const parameters = modeOperationParameters(operation)
|
||||
.map(([name, value]) => {
|
||||
const label = CONFIG_PARAMETER_LABELS[name] || name;
|
||||
return `${label}:${formatModeOperationValue(name, value)}`;
|
||||
return `${label}:${formatModeOperationValue(name, value, capability)}`;
|
||||
})
|
||||
.join(",");
|
||||
return {
|
||||
@@ -5232,7 +5243,50 @@ function modeTimelineStepView(step, action) {
|
||||
};
|
||||
}
|
||||
|
||||
function modeScheduleDurationLabel(durationMs) {
|
||||
const minutes = Math.floor(durationMs / 60000);
|
||||
const seconds = Number(((durationMs % 60000) / 1000).toFixed(3));
|
||||
return minutes ? `${minutes}分${seconds ? `${seconds}秒` : ""}` : `${seconds}秒`;
|
||||
}
|
||||
|
||||
function modeScheduleView(mode) {
|
||||
const schedule = mode?.schedule;
|
||||
if (
|
||||
schedule?.schema !== "cognitive-agent-mode-schedule/v1"
|
||||
|| !Array.isArray(schedule.phases) || !schedule.phases.length
|
||||
|| !Number.isInteger(schedule.repeat_count)
|
||||
|| schedule.repeat_count < 1 || schedule.repeat_count > 20
|
||||
|| schedule.phases.some((phase) => !Number.isFinite(phase?.duration_ms)
|
||||
|| phase.duration_ms <= 0 || !Array.isArray(phase.operations))
|
||||
) return null;
|
||||
let offsetMs = 0;
|
||||
const phases = schedule.phases.map((phase, index) => {
|
||||
const view = {
|
||||
name: String(phase.name || `阶段 ${index + 1}`),
|
||||
timing: `+${modeScheduleDurationLabel(offsetMs)} 开始 · 持续 ${modeScheduleDurationLabel(phase.duration_ms)}`,
|
||||
actions: phase.operations.map(modeOperationView),
|
||||
};
|
||||
offsetMs += phase.duration_ms;
|
||||
return view;
|
||||
});
|
||||
return {
|
||||
phases,
|
||||
summary: `${phases.length} 个阶段 · 重复 ${schedule.repeat_count} 次 · 总时长 ${modeScheduleDurationLabel(offsetMs * schedule.repeat_count)}`,
|
||||
stopHint: "执行后可输入“停止动态模式”提前结束,已执行状态不自动回滚;时间为每轮的相对时间。",
|
||||
};
|
||||
}
|
||||
|
||||
function modeExecutionActionViews(mode) {
|
||||
const schedule = modeScheduleView(mode);
|
||||
if (schedule) {
|
||||
// Runtime operations may contain a flattened projection. Prefer phases so
|
||||
// repeated device targets remain distinct and are not listed twice.
|
||||
return schedule.phases.flatMap((phase, index) => phase.actions.map((action) => ({
|
||||
...action,
|
||||
phase: `阶段 ${index + 1}:${phase.name}`,
|
||||
timing: phase.timing,
|
||||
})));
|
||||
}
|
||||
const operations = Array.isArray(mode?.operations)
|
||||
? mode.operations.map(modeOperationView)
|
||||
: [];
|
||||
@@ -5253,6 +5307,57 @@ function modeExecutionActionViews(mode) {
|
||||
return [...operations, ...timelineSteps];
|
||||
}
|
||||
|
||||
function modeScheduleTrialMatches(draft, payload) {
|
||||
if (!draft?.schedule) return true;
|
||||
if (!modeScheduleView(draft) || !modeScheduleView(payload)) return false;
|
||||
const signature = (schedule) => JSON.stringify([
|
||||
schedule.schema, schedule.repeat_count,
|
||||
schedule.phases.map((phase) => [
|
||||
phase.id, phase.name, phase.duration_ms,
|
||||
phase.operations.map((operation) => [
|
||||
operation.domain, operation.capability,
|
||||
operation.target_scope || operation.target?.instance || operation.target?.zone,
|
||||
modeOperationParameters(operation).sort(([left], [right]) => left.localeCompare(right)),
|
||||
]),
|
||||
]),
|
||||
]);
|
||||
const execution = payload.schedule_execution;
|
||||
const totalDurationMs = draft.schedule.phases.reduce((total, phase) => total + phase.duration_ms, 0)
|
||||
* draft.schedule.repeat_count;
|
||||
return signature(draft.schedule) === signature(payload.schedule)
|
||||
&& execution?.status === "completed" && execution.completed === true
|
||||
&& execution.virtual_elapsed_ms === totalDurationMs;
|
||||
}
|
||||
|
||||
function modeScheduleExecutionView(result) {
|
||||
const execution = result?.schedule_execution;
|
||||
if (!execution || typeof execution !== "object") return null;
|
||||
const status = String(execution.status || "");
|
||||
if (status === "running" && result.status === "running") {
|
||||
return {
|
||||
state: "processing", badge: "已启动", title: "动态时间轴已启动",
|
||||
detail: "后续动作将按阶段执行;可输入“停止动态模式”提前结束。已执行的设备状态不会自动回滚。",
|
||||
};
|
||||
}
|
||||
if (["stopped", "cancelled"].includes(status)) {
|
||||
return {
|
||||
state: "succeeded", badge: "已停止", title: "动态时间轴已停止",
|
||||
detail: "后续阶段不再执行;已经执行的设备状态不会自动回滚。",
|
||||
};
|
||||
}
|
||||
if (status === "completed" && execution.completed === true) {
|
||||
const simulated = execution.virtual_elapsed_ms != null;
|
||||
return {
|
||||
state: "succeeded", badge: simulated ? "模拟通过" : "已结束",
|
||||
title: simulated ? "动态时间轴模拟试运行通过" : "动态时间轴已结束",
|
||||
detail: simulated
|
||||
? "已使用虚拟时钟校验全部阶段;未按真实时间等待,也未向车辆下发控制。"
|
||||
: "已处理全部计划阶段,请以车辆反馈确认各设备的实际状态。",
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function isUserModeProfile(mode) {
|
||||
return mode?.origin === "user" || mode?.deletable === true;
|
||||
}
|
||||
@@ -5264,6 +5369,7 @@ function isN7SyncedModeProfile(mode) {
|
||||
function isDynamicModeProfile(mode) {
|
||||
const behavior = String(mode?.behavior || "").trim().toLowerCase();
|
||||
if (["cyclic", "dynamic"].includes(behavior)) return true;
|
||||
if (modeScheduleView(mode)) return true;
|
||||
if (behavior === "static") return false;
|
||||
if (mode?.timeline && typeof mode.timeline === "object") return true;
|
||||
return LEGACY_DYNAMIC_MODE_IDS.has(String(mode?.id || ""));
|
||||
@@ -5348,6 +5454,34 @@ function createModeGalleryCard(mode) {
|
||||
button.append(iconBox, copy);
|
||||
shell.append(button);
|
||||
|
||||
const schedule = modeScheduleView(mode);
|
||||
if (schedule) {
|
||||
meta.textContent = schedule.summary;
|
||||
const details = document.createElement("details");
|
||||
details.className = "mode-gallery-schedule-details";
|
||||
const summary = document.createElement("summary");
|
||||
summary.textContent = "查看分阶段执行动作";
|
||||
const list = document.createElement("ol");
|
||||
schedule.phases.forEach((phase) => {
|
||||
const item = document.createElement("li");
|
||||
const title = document.createElement("strong");
|
||||
title.textContent = phase.name;
|
||||
const timing = document.createElement("small");
|
||||
timing.textContent = phase.timing;
|
||||
item.append(title, timing);
|
||||
phase.actions.forEach((action) => {
|
||||
const row = document.createElement("p");
|
||||
row.textContent = `${action.target} · ${action.action}:${action.parameters}`;
|
||||
item.append(row);
|
||||
});
|
||||
list.append(item);
|
||||
});
|
||||
const hint = document.createElement("p");
|
||||
hint.textContent = schedule.stopHint;
|
||||
details.append(summary, list, hint);
|
||||
shell.append(details);
|
||||
}
|
||||
|
||||
const editButton = document.createElement("button");
|
||||
editButton.className = "mode-gallery-edit";
|
||||
editButton.type = "button";
|
||||
@@ -6313,25 +6447,37 @@ function installModeChipScroller() {
|
||||
pointerStartScroll = group.scrollLeft;
|
||||
dragged = false;
|
||||
pointerCaptured = false;
|
||||
suppressClick = false;
|
||||
});
|
||||
group.addEventListener("pointermove", (event) => {
|
||||
if (pointerId !== event.pointerId) return;
|
||||
if (event.buttons !== 1) {
|
||||
finishPointerDrag(event);
|
||||
return;
|
||||
}
|
||||
const distance = event.clientX - pointerStartX;
|
||||
if (!dragged && Math.abs(distance) < 5) return;
|
||||
dragged = true;
|
||||
if (!pointerCaptured && typeof group.setPointerCapture === "function") {
|
||||
group.setPointerCapture(pointerId);
|
||||
pointerCaptured = true;
|
||||
if (!dragged) {
|
||||
// Capturing on pointerdown retargets a normal button click to the rail.
|
||||
// Capture only after movement establishes that this gesture is a drag.
|
||||
dragged = true;
|
||||
if (typeof group.setPointerCapture === "function") {
|
||||
group.setPointerCapture(pointerId);
|
||||
pointerCaptured = true;
|
||||
}
|
||||
group.classList.add("is-dragging");
|
||||
}
|
||||
group.classList.add("is-dragging");
|
||||
group.scrollLeft = Math.max(0, Math.min(maximumScroll(), pointerStartScroll - distance));
|
||||
updateScrollState();
|
||||
event.preventDefault();
|
||||
});
|
||||
const finishPointerDrag = (event) => {
|
||||
if (pointerId !== event.pointerId) return;
|
||||
if (pointerCaptured) group.releasePointerCapture?.(pointerId);
|
||||
const finishedPointerId = pointerId;
|
||||
pointerId = null;
|
||||
if (pointerCaptured && group.hasPointerCapture?.(finishedPointerId)) {
|
||||
group.releasePointerCapture(finishedPointerId);
|
||||
}
|
||||
pointerCaptured = false;
|
||||
group.classList.remove("is-dragging");
|
||||
if (dragged) {
|
||||
@@ -6342,6 +6488,7 @@ function installModeChipScroller() {
|
||||
};
|
||||
group.addEventListener("pointerup", finishPointerDrag);
|
||||
group.addEventListener("pointercancel", finishPointerDrag);
|
||||
group.addEventListener("lostpointercapture", finishPointerDrag);
|
||||
group.addEventListener("click", (event) => {
|
||||
if (!suppressClick) return;
|
||||
event.preventDefault();
|
||||
@@ -6392,10 +6539,13 @@ function ensureModeActionPopover() {
|
||||
|
||||
function renderModeActionPopover(mode) {
|
||||
const popover = ensureModeActionPopover();
|
||||
const schedule = modeScheduleView(mode);
|
||||
const commandFlow = modeEditorReadableCommands(mode?.command_flow);
|
||||
const usesLatestCommandFlow = commandFlow.length > 0;
|
||||
const usesLatestCommandFlow = !schedule && commandFlow.length > 0;
|
||||
const actions = usesLatestCommandFlow ? commandFlow : modeExecutionActionViews(mode);
|
||||
$(`[data-mode-action-eyebrow]`, popover).textContent = usesLatestCommandFlow
|
||||
$(`[data-mode-action-eyebrow]`, popover).textContent = schedule
|
||||
? "动态时间轴"
|
||||
: usesLatestCommandFlow
|
||||
? "最新控制指令流"
|
||||
: "执行动作预览";
|
||||
$("[data-mode-action-title]", popover).textContent = mode?.name || mode?.id || "功能模式";
|
||||
@@ -6404,6 +6554,12 @@ function renderModeActionPopover(mode) {
|
||||
: `${Number(mode?.operation_count || 0)} 项`;
|
||||
const list = $("[data-mode-action-list]", popover);
|
||||
list.replaceChildren();
|
||||
if (schedule) {
|
||||
const summary = document.createElement("li");
|
||||
summary.className = "mode-schedule-popover-summary";
|
||||
summary.textContent = `${schedule.summary}。${schedule.stopHint}`;
|
||||
list.append(summary);
|
||||
}
|
||||
if (!actions.length) {
|
||||
const empty = document.createElement("li");
|
||||
empty.className = "mode-chip-action-empty";
|
||||
@@ -6422,6 +6578,12 @@ function renderModeActionPopover(mode) {
|
||||
actionName.textContent = usesLatestCommandFlow
|
||||
? String(action.category || "控制指令")
|
||||
: action.action;
|
||||
if (action.phase) {
|
||||
const phase = document.createElement("small");
|
||||
phase.className = "mode-schedule-popover-phase";
|
||||
phase.textContent = `${action.phase} · ${action.timing}`;
|
||||
copy.append(phase);
|
||||
}
|
||||
const metadata = document.createElement("small");
|
||||
const appendMetadata = (label, value) => {
|
||||
const text = String(value || "").trim();
|
||||
@@ -6703,8 +6865,17 @@ function populateModeChips() {
|
||||
runIcon.dataset.modeRun = "true";
|
||||
runIcon.title = `执行${mode.name || mode.id}`;
|
||||
const timeline = mode.timeline;
|
||||
const schedule = modeScheduleView(mode);
|
||||
let cycleBadge = $(".mode-cycle-badge", button);
|
||||
if (["infinite", "until_stopped_or_timeout"].includes(timeline?.repeat)) {
|
||||
if (schedule) {
|
||||
if (!cycleBadge) {
|
||||
cycleBadge = document.createElement("small");
|
||||
cycleBadge.className = "mode-cycle-badge";
|
||||
button.append(cycleBadge);
|
||||
}
|
||||
cycleBadge.textContent = schedule.summary;
|
||||
button.dataset.modeBehavior = "dynamic";
|
||||
} else if (["infinite", "until_stopped_or_timeout"].includes(timeline?.repeat)) {
|
||||
if (!cycleBadge) {
|
||||
cycleBadge = document.createElement("small");
|
||||
cycleBadge.className = "mode-cycle-badge";
|
||||
@@ -6736,7 +6907,7 @@ function populateModeChips() {
|
||||
: `${phase.name} 目标到位`;
|
||||
}).join(" → ")
|
||||
: "";
|
||||
button.title = [mode.description || mode.name, phaseSummary, "悬浮或聚焦查看全部执行动作"]
|
||||
button.title = [mode.description || mode.name, schedule?.summary || phaseSummary, "悬浮或聚焦查看全部执行动作"]
|
||||
.filter(Boolean)
|
||||
.join("\n");
|
||||
});
|
||||
@@ -6850,7 +7021,7 @@ function setModeExecutionState(modeProfileId, modeState = "idle") {
|
||||
$$(".mode-chips button[data-mode-profile-id], #modeGallery button[data-mode-profile-id]").forEach((button) => {
|
||||
const active = button.dataset.modeProfileId === modeProfileId && modeState !== "idle";
|
||||
button.classList.toggle("running", active && modeState === "running");
|
||||
button.classList.toggle("succeeded", active && modeState === "succeeded");
|
||||
button.classList.toggle("succeeded", active && ["succeeded", "started", "ended", "stopped"].includes(modeState));
|
||||
button.classList.toggle("failed", active && modeState === "failed");
|
||||
button.dataset.modeState = active ? modeState : "idle";
|
||||
button.setAttribute("aria-pressed", active ? "true" : "false");
|
||||
@@ -6859,6 +7030,12 @@ function setModeExecutionState(modeProfileId, modeState = "idle") {
|
||||
if (stateLabel) {
|
||||
stateLabel.textContent = active && modeState === "running"
|
||||
? "执行中"
|
||||
: active && modeState === "started"
|
||||
? "已启动"
|
||||
: active && modeState === "ended"
|
||||
? "已结束"
|
||||
: active && modeState === "stopped"
|
||||
? "已停止"
|
||||
: active && modeState === "succeeded"
|
||||
? "已完成"
|
||||
: active && modeState === "failed"
|
||||
@@ -6866,7 +7043,7 @@ function setModeExecutionState(modeProfileId, modeState = "idle") {
|
||||
: "点击执行";
|
||||
}
|
||||
});
|
||||
if (modeProfileId && ["succeeded", "failed"].includes(modeState)) {
|
||||
if (modeProfileId && ["succeeded", "failed", "started", "ended", "stopped"].includes(modeState)) {
|
||||
state.modeRunTimer = window.setTimeout(() => setModeExecutionState(null), 2800);
|
||||
}
|
||||
}
|
||||
@@ -6937,11 +7114,14 @@ async function executeSavedModeProfile(mode, { command = "" } = {}) {
|
||||
);
|
||||
if (!payload) throw new Error("模式卡片未返回执行结果");
|
||||
renderResult(payload);
|
||||
const scheduleRunning = modeScheduleExecutionView(payload)?.state === "processing";
|
||||
const completed = ["succeeded", "partially_succeeded"].includes(payload.status);
|
||||
$("#resultTitle").textContent = completed
|
||||
$("#resultTitle").textContent = scheduleRunning
|
||||
? `${mode.name}时间轴已启动`
|
||||
: completed
|
||||
? `${mode.name}执行完成`
|
||||
: `${mode.name}执行未完成`;
|
||||
setModeExecutionState(mode.id, completed ? "succeeded" : "failed");
|
||||
setModeExecutionState(mode.id, scheduleRunning ? "started" : completed ? "succeeded" : "failed");
|
||||
if (assistantModeHandle && assistant?.completeModeExecution) {
|
||||
assistant.completeModeExecution(assistantModeHandle, mode, payload, {
|
||||
command: modeCommand,
|
||||
@@ -6950,7 +7130,9 @@ async function executeSavedModeProfile(mode, { command = "" } = {}) {
|
||||
assistant?.announceModeExecution?.(mode, payload, { command: modeCommand });
|
||||
}
|
||||
if (state.executionMode === "hardware") await synchronizePhysicalSeatState();
|
||||
showToast(completed
|
||||
showToast(scheduleRunning
|
||||
? "时间轴已启动,可输入“停止动态模式”提前结束"
|
||||
: completed
|
||||
? `${mode.name}已直接执行保存的控制指令流`
|
||||
: `${mode.name}未完成,请查看执行结果`);
|
||||
} catch (error) {
|
||||
@@ -6985,10 +7167,17 @@ function applyModeCommand(command, modeProfileId = null) {
|
||||
showToast("AI助手正在处理上一条指令,请稍候");
|
||||
return false;
|
||||
}
|
||||
const speech = window.CognitiveAgentSpeech;
|
||||
if (["capturing", "finalizing"].includes(speech?.phase)
|
||||
|| (speech?.phase === "arming" && speech?.inputMode === "manual")) {
|
||||
showToast("请等待语音整理完成后再发送");
|
||||
return false;
|
||||
}
|
||||
if ($("#runButton")?.disabled) {
|
||||
showToast("上一条指令仍在执行,请稍候");
|
||||
return false;
|
||||
}
|
||||
hideModeActionPopover({ immediate: true });
|
||||
const mode = modeProfiles().find((item) => item.id === modeProfileId);
|
||||
setModeRailSelection(mode);
|
||||
closeModeGallery({ restoreFocus: false });
|
||||
@@ -8057,6 +8246,9 @@ const CONFIG_DOMAIN_META = {
|
||||
const CONFIG_CAPABILITY_LABELS = {
|
||||
"seat.set_ventilation": "设置座椅通风",
|
||||
"seat.set_heating": "设置座椅加热",
|
||||
"seat.set_driver_ventilation_native": "设置主驾座椅通风",
|
||||
"seat.set_driver_heating_native": "设置主驾座椅加热",
|
||||
"seat.set_driver_massage_native": "设置主驾座椅按摩",
|
||||
"seat.set_longitudinal": "调节座椅前后位置",
|
||||
"seat.set_longitudinal_position": "调节座椅前后位置",
|
||||
"seat.set_cushion_tilt": "调节座椅高度",
|
||||
@@ -8087,6 +8279,8 @@ const CONFIG_CAPABILITY_LABELS = {
|
||||
"ambient_light.set_illumination": "设置氛围灯颜色与亮度",
|
||||
"ambient_light.set_color": "设置氛围灯颜色",
|
||||
"ambient_light.set_brightness": "设置氛围灯亮度",
|
||||
"ambient_light.set_brightness_level": "设置氛围灯亮度",
|
||||
"ambient_light.set_color_index": "设置氛围灯色号",
|
||||
"ambient_light.set_mode": "设置氛围灯模式",
|
||||
"roof.set_transmittance": "设置天幕透光率",
|
||||
"roof.set_shade_position": "设置遮阳帘位置",
|
||||
@@ -8095,6 +8289,10 @@ const CONFIG_CAPABILITY_LABELS = {
|
||||
};
|
||||
|
||||
const CONFIG_PARAMETER_LABELS = {
|
||||
action: "动作",
|
||||
strength: "力度",
|
||||
color_index: "色号",
|
||||
brightness_level: "亮度档位",
|
||||
power: "电源",
|
||||
state: "状态",
|
||||
level: "档位",
|
||||
@@ -8381,6 +8579,24 @@ function renderExecution(result) {
|
||||
const summary = $("#executionSummary");
|
||||
const list = $("#resultList");
|
||||
list.replaceChildren();
|
||||
const scheduleExecution = modeScheduleExecutionView(result);
|
||||
if (scheduleExecution) {
|
||||
summary.className = `execution-summary ${scheduleExecution.state === "processing" ? "partial" : scheduleExecution.state}`;
|
||||
const icon = document.createElement("i");
|
||||
icon.dataset.lucide = scheduleExecution.state === "processing" ? "timer" : "circle-check";
|
||||
const copy = document.createElement("div");
|
||||
const title = document.createElement("strong");
|
||||
title.textContent = scheduleExecution.title;
|
||||
const detail = document.createElement("span");
|
||||
detail.textContent = scheduleExecution.detail;
|
||||
copy.append(title, detail);
|
||||
summary.replaceChildren(icon, copy);
|
||||
$("#resultNavMeta").textContent = scheduleExecution.badge;
|
||||
$("#resultPanelState").textContent = scheduleExecution.badge;
|
||||
$("#resultPanelState").className = `workspace-panel-state ${scheduleExecution.state}`;
|
||||
refreshIcons();
|
||||
return;
|
||||
}
|
||||
const report = result.execution_report;
|
||||
if (!report) {
|
||||
summary.className = "execution-summary failed";
|
||||
@@ -8656,6 +8872,7 @@ window.addEventListener("cognitive-agent:extension-vehicle-result", (event) => {
|
||||
|
||||
function renderResult(result) {
|
||||
state.result = result;
|
||||
const scheduleExecution = modeScheduleExecutionView(result);
|
||||
const reportMode = result.execution_report?.spec?.mode;
|
||||
const feedbackSource = result.execution_report?.metadata?.labels?.seat_feedback;
|
||||
const submittedUnverified = executionVerificationStatus(result) === "submitted_unverified";
|
||||
@@ -8690,7 +8907,9 @@ function renderResult(result) {
|
||||
};
|
||||
const peripheralRoute = String(result.orchestration_route || "")
|
||||
.startsWith("nfc_peripheral");
|
||||
$("#resultTitle").textContent = peripheralRoute && executionSucceeded
|
||||
$("#resultTitle").textContent = scheduleExecution
|
||||
? `${result.mode_profile?.name ? `${result.mode_profile.name} · ` : ""}${scheduleExecution.title}`
|
||||
: peripheralRoute && executionSucceeded
|
||||
? `${result.peripheral?.name || "第三方外设"} · ${result.peripheral?.action || "动作已执行"}`
|
||||
: partiallySucceeded
|
||||
? `${domains.length} 域场景部分完成`
|
||||
@@ -8714,7 +8933,7 @@ function renderResult(result) {
|
||||
$("#requestMeta").textContent += ` / reasoning:${result.reasoning_effort_used}`;
|
||||
}
|
||||
setRunStatus(
|
||||
partiallySucceeded || submittedUnverified ? "partial" : executionSucceeded ? "succeeded" : "failed",
|
||||
scheduleExecution?.state || (partiallySucceeded || submittedUnverified ? "partial" : executionSucceeded ? "succeeded" : "failed"),
|
||||
submittedUnverified ? "SUBMITTED_UNVERIFIED" : result.status.toUpperCase(),
|
||||
);
|
||||
renderDecision(result);
|
||||
@@ -9293,12 +9512,17 @@ window.CognitiveAgentConsole = {
|
||||
&& expectedSignatures.every((signature, index) => signature === actualSignatures[index]));
|
||||
if (payload.status !== "succeeded"
|
||||
|| (expectedOperationCount > 0 && actualOperationCount < expectedOperationCount)
|
||||
|| !sameActions) {
|
||||
|| !sameActions || !modeScheduleTrialMatches(draft, payload)) {
|
||||
throw new Error("试运行未完整覆盖草稿动作,请重新生成模式预览。");
|
||||
}
|
||||
return payload;
|
||||
},
|
||||
revealModeProfile,
|
||||
updateScheduleExecutionStatus(modeProfileId, status) {
|
||||
if (!modeProfileId || (state.pendingModeProfileId && state.pendingModeProfileId !== modeProfileId)) return;
|
||||
const terminal = { completed: "ended", failed: "failed", cancelled: "stopped", stopped: "stopped", idle: "idle" }[status];
|
||||
if (terminal) setModeExecutionState(modeProfileId, terminal);
|
||||
},
|
||||
notify(message) {
|
||||
showToast(String(message));
|
||||
},
|
||||
@@ -9321,9 +9545,11 @@ window.addEventListener("cognitive-agent:request-complete", (event) => {
|
||||
if (!modeProfileId) return;
|
||||
state.pendingModeProfileId = null;
|
||||
const result = event.detail?.result;
|
||||
const scheduleRunning = !event.detail?.error
|
||||
&& modeScheduleExecutionView(result)?.state === "processing";
|
||||
const succeeded = !event.detail?.error
|
||||
&& ["succeeded", "partially_succeeded"].includes(String(result?.status || ""));
|
||||
setModeExecutionState(modeProfileId, succeeded ? "succeeded" : "failed");
|
||||
setModeExecutionState(modeProfileId, scheduleRunning ? "started" : succeeded ? "succeeded" : "failed");
|
||||
});
|
||||
|
||||
document.addEventListener("visibilitychange", () => {
|
||||
|
||||
Reference in New Issue
Block a user