- Fix HandTaskPanel to use hand.id when loading runs and triggering - Fix HandsPanel to use hand.id for getHandDetails and triggerHand - Fix WorkflowEditor to use hand.id as option value The API expects hand identifiers, not names. This ensures correct hand execution and run history loading. Also clean up old plan files and add Gateway stability plan. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
5.5 KiB
5.5 KiB
ZCLAW Gateway 连接稳定性与 API 修复计划
Context
问题背景: 用户报告"Gateway 连接不稳定",通过 Chrome DevTools 诊断发现:
- WebSocket 连接和聊天功能实际正常工作
- 真正的问题是 6 个 API 端点返回 404,大量错误日志被误认为是连接问题
诊断结果:
| 项目 | 状态 |
|---|---|
| WebSocket 连接 | ✅ 正常 |
| 消息发送/流式响应 | ✅ 正常 |
| 核心 API (agents, hands, workflows) | ✅ 正常 |
| 6 个 API 端点 | ❌ 404 错误 |
目标:
- P0: 修复 6 个 404 API 端点(通过前端 fallback 降级)
- P1: 增强连接稳定性(心跳机制 + 改进重连策略)
Phase 1: P0 - API Fallback 降级处理
1.1 创建 API Fallback 模块
新建文件: desktop/src/lib/api-fallbacks.ts
// 提供 6 个 404 API 的降级数据
export interface QuickConfigFallback { ... }
export interface WorkspaceInfoFallback { ... }
export interface UsageStatsFallback { ... }
export interface PluginStatusFallback { ... }
export interface ScheduledTaskFallback { ... }
export function getQuickConfigFallback(): QuickConfigFallback { ... }
export function getWorkspaceInfoFallback(): WorkspaceInfoFallback { ... }
export function getUsageStatsFallback(sessions: Session[]): UsageStatsFallback { ... }
export function getPluginStatusFallback(skills: SkillInfo[]): PluginStatusFallback { ... }
export function getScheduledTasksFallback(triggers: Trigger[]): ScheduledTaskFallback[] { ... }
1.2 更新 gateway-client.ts
为每个 404 API 添加结构化 fallback:
async getQuickConfig(): Promise<any> {
try {
return await this.restGet('/api/config/quick');
} catch (error) {
if ((error as any).status === 404) {
return { quickConfig: getQuickConfigFallback() };
}
throw error;
}
}
1.3 更新 gatewayStore.ts
在数据加载时使用 fallback:
loadUsageStats: async () => {
try {
const stats = await get().client.getUsageStats();
set({ usageStats: stats });
} catch {
const fallback = getUsageStatsFallback(get().sessions);
set({ usageStats: fallback });
}
},
Phase 2: P1 - 心跳机制
2.1 添加心跳字段
修改文件: desktop/src/lib/gateway-client.ts
// 新增私有字段
private heartbeatInterval: number | null = null;
private heartbeatTimeout: number | null = null;
private missedHeartbeats: number = 0;
private static readonly HEARTBEAT_INTERVAL = 30000; // 30秒
private static readonly HEARTBEAT_TIMEOUT = 10000; // 10秒
private static readonly MAX_MISSED_HEARTBEATS = 3;
2.2 心跳方法
private startHeartbeat(): void { ... }
private stopHeartbeat(): void { ... }
private sendHeartbeat(): void { ... }
private handlePong(): void { ... }
2.3 集成到连接流程
connect()成功后调用startHeartbeat()cleanup()时调用stopHeartbeat()handleFrame()处理pong响应
Phase 3: P1 - 改进重连策略
3.1 新增配置选项
interface GatewayClientOptions {
maxReconnectAttempts?: number; // -1=无限, 0=禁用, 默认10
reconnectBackoff?: 'linear' | 'exponential' | 'fixed';
}
3.2 更新 scheduleReconnect
- 支持无限重连模式 (
maxReconnectAttempts: -1) - 添加重连事件通知 (
reconnecting,reconnect_failed) - 改进退避算法
3.3 流式 WebSocket 重连
为 openfangWs 添加重连逻辑:
private streamState = { agentId: null, sessionId: null, lastMessage: null };
private scheduleStreamReconnect(runId: string): void { ... }
Phase 4: UI 集成
4.1 创建 ConnectionStatus 组件
新建文件: desktop/src/components/ConnectionStatus.tsx
export function ConnectionStatus() {
const { connectionState } = useGatewayStore();
const statusConfig = {
disconnected: { color: 'red', label: '已断开', icon: WifiOff },
connecting: { color: 'yellow', label: '连接中...', icon: Loader2 },
connected: { color: 'green', label: '已连接', icon: Wifi },
reconnecting: { color: 'orange', label: '重连中...', icon: RefreshCw },
};
// ...
}
4.2 集成到 ChatArea
在聊天区域顶部显示连接状态指示器。
关键文件
| 文件 | 修改类型 | 说明 |
|---|---|---|
desktop/src/lib/api-fallbacks.ts |
新建 | API 降级数据 |
desktop/src/lib/gateway-client.ts |
修改 | 心跳 + 重连 + fallback |
desktop/src/store/gatewayStore.ts |
修改 | 使用 fallback |
desktop/src/components/ConnectionStatus.tsx |
新建 | 连接状态 UI |
desktop/src/components/ChatArea.tsx |
修改 | 集成状态指示器 |
tests/desktop/gatewayStore.test.ts |
修改 | 测试覆盖 |
Verification
测试清单
P0 - API Fallback:
- 启动应用,检查控制台无 404 错误
- 用量统计面板显示数据(即使 API 404)
- 设置页面显示配置(即使 API 404)
P1 - 心跳:
- 连接后空闲 5 分钟,连接保持
- 检查 WebSocket 流量有 ping/pong 帧
P1 - 重连:
- 关闭 OpenFang,显示"重连中"
- 重启 OpenFang,自动重连成功
- 聊天中断开后自动恢复
运行测试
pnpm vitest run tests/desktop/gatewayStore.test.ts
Implementation Sequence
- Day 1: Phase 1 - API Fallbacks
- Day 2: Phase 2 - Heartbeat + Phase 3 - Reconnection
- Day 3: Phase 4 - UI Integration + Testing