feat: 对接设计 Agent Gateway WebSocket

需求:服务端统一 Agent Gateway 将设计任务状态流切换为 WebSocket,客户端需要实时展示生成任务并支持断线恢复。

实现:Electron Main 管理 Session、一次性 Ticket、WebSocket 心跳与游标续传,按关闭码回收会话;Renderer 继续通过本机 Host API 的 SSE 投影接收任务事件,并保留 REST 降级同步。

验证:typecheck、变更文件 ESLint、37 个聚焦测试及 build:vite 通过。
This commit is contained in:
2026-08-02 20:15:37 +08:00
parent 83e21563dc
commit 518d7ab4cd
17 changed files with 1816 additions and 50 deletions

View File

@@ -4,6 +4,7 @@
*/
import { app } from 'electron';
import { randomUUID } from 'node:crypto';
import { resolveSupportedLanguage } from '../../shared/language';
// Lazy-load electron-store (ESM module)
@@ -21,6 +22,7 @@ export interface AppSettings {
launchAtStartup: boolean;
telemetryEnabled: boolean;
machineId: string;
agentGatewaySessionClientIds: Record<string, string>;
hasReportedInstall: boolean;
proxyEnabled: boolean;
@@ -68,6 +70,7 @@ function createDefaultSettings(): AppSettings {
launchAtStartup: false,
telemetryEnabled: true,
machineId: '',
agentGatewaySessionClientIds: {},
hasReportedInstall: false,
proxyEnabled: false,
@@ -127,6 +130,39 @@ export async function setSetting<K extends keyof AppSettings>(
store.set(key, value);
}
let agentGatewaySessionIdMutation: Promise<void> = Promise.resolve();
async function mutateAgentGatewaySessionClientIds<T>(
mutation: (current: Record<string, string>) => Promise<T> | T,
): Promise<T> {
const result = agentGatewaySessionIdMutation.then(async () => {
const current = await getSetting('agentGatewaySessionClientIds');
return await mutation({ ...current });
});
agentGatewaySessionIdMutation = result.then(() => undefined, () => undefined);
return await result;
}
export function getOrCreateAgentGatewaySessionClientId(workspaceId: string): Promise<string> {
return mutateAgentGatewaySessionClientIds(async (current) => {
const existing = current[workspaceId]?.trim();
if (existing) return existing;
const created = `design-stream-${randomUUID()}`;
current[workspaceId] = created;
await setSetting('agentGatewaySessionClientIds', current);
return created;
});
}
export function rotateAgentGatewaySessionClientId(workspaceId: string): Promise<string> {
return mutateAgentGatewaySessionClientIds(async (current) => {
const created = `design-stream-${randomUUID()}`;
current[workspaceId] = created;
await setSetting('agentGatewaySessionClientIds', current);
return created;
});
}
/**
* Get all settings
*/