feat: integrate production cockpit AI assistant

This commit is contained in:
vee
2026-09-08 17:46:07 +08:00
parent 5e228e12ae
commit 93103c2579
66 changed files with 11046 additions and 374 deletions
+151 -6
View File
@@ -169,6 +169,7 @@ function createHarness(events) {
const storage = new Map();
const requestCalls = [];
const completed = [];
const refreshedModeProfiles = [];
windowEvents.addEventListener("cognitive-agent:request-complete", (event) => {
completed.push(event.detail);
});
@@ -207,7 +208,12 @@ function createHarness(events) {
sandbox.addEventListener = windowEvents.addEventListener.bind(windowEvents);
sandbox.removeEventListener = windowEvents.removeEventListener.bind(windowEvents);
sandbox.dispatchEvent = windowEvents.dispatchEvent.bind(windowEvents);
sandbox.CognitiveAgentConsole = { getExecutionMode: () => "dry_run" };
sandbox.CognitiveAgentConsole = {
getExecutionMode: () => "dry_run",
async refreshModeProfiles(modeProfileId) {
refreshedModeProfiles.push(modeProfileId);
},
};
sandbox.CognitiveAgentNetwork = {
async request(url, options) {
requestCalls.push({ url, options });
@@ -225,15 +231,22 @@ function createHarness(events) {
};
vm.createContext(sandbox);
vm.runInContext(ASSISTANT_SOURCE, sandbox, { filename: "assistant-chat.js" });
return { completed, input, messages, requestCalls, sandbox };
return {
completed,
input,
messages,
refreshedModeProfiles,
requestCalls,
sandbox,
};
}
test("a late NDJSON model error is rendered after an HTTP 200 stream", async () => {
const publicMessage = "Codex AI 助手暂时没有响应,请稍后再试。";
const publicMessage = "小迪暂时没有响应,请稍后再试。";
const harness = createHarness([
{ type: "message.accepted", route: "agent", engine: "codex-app-server" },
{ type: "work.started", display_text: "Codex 正在理解并处理……" },
{ type: "work.progress", display_text: "Codex 正在重新连接……" },
{ type: "work.started", display_text: "小迪正在理解并处理……" },
{ type: "work.progress", display_text: "小迪正在重新连接……" },
{ type: "error", error: "assistant_model_failed", message: publicMessage },
]);
harness.input.value = "解释一下 CAN FD";
@@ -261,7 +274,7 @@ test("a completed NDJSON answer remains the authoritative visible response", asy
const harness = createHarness([
{ type: "message.accepted", route: "agent", engine: "codex-app-server" },
{ type: "answer.delta", delta: "流式草稿" },
{ type: "work.completed", success: true, display_text: "Codex 已完成" },
{ type: "work.completed", success: true, display_text: "小迪已完成" },
{ type: "answer.completed", route: "agent", answer: "最终回答" },
]);
harness.input.value = "普通问题";
@@ -274,6 +287,138 @@ test("a completed NDJSON answer remains the authoritative visible response", asy
assert.equal(harness.completed[0].error, null);
});
test("unsupported-control suggestions render once and click through as a new command", async () => {
const suggestions = [
{ id: "climate-on", label: "打开空调", command: "打开空调", domain: "climate" },
{ id: "shade-close", label: "关闭遮阳帘", command: "关闭遮阳帘", domain: "roof" },
{ id: "climate-copy", label: "重复项", command: " 打开 空调 ", domain: "climate" },
];
const events = [
{
type: "control.suggestions",
message_id: "msg-unsupported",
suggestions,
},
{
type: "answer.completed",
route: "unsupported_control",
engine: "n7web-capability-registry",
answer: "当前车端暂不支持该功能控制哦,您可以尝试以下操作。",
suggestions,
},
];
const harness = createHarness(events);
harness.input.value = "打开后备箱";
await harness.sandbox.CognitiveAgentAssistant.submit();
const suggestionGroups = harness.messages.querySelectorAll(".assistant-control-suggestions");
assert.equal(suggestionGroups.length, 1);
const buttons = suggestionGroups[0].querySelectorAll("button");
assert.equal(buttons.length, 2);
assert.equal(buttons[0].type, "button");
assert.equal(buttons[0].dataset.suggestionCommand, "打开空调");
assert.equal(buttons[0].attributes.get("aria-label"), "执行控制指令:打开空调");
assert.equal(buttons[0].attributes.get("aria-busy"), "false");
buttons[0].dispatchEvent({ type: "click" });
buttons[0].dispatchEvent({ type: "click" });
assert.equal(buttons.every((button) => button.disabled), true);
await new Promise((resolve) => setTimeout(resolve, 0));
await new Promise((resolve) => setTimeout(resolve, 0));
const streamCalls = harness.requestCalls.filter(
(call) => call.url === "/api/assistant/stream",
);
assert.equal(streamCalls.length, 2);
assert.equal(JSON.parse(streamCalls[1].options.body).message, "打开空调");
assert.equal(harness.messages.children[2].dataset.messageContent, "打开空调");
assert.equal(buttons.every((button) => !button.disabled), true);
assert.equal(buttons[0].attributes.get("aria-busy"), "false");
});
test("answer fallback accepts recommended_commands and caps unsafe suggestion payloads", async () => {
const harness = createHarness([
{
type: "answer.completed",
route: "unsupported_control",
answer: "当前车端暂不支持该功能控制哦。",
recommended_commands: [
"打开空调",
{ id: "seat", label: "调节座椅", command: "副驾座椅调到80%", domain: "seat" },
{ id: "empty", label: "空指令", command: "" },
{ id: "window", label: "关闭车窗", command: "关闭所有车窗", domain: "window" },
{ id: "light", label: "打开氛围灯", command: "打开氛围灯", domain: "lighting" },
{ id: "extra", label: "不应显示", command: "空调调到25度", domain: "climate" },
],
},
]);
harness.input.value = "打开后备箱";
await harness.sandbox.CognitiveAgentAssistant.submit();
const group = harness.messages.querySelector(".assistant-control-suggestions");
assert.ok(group);
const buttons = group.querySelectorAll("button");
assert.equal(buttons.length, 4);
assert.deepEqual(
buttons.map((button) => button.dataset.suggestionCommand),
["打开空调", "副驾座椅调到80%", "关闭所有车窗", "打开氛围灯"],
);
buttons.forEach((button) => {
assert.equal(button.type, "button");
assert.match(button.attributes.get("aria-label"), /^执行控制指令:/);
});
});
test("a natural-language saved-mode update refreshes the mode gallery", async () => {
const harness = createHarness([
{ type: "message.accepted", route: "mode_profile_management", engine: "n7web-mode-registry" },
{
type: "action.completed",
success: true,
payload: {
status: "succeeded",
execution_mode: "dry_run",
orchestration_route: "mode_profile_update",
mode_profile: { id: "mode-reading", name: "阅读模式" },
},
},
{ type: "answer.completed", route: "mode_profile_management", answer: "已更新阅读模式。" },
]);
harness.input.value = "把阅读模式中空调温度调整到26度";
await harness.sandbox.CognitiveAgentAssistant.submit();
assert.deepEqual(harness.refreshedModeProfiles, ["mode-reading"]);
const state = harness.messages.querySelectorAll(".assistant-mode-created");
assert.equal(state.length, 1);
assert.equal(state[0].children[1].children[0].textContent, "已更新「我的模式」");
});
test("a natural-language saved-mode deletion refreshes the mode gallery", async () => {
const harness = createHarness([
{ type: "message.accepted", route: "mode_profile_management", engine: "n7web-mode-registry" },
{
type: "action.completed",
success: true,
payload: {
status: "succeeded",
execution_mode: "dry_run",
orchestration_route: "mode_profile_delete",
deleted_mode_profile: { id: "mode-reading", name: "阅读模式" },
},
},
{ type: "answer.completed", route: "mode_profile_management", answer: "已删除阅读模式。" },
]);
harness.input.value = "删除阅读模式";
await harness.sandbox.CognitiveAgentAssistant.submit();
assert.deepEqual(harness.refreshedModeProfiles, [undefined]);
assert.equal(harness.messages.querySelectorAll(".assistant-mode-created").length, 0);
});
function modeDraftEvents(sourceRequestId, temperatureC) {
return [
{ type: "message.accepted", route: "vehicle_control", engine: "n7web-mode-builder" },