@aiscene/aiserver 1.2.6 → 1.2.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -95,6 +95,7 @@ export interface ExecuteResult {
95
95
  errorMessage?: string;
96
96
  result?: unknown;
97
97
  dump?: string;
98
+ executionDump?: unknown;
98
99
  reportHTML?: string;
99
100
  }
100
101
  export type DebugSessionStatus = 'idle' | 'running' | 'completed' | 'failed' | 'stopped';
@@ -115,6 +116,8 @@ export interface DebugSession {
115
116
  screencastEnabled?: boolean;
116
117
  dumpIntervalId?: NodeJS.Timeout;
117
118
  process?: unknown;
119
+ executor?: unknown;
120
+ abortController?: AbortController;
118
121
  }
119
122
  export type EventType = 'task:started' | 'task:completed' | 'task:failed' | 'task:log' | 'device:online' | 'device:offline' | 'device:heartbeat' | 'node:registered' | 'node:command' | 'debug:session_created' | 'debug:log_output' | 'debug:action_dump' | 'debug:execution_line' | 'debug:action_result' | 'debug:completed' | 'debug:error' | 'executor:dump';
120
123
  export interface EventPayload {
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"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"}
@@ -11,6 +11,7 @@ export interface DebugRequest {
11
11
  isRnUrl?: boolean;
12
12
  needLogin?: boolean;
13
13
  modelName?: string;
14
+ modelConfig?: Record<string, unknown>;
14
15
  }
15
16
  export interface StopDebugRequest {
16
17
  type: 'stop_debug';
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/debug/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/debug/types.ts"],"names":[],"mappings":"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"}
@@ -48,6 +48,11 @@ export declare class DebugWebSocketServer {
48
48
  private handleCloseWebSession;
49
49
  private handleStopDebug;
50
50
  private handleGetLogs;
51
+ /**
52
+ * 将前端传来的 modelConfig 应用到环境变量
53
+ * ActionExecutor 通过环境变量读取模型配置,所以需要同步更新
54
+ */
55
+ private applyModelConfig;
51
56
  private sendMessage;
52
57
  private sendError;
53
58
  private cleanupSession;
@@ -1 +1 @@
1
- {"version":3,"file":"websocket-server.d.ts","sourceRoot":"","sources":["../../src/debug/websocket-server.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAgBrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAmB1D,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,GAAG,CAAgC;IAC3C,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,SAAS,CAAkB;IAGnC,OAAO,CAAC,kBAAkB,CAA0C;IAEpE,OAAO,CAAC,uBAAuB,CAA0C;gBAE7D,IAAI,GAAE,MAAa;IAIzB,KAAK,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAoDlD;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAmB5B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAexB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAcxB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAiB1B;;OAEG;IACH,OAAO,CAAC,0BAA0B;IAUlC,OAAO,CAAC,uBAAuB;YA0BjB,aAAa;IAyC3B,OAAO,CAAC,uBAAuB;IAS/B,OAAO,CAAC,yBAAyB;IAWjC,4CAA4C;IAC5C,OAAO,CAAC,YAAY;YAMN,gBAAgB;IA2B9B,6CAA6C;YAC/B,uBAAuB;IAmDrC,uCAAuC;YACzB,wBAAwB;YA+DxB,mBAAmB;YA0DnB,kBAAkB;YAwDlB,sBAAsB;YA+RtB,qBAAqB;YA4BrB,oBAAoB;YAuBpB,qBAAqB;YAoCrB,eAAe;YA6Bf,aAAa;IAU3B,OAAO,CAAC,WAAW;IAenB,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,cAAc;IAMtB,WAAW,IAAI,YAAY,EAAE;IAIvB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAW7B"}
1
+ {"version":3,"file":"websocket-server.d.ts","sourceRoot":"","sources":["../../src/debug/websocket-server.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAgBrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAmB1D,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,GAAG,CAAgC;IAC3C,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,SAAS,CAAkB;IAGnC,OAAO,CAAC,kBAAkB,CAA0C;IAEpE,OAAO,CAAC,uBAAuB,CAA0C;gBAE7D,IAAI,GAAE,MAAa;IAIzB,KAAK,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAqElD;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAmB5B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAexB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAcxB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAiB1B;;OAEG;IACH,OAAO,CAAC,0BAA0B;IAUlC,OAAO,CAAC,uBAAuB;YAiCjB,aAAa;IAyC3B,OAAO,CAAC,uBAAuB;IAS/B,OAAO,CAAC,yBAAyB;IAWjC,4CAA4C;IAC5C,OAAO,CAAC,YAAY;YAMN,gBAAgB;IA2B9B,6CAA6C;YAC/B,uBAAuB;IA6ErC,uCAAuC;YACzB,wBAAwB;YAkFxB,mBAAmB;YAgGnB,kBAAkB;YAgGlB,sBAAsB;YA+RtB,qBAAqB;YA4BrB,oBAAoB;YAuBpB,qBAAqB;YAoCrB,eAAe;YA8Ff,aAAa;IAU3B;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IAkBxB,OAAO,CAAC,WAAW;IAmCnB,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,cAAc;IAMtB,WAAW,IAAI,YAAY,EAAE;IAIvB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAW7B"}
@@ -47,6 +47,21 @@ export class DebugWebSocketServer {
47
47
  host: config.server.host,
48
48
  port: this.port,
49
49
  perMessageDeflate: false,
50
+ maxPayload: 10 * 1024 * 1024, // 10MB max message size
51
+ });
52
+ // 定期 ping 所有客户端,防止反向代理/负载均衡器因空闲超时断开 WebSocket
53
+ const heartbeatInterval = setInterval(() => {
54
+ this.wss?.clients.forEach((ws) => {
55
+ if (ws.isAlive === false) {
56
+ logger.warn('[WS] Client missed heartbeat, terminating connection');
57
+ return ws.terminate();
58
+ }
59
+ ws.isAlive = false;
60
+ ws.ping();
61
+ });
62
+ }, 30000);
63
+ this.wss.on('close', () => {
64
+ clearInterval(heartbeatInterval);
50
65
  });
51
66
  this.wss.on('connection', (ws, req) => {
52
67
  let parsedUrl;
@@ -164,13 +179,19 @@ export class DebugWebSocketServer {
164
179
  }
165
180
  handleControlConnection(ws) {
166
181
  logger.info('[Control] New connection');
182
+ // 心跳:收到 pong 标记为存活
183
+ ws.isAlive = true;
184
+ ws.on('pong', () => {
185
+ ws.isAlive = true;
186
+ });
167
187
  ws.on('message', async (data) => {
168
188
  try {
169
189
  const message = JSON.parse(data.toString());
170
190
  await this.handleMessage(ws, message);
171
191
  }
172
192
  catch (error) {
173
- this.sendError(ws, 'Invalid message format');
193
+ logger.error(`[Control] Message handling error: ${error.message}`);
194
+ this.sendError(ws, `Message handling error: ${error.message}`);
174
195
  }
175
196
  });
176
197
  ws.on('close', () => {
@@ -275,6 +296,12 @@ export class DebugWebSocketServer {
275
296
  }
276
297
  /** 代码模式:在主进程内使用 ActionExecutor 执行 runCode */
277
298
  async executeRunCodeInProcess(ws, sessionId, request) {
299
+ const session = sessionManager.get(sessionId);
300
+ const abortController = new AbortController();
301
+ if (session)
302
+ session.abortController = abortController;
303
+ // 将前端传来的 modelConfig 应用到环境变量
304
+ this.applyModelConfig(request.modelConfig);
278
305
  const executor = ExecutorFactory.create('action', {
279
306
  sessionId,
280
307
  onLog: (msg) => {
@@ -288,6 +315,9 @@ export class DebugWebSocketServer {
288
315
  this.sendMessage(ws, { type: 'execution_line', sessionId, line }, request.deviceId);
289
316
  },
290
317
  });
318
+ // 保存 executor 引用到 session,以便 stop_debug 时可以中断
319
+ if (session)
320
+ session.executor = executor;
291
321
  const config = {
292
322
  type: request.platform || 'android',
293
323
  testName: 'debug-runCode',
@@ -300,7 +330,23 @@ export class DebugWebSocketServer {
300
330
  modelConfig: undefined,
301
331
  executionId: sessionId,
302
332
  };
303
- const result = await executor.execute(config);
333
+ // 使用 AbortSignal 监听停止请求
334
+ const executePromise = executor.execute(config);
335
+ const abortPromise = new Promise((resolve) => {
336
+ abortController.signal.addEventListener('abort', () => {
337
+ resolve({ success: false, errorMessage: 'Action stopped by user' });
338
+ }, { once: true });
339
+ });
340
+ let result;
341
+ try {
342
+ result = await Promise.race([executePromise, abortPromise]);
343
+ }
344
+ catch (error) {
345
+ result = { success: false, errorMessage: error.message };
346
+ }
347
+ // 清理 executor 引用
348
+ if (session)
349
+ session.executor = undefined;
304
350
  sessionManager.updateStatus(sessionId, result.success ? 'completed' : 'failed');
305
351
  this.sendMessage(ws, {
306
352
  type: 'action_result',
@@ -308,7 +354,7 @@ export class DebugWebSocketServer {
308
354
  actionType: 'runCode',
309
355
  success: result.success,
310
356
  result: result.result,
311
- dump: result.dump || '',
357
+ dump: result.executionDump || result.dump || '',
312
358
  reportHTML: result.reportHTML || '',
313
359
  error: result.errorMessage,
314
360
  platform: request.platform || 'android',
@@ -322,6 +368,8 @@ export class DebugWebSocketServer {
322
368
  }
323
369
  /** 自然语言模式:Fork worker 进程执行 aiAction */
324
370
  async executeWithWorkerProcess(ws, sessionId, request) {
371
+ // 将前端传来的 modelConfig 应用到环境变量(fork 前应用,子进程继承)
372
+ this.applyModelConfig(request.modelConfig);
325
373
  const execConfig = {
326
374
  type: request.platform || 'android',
327
375
  testName: 'debugtest',
@@ -362,12 +410,27 @@ export class DebugWebSocketServer {
362
410
  sessionManager.addLog(sessionId, `ERROR: ${errorOutput}`);
363
411
  this.sendMessage(ws, { type: 'log_output', sessionId, content: `ERROR: ${errorOutput}`, level: 'error' }, request.deviceId);
364
412
  });
413
+ // 缓存 worker 返回的结果(包括 dump 数据)
414
+ let workerResult = {};
365
415
  childProcess.on('exit', (code) => {
366
416
  const success = code === 0;
367
417
  sessionManager.updateStatus(sessionId, success ? 'completed' : 'failed');
368
- this.sendMessage(ws, { type: 'debug_completed', sessionId, success, exitCode: code }, request.deviceId);
418
+ // 发送 debug_completed 消息时包含 dump 数据
419
+ this.sendMessage(ws, {
420
+ type: 'debug_completed',
421
+ sessionId,
422
+ success,
423
+ exitCode: code,
424
+ dump: workerResult.dump || '',
425
+ reportFile: workerResult.reportFile,
426
+ errorMessage: workerResult.errorMessage,
427
+ }, request.deviceId);
369
428
  });
370
429
  childProcess.on('message', (message) => {
430
+ // 缓存 worker 返回的结果,用于在 exit 时发送
431
+ if (typeof message === 'object' && message) {
432
+ workerResult = { ...workerResult, ...message };
433
+ }
371
434
  this.sendMessage(ws, { type: 'execution_result', sessionId, ...(typeof message === 'object' && message ? message : {}) }, request.deviceId);
372
435
  });
373
436
  childProcess.on('error', (error) => {
@@ -379,7 +442,12 @@ export class DebugWebSocketServer {
379
442
  async handleExecuteAction(ws, request) {
380
443
  const sessionId = `action-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
381
444
  const session = sessionManager.create(sessionId, ws, request.deviceId);
445
+ const abortController = new AbortController();
446
+ session.abortController = abortController;
447
+ // 将前端传来的 modelConfig 应用到环境变量
448
+ this.applyModelConfig(request.modelConfig);
382
449
  try {
450
+ sessionManager.updateStatus(sessionId, 'running');
383
451
  this.sendMessage(ws, { type: 'action_started', sessionId, actionType: request.actionType }, request.deviceId);
384
452
  const executor = ExecutorFactory.create('action', {
385
453
  sessionId,
@@ -394,6 +462,8 @@ export class DebugWebSocketServer {
394
462
  this.sendMessage(ws, { type: 'execution_line', sessionId, line }, request.deviceId);
395
463
  },
396
464
  });
465
+ // 保存 executor 引用到 session,以便 stop_debug 时可以中断
466
+ session.executor = executor;
397
467
  const config = {
398
468
  type: request.platform || 'android',
399
469
  testName: `action-${request.actionType}`,
@@ -406,33 +476,63 @@ export class DebugWebSocketServer {
406
476
  modelConfig: undefined,
407
477
  executionId: sessionId,
408
478
  };
409
- const result = await executor.execute(config);
410
- sessionManager.updateStatus(sessionId, result.success ? 'completed' : 'failed');
479
+ // 使用 AbortSignal 监听停止请求
480
+ const executePromise = executor.execute(config);
481
+ const abortPromise = new Promise((resolve) => {
482
+ abortController.signal.addEventListener('abort', () => {
483
+ resolve({ success: false, errorMessage: 'Action stopped by user' });
484
+ }, { once: true });
485
+ });
486
+ const result = await Promise.race([executePromise, abortPromise]);
487
+ // 清理 executor 引用
488
+ session.executor = undefined;
489
+ const status = result.success ? 'completed' : 'failed';
490
+ sessionManager.updateStatus(sessionId, status);
491
+ logger.info(`[Action] Execution finished: sessionId=${sessionId}, status=${status}, ws.readyState=${ws.readyState}`);
411
492
  this.sendMessage(ws, {
412
493
  type: 'action_result',
413
494
  sessionId,
414
495
  success: result.success,
415
496
  result: result.result,
416
- dump: result.dump || '',
497
+ dump: result.executionDump || result.dump || '',
417
498
  reportHTML: result.reportHTML || '',
418
499
  error: result.errorMessage,
419
500
  }, request.deviceId);
501
+ this.sendMessage(ws, {
502
+ type: 'debug_completed',
503
+ sessionId,
504
+ success: result.success,
505
+ }, request.deviceId);
506
+ logger.info(`[Action] Sent action_result + debug_completed for sessionId=${sessionId}`);
420
507
  }
421
508
  catch (error) {
509
+ session.executor = undefined;
422
510
  sessionManager.updateStatus(sessionId, 'failed');
511
+ logger.error(`[Action] Execution error: sessionId=${sessionId}, error=${error.message}, ws.readyState=${ws.readyState}`);
423
512
  this.sendMessage(ws, {
424
513
  type: 'action_result',
425
514
  sessionId,
426
515
  success: false,
427
516
  error: error.message,
428
517
  }, request.deviceId);
518
+ // 异常时也发送 debug_completed,确保前端能退出执行中状态
519
+ this.sendMessage(ws, {
520
+ type: 'debug_completed',
521
+ sessionId,
522
+ success: false,
523
+ }, request.deviceId);
429
524
  }
430
525
  }
431
526
  // ==================== Execute AI Act ====================
432
527
  async handleExecuteAiAct(ws, request) {
433
528
  const sessionId = `aiact-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
434
529
  const session = sessionManager.create(sessionId, ws, request.deviceId);
530
+ const abortController = new AbortController();
531
+ session.abortController = abortController;
532
+ // 将前端传来的 modelConfig 应用到环境变量
533
+ this.applyModelConfig(request.modelConfig);
435
534
  try {
535
+ sessionManager.updateStatus(sessionId, 'running');
436
536
  this.sendMessage(ws, { type: 'ai_act_started', sessionId }, request.deviceId);
437
537
  const executor = ExecutorFactory.create('action', {
438
538
  sessionId,
@@ -444,6 +544,8 @@ export class DebugWebSocketServer {
444
544
  this.sendMessage(ws, { type: 'action_dump', sessionId, dump }, request.deviceId);
445
545
  },
446
546
  });
547
+ // 保存 executor 引用到 session,以便 stop_debug 时可以中断
548
+ session.executor = executor;
447
549
  const config = {
448
550
  type: request.platform || 'android',
449
551
  testName: 'ai-act',
@@ -457,26 +559,52 @@ export class DebugWebSocketServer {
457
559
  deepThink: request.deepThink,
458
560
  },
459
561
  };
460
- const result = await executor.execute(config);
461
- sessionManager.updateStatus(sessionId, result.success ? 'completed' : 'failed');
562
+ // 使用 AbortSignal 监听停止请求
563
+ const executePromise = executor.execute(config);
564
+ const abortPromise = new Promise((resolve) => {
565
+ abortController.signal.addEventListener('abort', () => {
566
+ resolve({ success: false, errorMessage: 'Action stopped by user' });
567
+ }, { once: true });
568
+ });
569
+ const result = await Promise.race([executePromise, abortPromise]);
570
+ // 清理 executor 引用
571
+ session.executor = undefined;
572
+ const status = result.success ? 'completed' : 'failed';
573
+ sessionManager.updateStatus(sessionId, status);
574
+ logger.info(`[AiAct] Execution finished: sessionId=${sessionId}, status=${status}, ws.readyState=${ws.readyState}`);
462
575
  this.sendMessage(ws, {
463
576
  type: 'ai_act_result',
464
577
  sessionId,
465
578
  success: result.success,
466
579
  result: result.result,
467
- dump: result.dump || '',
580
+ dump: result.executionDump || result.dump || '',
468
581
  reportHTML: result.reportHTML || '',
469
582
  error: result.errorMessage,
470
583
  }, request.deviceId);
584
+ // 发送 debug_completed,让前端能正确识别执行完成状态
585
+ this.sendMessage(ws, {
586
+ type: 'debug_completed',
587
+ sessionId,
588
+ success: result.success,
589
+ }, request.deviceId);
590
+ logger.info(`[AiAct] Sent ai_act_result + debug_completed for sessionId=${sessionId}`);
471
591
  }
472
592
  catch (error) {
593
+ session.executor = undefined;
473
594
  sessionManager.updateStatus(sessionId, 'failed');
595
+ logger.error(`[AiAct] Execution error: sessionId=${sessionId}, error=${error.message}, ws.readyState=${ws.readyState}`);
474
596
  this.sendMessage(ws, {
475
597
  type: 'ai_act_result',
476
598
  sessionId,
477
599
  success: false,
478
600
  error: error.message,
479
601
  }, request.deviceId);
602
+ // 异常时也发送 debug_completed,确保前端能退出执行中状态
603
+ this.sendMessage(ws, {
604
+ type: 'debug_completed',
605
+ sessionId,
606
+ success: false,
607
+ }, request.deviceId);
480
608
  }
481
609
  }
482
610
  // ==================== Execute Web Action (Playwright + Midscene, with screencast) ====================
@@ -821,11 +949,49 @@ export class DebugWebSocketServer {
821
949
  // ==================== Stop Debug ====================
822
950
  async handleStopDebug(ws, request) {
823
951
  const session = sessionManager.get(request.sessionId);
824
- if (!session) {
825
- this.sendError(ws, `Session not found: ${request.sessionId}`);
952
+ // Session 不存在或已结束,直接返回 debug_stopped(而非报错)
953
+ // 前端可能在执行完成后才发 stop 请求,此时 session 已被清理或状态已变更
954
+ if (!session || (session.status !== 'running' && session.status !== 'idle')) {
955
+ this.sendMessage(ws, { type: 'debug_stopped', sessionId: request.sessionId });
826
956
  return;
827
957
  }
828
- // Stop child process
958
+ // 仿照 playground cancelTask:先获取当前执行数据,再 destroy agent
959
+ let dump = '';
960
+ let reportHTML = '';
961
+ const agent = session.executor?.getAgent?.() || session.agent;
962
+ // 获取 dump 数据(必须在 destroy 之前,因为 dump 存储在 agent 内存中)
963
+ try {
964
+ if (agent && typeof agent.dumpDataString === 'function') {
965
+ dump = agent.dumpDataString({ inlineScreenshots: true }) || '';
966
+ }
967
+ }
968
+ catch (error) {
969
+ logger.warn(`Failed to get dump before cancel: ${error.message}`);
970
+ }
971
+ // 获取 reportHTML
972
+ try {
973
+ if (agent && typeof agent.reportHTMLString === 'function') {
974
+ reportHTML = agent.reportHTMLString({ inlineScreenshots: true }) || '';
975
+ }
976
+ }
977
+ catch (error) {
978
+ logger.warn(`Failed to get reportHTML before cancel: ${error.message}`);
979
+ }
980
+ // 中断主进程内的执行(execute_action / execute_ai_act)
981
+ if (session.abortController && !session.abortController.signal.aborted) {
982
+ session.abortController.abort();
983
+ }
984
+ // 销毁 executor(释放 device/agent 资源)—— 仿照 playground 的 recreateAgent
985
+ if (session.executor && typeof session.executor.destroy === 'function') {
986
+ try {
987
+ await session.executor.destroy();
988
+ }
989
+ catch (error) {
990
+ logger.warn(`Executor destroy error: ${error.message}`);
991
+ }
992
+ }
993
+ session.executor = undefined;
994
+ // Stop child process (for start_debug with worker process)
829
995
  if (session.process) {
830
996
  session.process.kill('SIGTERM');
831
997
  }
@@ -841,7 +1007,28 @@ export class DebugWebSocketServer {
841
1007
  }
842
1008
  }
843
1009
  sessionManager.updateStatus(request.sessionId, 'stopped');
844
- this.sendMessage(ws, { type: 'debug_stopped', sessionId: request.sessionId });
1010
+ // 发送带执行数据的停止消息(仿照 playground cancel 返回 dump + reportHTML)
1011
+ this.sendMessage(ws, {
1012
+ type: 'debug_stopped',
1013
+ sessionId: request.sessionId,
1014
+ dump,
1015
+ reportHTML,
1016
+ });
1017
+ // 同时发送 action_result,让前端能获取到停止时的执行数据
1018
+ this.sendMessage(ws, {
1019
+ type: 'action_result',
1020
+ sessionId: request.sessionId,
1021
+ success: false,
1022
+ error: 'Action stopped by user',
1023
+ dump,
1024
+ reportHTML,
1025
+ });
1026
+ // 发送 debug_completed
1027
+ this.sendMessage(ws, {
1028
+ type: 'debug_completed',
1029
+ sessionId: request.sessionId,
1030
+ success: false,
1031
+ });
845
1032
  }
846
1033
  // ==================== Get Logs ====================
847
1034
  async handleGetLogs(ws, request) {
@@ -853,6 +1040,26 @@ export class DebugWebSocketServer {
853
1040
  this.sendMessage(ws, { type: 'all_logs', sessionId: request.sessionId, logs: session.logs });
854
1041
  }
855
1042
  // ==================== Utilities ====================
1043
+ /**
1044
+ * 将前端传来的 modelConfig 应用到环境变量
1045
+ * ActionExecutor 通过环境变量读取模型配置,所以需要同步更新
1046
+ */
1047
+ applyModelConfig(modelConfig) {
1048
+ if (!modelConfig || typeof modelConfig !== 'object')
1049
+ return;
1050
+ const envMapping = {
1051
+ MIDSCENE_MODEL_BASE_URL: 'MIDSCENE_MODEL_BASE_URL',
1052
+ MIDSCENE_MODEL_API_KEY: 'MIDSCENE_MODEL_API_KEY',
1053
+ MIDSCENE_MODEL_NAME: 'MIDSCENE_MODEL_NAME',
1054
+ MIDSCENE_MODEL_FAMILY: 'MIDSCENE_MODEL_FAMILY',
1055
+ };
1056
+ for (const [configKey, envKey] of Object.entries(envMapping)) {
1057
+ if (modelConfig[configKey] && typeof modelConfig[configKey] === 'string') {
1058
+ process.env[envKey] = modelConfig[configKey];
1059
+ logger.info(`[ModelConfig] Applied ${envKey} from request`);
1060
+ }
1061
+ }
1062
+ }
856
1063
  sendMessage(ws, message, deviceId) {
857
1064
  try {
858
1065
  const msg = {
@@ -861,11 +1068,31 @@ export class DebugWebSocketServer {
861
1068
  timestamp: new Date().toISOString(),
862
1069
  };
863
1070
  if (ws.readyState === ws.OPEN) {
864
- ws.send(JSON.stringify(msg));
1071
+ const payload = JSON.stringify(msg);
1072
+ // 大数据消息(如 reportHTML)截断,避免超出 WebSocket 帧大小限制
1073
+ const MAX_PAYLOAD_SIZE = 2 * 1024 * 1024; // 2MB
1074
+ if (payload.length > MAX_PAYLOAD_SIZE) {
1075
+ logger.warn(`[WS] Message too large (${(payload.length / 1024 / 1024).toFixed(2)}MB), type=${message.type}, truncating reportHTML/dump`);
1076
+ // 截断 reportHTML 和 dump 字段
1077
+ if (msg.reportHTML && typeof msg.reportHTML === 'string' && msg.reportHTML.length > 512 * 1024) {
1078
+ msg.reportHTML = msg.reportHTML.substring(0, 512 * 1024) + '\n...[truncated]';
1079
+ }
1080
+ if (msg.dump && typeof msg.dump === 'string' && msg.dump.length > 512 * 1024) {
1081
+ msg.dump = msg.dump.substring(0, 512 * 1024) + '\n...[truncated]';
1082
+ }
1083
+ }
1084
+ ws.send(payload, (err) => {
1085
+ if (err) {
1086
+ logger.error(`[WS] Send failed: type=${message.type}, error=${err.message}`);
1087
+ }
1088
+ });
1089
+ }
1090
+ else {
1091
+ logger.warn(`[WS] Cannot send message: ws not open (readyState=${ws.readyState}), type=${message.type}, sessionId=${message.sessionId}`);
865
1092
  }
866
1093
  }
867
1094
  catch (error) {
868
- logger.error(`Send message error: ${error.message}`);
1095
+ logger.error(`Send message error: ${error.message}, type=${message.type}`);
869
1096
  }
870
1097
  }
871
1098
  sendError(ws, error) {