fix: reduce supervisor stalls and preserve task delivery
Load Supervisor graphs only when opened, preserve source details on demand, reuse indexed story digests and window selection lists without losing keyboard or focus behavior. Route heavy UI reads through the existing worker, batch scoped queries and construct each publication snapshot once. Keep remote cancellation responsive during model-route cleanup, remove late routes and retain reported usage after response-cap cancellation. Preserve Telegram pending replies through polling conflicts, show delivery errors and honor the final rate-limit cooldown. Schema 62 adds lookup indexes without rewriting user content; older clients cannot open upgraded data. Large review publication still blocks Main and remains documented follow-up work. Record the future storage-service direction without performing the architecture migration. Validation: exact staged code passed isolated full tests (6212 passed, 87 skipped), typecheck and lint. Three-round source performance comparisons, SQLite migration equivalence, native Electron interaction checks and current-source Linux x64 Host validation completed; eight external text-model requests. Release note: Supervisor opens reviews without loading the entire graph, keeps long selection lists responsive and preserves details and keyboard navigation. Remote cancellation and Telegram reply recovery are more reliable; remote fixes require an Agent build containing this change.
This commit is contained in:
@@ -138,6 +138,8 @@ Token 使用现有加密凭据存储,保存后不在普通设置快照中返
|
||||
|
||||
已生成并保存的结果沿用现有发件箱有限重试,发送失败与任务执行失败分别记录。补发回复不重新调用模型或重跑任务。用户阻止 Bot 等不可恢复错误应停止无效重试。
|
||||
|
||||
已有 webhook 或另一实例占用轮询时,已确认 Bot 身份且目标匹配的待发回复仍可发送;接收冲突本身不能永久终止这些回复。发送内部重试达到上限后,发件箱的下一次尝试仍须遵守最近一次 429 响应的等待时间,停用可取消等待。
|
||||
|
||||
同一驱动实例内且分段进度仍在缓存时,多段回复从未发送部分继续。进度不跨重启持久化,重启或缓存淘汰后补发可能重复已发送段落;网络中断造成平台接收结果不明时也可能重复。首版不承诺平台级发送幂等。
|
||||
|
||||
### FR-10 启停与历史保留
|
||||
@@ -162,6 +164,8 @@ Telegram 待接收更新最多保留 24 小时,超过平台保留期的离线
|
||||
|
||||
状态和错误推送只更新状态区域,不覆盖尚未保存的 Token 或白名单草稿。解决轮询冲突后可重新保存当前配置以启动连接;单独测试连接成功不改变接收状态。
|
||||
|
||||
接收正常而结果发送失败时,保留已连接状态并显示脱敏的发送错误。后续健康轮询不清除发送提示,投递成功后清除;接收也发生错误时优先展示接收原因,恢复后保留尚未清除的发送提示。
|
||||
|
||||
状态通过文字表达,不能只靠颜色。错误保留可操作原因,如 Token 无效、网络不可达、webhook 占用或另一实例正在轮询。测试成功、发送失败和模型失败使用各自准确文案,避免统一显示“连接失败”。
|
||||
|
||||
界面沿用 [UI-DESIGN.md](../../../UI-DESIGN.md) 的控件、通知、键盘和可访问性规则,不新增独立视觉体系。
|
||||
|
||||
@@ -55,6 +55,32 @@ npm test -- tests/telegram-channel.electron.test.ts
|
||||
|
||||
补充检查:钉钉错误码断言加入后,单独复跑 9 项通过;修改的 TS 文件 ESLint、Renderer typecheck 和 `git diff --check` 通过。早期全仓检查受到并行修改中的类型与 lint 错误阻塞,负责方修正后最终检查均通过;完整测试为 6,136 项通过、0 失败、87 跳过。汇总见[阶段修复验收](../../review/stage-audit-fixes-2026-10-05.md#最终检查)。
|
||||
|
||||
## 2026-10-05 K09 投递修复
|
||||
|
||||
本轮只修改 Telegram 驱动、Manager 及其测试,复用现有服务重试、SQLite 发件箱和状态 IPC。未改数据库结构、Main IPC、Runtime 或 Agent;本地与远程任务完成后的通道结果均使用同一发送路径,无需独立 Agent 修复。
|
||||
|
||||
修复前先运行持久回归:`telegram-delivery.test.ts` 的 3 项 loopback HTTP/SQLite 用例和 Manager 的状态用例共 4 项失败。启动 webhook 冲突时,同 Bot 的待发回复未发出且变为终止记录;403 后状态仍为 `running` 且无错误;连续 429 的最后响应要求等待 3 秒,下一次发送却只间隔约 1.010 秒。扩展的 Electron 设置 fixture 也在“已连接时显示发送失败”断言处失败。
|
||||
|
||||
修复后,启动阶段保留 `getMe` 确认的身份,已有 webhook 时发送同 Bot 的待发回复,其他 Bot 的记录仍被拒绝,轮询状态仍报告冲突。发送错误经脱敏后由现有状态区域显示,健康轮询不清除;发送成功清除投递提示但不覆盖轮询错误。驱动在内部重试耗尽后仍完成最后一次 `retry_after` 等待,再返回发件箱;新增取消用例验证等待可中断、记录保持 `pending / attempts=0`,重新启用后只补发一次且不运行 executor。
|
||||
|
||||
| 检查 | 最终结果 |
|
||||
| --- | --- |
|
||||
| 9 个通道/Renderer 聚焦文件 | 127 项通过,包含 4 项 loopback HTTP/SQLite 回归 |
|
||||
| 现有 Electron 设置 fixture | 1 项通过;生产设置 UI、Preload、IPC、Manager、驱动与 SQLite,403 提示、已连接状态、Token/白名单草稿、重载恢复均通过 |
|
||||
| 修改的 6 个 TS 文件 ESLint | 通过 |
|
||||
| `npm run typecheck` | Main、Agent 通过;Renderer 被并行工作区的 `App.tsx:174` 未使用 `refreshArtifacts` 导入阻塞,未修改该文件 |
|
||||
|
||||
最终聚焦命令:
|
||||
|
||||
```powershell
|
||||
npm exec -- vitest run src/main/channels/telegram-delivery.test.ts src/main/channels/telegram-channel-driver.test.ts src/main/channels/channel-manager.test.ts src/main/channels/channel-service.test.ts src/main/channels/channel-settings-store.test.ts src/main/channels/sqlite-channel-state.test.ts src/renderer/src/ChannelSettingsSection.test.tsx src/renderer/src/channel-status-store.test.ts src/main/channels/dingtalk-channel-driver.test.ts
|
||||
npm exec -- vitest run tests/telegram-channel.electron.test.ts
|
||||
npm exec -- eslint src/main/channels/telegram-channel-driver.ts src/main/channels/channel-manager.ts src/main/channels/telegram-delivery.test.ts src/main/channels/telegram-channel-driver.test.ts src/main/channels/channel-manager.test.ts tests/support/telegram-main.ts
|
||||
npm run typecheck
|
||||
```
|
||||
|
||||
Electron 最终运行使用 2 次本地 HTTP 模型响应;连同修复前失败运行和中间验证,本轮共 6 次本地 fixture 请求、0 次外部 Provider 请求、0 次真实 Telegram 收件人消息。未读取 `.env`,未运行生产构建。完整测试、全仓 lint 及合并后的类型检查由协调方执行;本节不声明全仓验收通过或性能提升。
|
||||
|
||||
## Main 性能对比
|
||||
|
||||
基线为 `78afec77758f3c175f8e2b80e5be4327e13b4689` 的临时 detached worktree,当前为包含 Telegram 改动的工作区。按基线、当前交替执行 `npm run perf:main` 各 3 次。环境为 Windows x64、Intel Core Ultra X7 358H、Electron 44.5.1、Node 24.21.0;每轮使用隔离数据库,包含 1000 个会话、20008 条生成消息、24000 条活动记录,每个场景预热后测量 15 次,无外部模型调用。
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
设置页经生产 Preload 和 IPC 调用 `ChannelManager`,由 `ChannelSettingsStore` 保存配置。Manager 按需加载 `TelegramChannelDriver`,向其注入 Electron `net.fetch`;驱动默认网络实现也使用 `net.fetch`。请求走 Electron 网络栈及系统代理,不依赖 Node 的 `HTTPS_PROXY` 配置,不使用 grammY 或 Telegraf。
|
||||
|
||||
驱动先调用 `getMe` 与 `getWebhookInfo`,拒绝已有 webhook,不删除外部配置。测试连接只做这两项检查,不启动轮询。启用后使用 `getUpdates`,`timeout=30`、`limit=100`、`allowed_updates=['message']`;普通请求超时 15 秒,轮询请求超时 40 秒。临时错误以 1~30 秒退避重连,429 按 `retry_after` 等待;其他 4xx 停止轮询并报告错误。
|
||||
驱动先调用 `getMe` 与 `getWebhookInfo`,已有 webhook 时拒绝启动轮询,不删除外部配置。`getMe` 验证的 Bot 身份独立保留;启动 webhook 冲突与运行中的轮询冲突均不阻止身份匹配的已保存回复发送,也不因此终止其发件箱记录。测试连接只做这两项检查,不启动轮询或改写运行中的身份。启用后使用 `getUpdates`,`timeout=30`、`limit=100`、`allowed_updates=['message']`;普通请求超时 15 秒,轮询请求超时 40 秒。临时错误以 1~30 秒退避重连,429 按 `retry_after` 等待;其他 4xx 停止轮询并报告错误。
|
||||
|
||||
## 身份、执行与保存
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
生成图片后,executor 先把 `artifactIds` 写入桌面会话,再向 `ChannelService` 返回通道契约中的状态、正文、错误和附件。图片字节保留在附件中;桌面成果 ID 不进入严格校验的通道结果,避免成功任务被误报为“无效结果”。该转换位于本地和远程 Runtime 事件处理之后,不改变 Runtime 或 Agent 协议。
|
||||
|
||||
驱动按最多 4096 个 UTF-16 码元拆分纯文本,并避开代理对中间位置;不设置 `parse_mode` 或引用原消息。分段进度只在驱动内存保存,最多 128 条,停止时清空。单次发送的 429 最多等待重试 3 次,仍失败则交回发件箱处理。跨重启补发与不确定网络结果允许产生重复段落。
|
||||
驱动按最多 4096 个 UTF-16 码元拆分纯文本,并避开代理对中间位置;不设置 `parse_mode` 或引用原消息。分段进度只在驱动内存保存,最多 128 条,停止时清空。单次发送遇到 429 最多额外尝试 3 次;最后一次仍被限流时,先等待该响应的 `retry_after`,再将失败交回发件箱,避免服务层提前重发。等待沿用调用方与服务生命周期的取消信号;停止期间不增加失败计数。跨重启补发与不确定网络结果允许产生重复段落。
|
||||
|
||||
停用会中止轮询、发送等待、活动执行与排队工作,等待活动操作结束后报告停止。清除凭据时设置页同时提交 `enabled=false`;底层拒绝启用但无 Token 的配置。Token 替换先验证,失败不停止旧服务。项目与历史不因停用或清除凭据删除。
|
||||
|
||||
@@ -37,6 +37,8 @@
|
||||
|
||||
Manager 通过 `{ channel, status }` 增量 IPC 推送状态,忽略旧服务实例的迟到事件。Telegram 连接状态由驱动维护,发送成功不会覆盖轮询错误。状态值为 `disabled`、`starting`、`running`、`stopped`、`error`;重连使用 `starting` 加错误说明,未配置由界面结合凭据状态显示。
|
||||
|
||||
Manager 在当前服务实例内保留最近一次发送错误,经既有脱敏函数处理后,附在连接状态的错误说明中。轮询正常时仍显示已连接,同时提示 `Telegram sending failed: ...`;健康轮询不会清除该提示。若同时有轮询错误,优先显示轮询原因;恢复接收后仍可看到未清除的发送错误。后续投递成功清除发送提示,停用或替换服务释放该实例的错误状态,无新增持久化记录或 IPC 字段。
|
||||
|
||||
Renderer 的 `channel-status-store.ts` 订阅事件,selector 只向状态区域提供对应通道数据。首次快照不会覆盖已收到的较新事件;状态更新不重新加载整份设置,不重置 Token 或白名单草稿。配置页复用共享页签、开关、项目设置字段和通知控件。
|
||||
|
||||
首次配置说明、空白名单提示和发送者 ID 字段帮助均明确:ID 可先留空,先启用并保存通道,连接后私聊自己的 Bot 发送 `/whoami`,取得本人数字用户 ID 后填入并再次保存。仅测试连接不启动消息接收;用户名和 Bot ID 不能代替发送者 ID。白名单为空时仍只提供帮助,不接受 AI 请求。
|
||||
|
||||
Reference in New Issue
Block a user