fix: compose named cockpit modes from capabilities

This commit is contained in:
vee
2026-09-07 20:52:19 +08:00
parent cf9b89508c
commit 6b2b644ee6
23 changed files with 2917 additions and 124 deletions
+56 -7
View File
@@ -8310,20 +8310,69 @@ window.CognitiveAgentConsole = {
? draft.trim()
: String(draft?.instruction || "").trim();
if (!instruction) throw new Error("功能模式草稿缺少可试运行的指令。");
const { payload } = await requestNaturalLanguageControl(instruction, {
executionMode: "dry_run",
clientType: "assistant_mode_trial",
provider: "local",
previewOnly: false,
});
let payload;
if (draft && typeof draft === "object" && draft.source_request_id) {
const response = await apiRequest("/api/mode-profile-drafts/trial", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
name: draft.name,
instruction,
source_request_id: draft.source_request_id,
vehicle_id: draft.vehicle_id || state.vehicleId || null,
}),
timeoutMs: 30 * 1000,
retries: 0,
});
payload = await response.json();
if (response.status === 401) {
window.location.replace("/login");
return null;
}
if (!response.ok) {
throw new Error(payload.message || payload.error || `HTTP ${response.status}`);
}
} else {
({ payload } = await requestNaturalLanguageControl(instruction, {
executionMode: "dry_run",
clientType: "assistant_mode_trial",
provider: "local",
previewOnly: false,
}));
}
if (!payload) throw new Error("模拟试运行没有返回结果。");
const actualOperationCount = Object.values(payload.function_configs || {})
.reduce((total, config) => total + (config?.spec?.operations?.length || 0), 0);
const expectedOperationCount = Number(
typeof draft === "object" ? draft?.operation_count : 0,
);
const actionSignature = (action) => {
const target = action?.target && typeof action.target === "object"
? action.target.instance || action.target.zone || action.target.device || ""
: action?.target || "";
const parameters = action?.parameters && typeof action.parameters === "object"
? Object.fromEntries(Object.entries(action.parameters).sort(([left], [right]) => left.localeCompare(right)))
: {};
return JSON.stringify([
String(action?.domain || ""),
String(action?.capability || ""),
String(target),
parameters,
]);
};
const expectedSignatures = Array.isArray(draft?.actions)
? draft.actions.map(actionSignature).sort()
: [];
const actualActions = Array.isArray(payload?.intent_ir?.spec?.actions)
? payload.intent_ir.spec.actions
: [];
const actualSignatures = actualActions.map(actionSignature).sort();
const sameActions = expectedSignatures.length === 0
|| (expectedSignatures.length === actualSignatures.length
&& expectedSignatures.every((signature, index) => signature === actualSignatures[index]));
if (payload.status !== "succeeded"
|| (expectedOperationCount > 0 && actualOperationCount < expectedOperationCount)) {
|| (expectedOperationCount > 0 && actualOperationCount < expectedOperationCount)
|| !sameActions) {
throw new Error("试运行未完整覆盖草稿动作,请重新生成模式预览。");
}
return payload;