[P0/严重] TaskOrchestrator SubEngine 共享主 Engine 的 adapter 导致 abort signal 互斥覆盖 #4

Closed
opened 2026-07-21 21:55:36 +08:00 by thzxx · 1 comment
Owner

问题类型

缺陷 / 严重 / Agent 引擎

文件位置

electron/harness/orchestration/orchestrator.ts

问题描述

TaskOrchestrator 委派子任务时,SubEngine 通过 mainEngine.getAdapter() 复用主 Engine 的 adapter 实例。
但 adapter 内部维护 currentAbortSignal,SubEngine 与主 Engine 都会调用 adapter.setAbortSignal()

  1. SubEngine 启动时覆盖主 Engine 的 signal
  2. SubEngine abort 后清除 signal,主 Engine 进行中的请求被意外中断
  3. 主 Engine abort 时会同时 abort SubEngine

影响

  • 委派任务与主流程互相干扰
  • 中断行为不可预测
  • 可能导致主会话永久卡死

建议修复

两种方案:

方案 A(推荐):为 SubEngine 创建独立的 adapter 实例(深拷贝配置)

const subAdapter = cloneAdapter(mainEngine.getAdapter());
const subEngine = new AgentLoopEngine(config, subAdapter, ...);

方案 B:adapter 改为 signal map(按 runId 索引),允许多个 signal 共存

方案 A 更简单且符合 isolation 原则。

## 问题类型 缺陷 / 严重 / Agent 引擎 ## 文件位置 `electron/harness/orchestration/orchestrator.ts` ## 问题描述 TaskOrchestrator 委派子任务时,SubEngine 通过 `mainEngine.getAdapter()` 复用主 Engine 的 adapter 实例。 但 adapter 内部维护 `currentAbortSignal`,SubEngine 与主 Engine 都会调用 `adapter.setAbortSignal()`: 1. SubEngine 启动时覆盖主 Engine 的 signal 2. SubEngine abort 后清除 signal,主 Engine 进行中的请求被意外中断 3. 主 Engine abort 时会同时 abort SubEngine ## 影响 - 委派任务与主流程互相干扰 - 中断行为不可预测 - 可能导致主会话永久卡死 ## 建议修复 两种方案: **方案 A(推荐)**:为 SubEngine 创建独立的 adapter 实例(深拷贝配置) ```ts const subAdapter = cloneAdapter(mainEngine.getAdapter()); const subEngine = new AgentLoopEngine(config, subAdapter, ...); ``` **方案 B**:adapter 改为 signal map(按 runId 索引),允许多个 signal 共存 方案 A 更简单且符合 isolation 原则。
thzxx added the Agent?????? labels 2026-07-21 21:55:36 +08:00
Author
Owner

修复说明

文件: electron/harness/agent-loop/engine.ts + electron/harness/orchestration/orchestrator.ts

问题: SubEngine 通过 mainEngine.getAdapter() 共享主 Engine 的 adapter 实例,SubEngine 调用 setAbortSignal() 会覆盖主 Engine 的 signal,SubEngine 完成后清除 signal,导致主 Engine 后续 fetch 无法被用户中断。

修复方案(选择风险最低的方案,而非 clone adapter):

  1. Engine 新增 restoreAbortSignal() 方法:将当前 abortController.signal 重新设置给 adapter
  2. Orchestrator 的 delegate() 方法在 finally 块中调用 mainEngine.restoreAbortSignal(),确保 SubEngine 完成后(无论正常/异常/abort)恢复主 Engine 的 abort signal

设计决策: 相比工单建议的"为 SubEngine 创建独立 adapter 实例"(需要给所有 adapter 实现 clone,改动大且风险高),此方案改动最小,且由于 SubEngine 是 await 的(主 Engine 不会同时发 fetch),恢复 signal 即可解决问题。

验证: tsc --noEmit 类型检查通过。

## 修复说明 **文件**: `electron/harness/agent-loop/engine.ts` + `electron/harness/orchestration/orchestrator.ts` **问题**: SubEngine 通过 `mainEngine.getAdapter()` 共享主 Engine 的 adapter 实例,SubEngine 调用 `setAbortSignal()` 会覆盖主 Engine 的 signal,SubEngine 完成后清除 signal,导致主 Engine 后续 fetch 无法被用户中断。 **修复方案**(选择风险最低的方案,而非 clone adapter): 1. Engine 新增 `restoreAbortSignal()` 方法:将当前 `abortController.signal` 重新设置给 adapter 2. Orchestrator 的 `delegate()` 方法在 `finally` 块中调用 `mainEngine.restoreAbortSignal()`,确保 SubEngine 完成后(无论正常/异常/abort)恢复主 Engine 的 abort signal **设计决策**: 相比工单建议的"为 SubEngine 创建独立 adapter 实例"(需要给所有 adapter 实现 clone,改动大且风险高),此方案改动最小,且由于 SubEngine 是 await 的(主 Engine 不会同时发 fetch),恢复 signal 即可解决问题。 **验证**: `tsc --noEmit` 类型检查通过。
thzxx closed this issue 2026-07-22 09:14:48 +08:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: MetonaTeam/metona-ai-desktop#4