Termexo v0.8.6:刷新与重连不再打断正在运行的 Agent

2026-09-11 19 预计阅读时间: 1 分钟
来源: oschina.net AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:9 分钟

Termexo v0.8.6 把重点放在了终端工作流最容易被忽略的一刻:页面刷新、重新连接,或者窗口尺寸发生变化之后,正在执行的任务还能不能接着工作。这个 MIT 开源的 Windows 多 Agent 工作台现在可以统一管理 Claude Code、Codex、OpenCode 和真实终端,并针对刷新后的 Agent 保留和终端画面恢复进行了改进。

对于长时间运行的编码任务来说,刷新浏览器不应该等价于重新启动进程。v0.8.6 的变化,正是把“前端视图重新加载”和“后端 Agent 生命周期”区分开来。

刷新不再误启动新的 Agent

过去,前端加载过程可能被当成一次新的终端启动。用户刷新页面时,应用没有先确认已有 Agent 是否仍然存在,就可能重新创建终端或重新启动任务。

这会带来几个直接问题:

  • 正在运行的 Agent 可能被重复启动。
  • 原有任务的上下文和输出连续性受到影响。
  • 用户很难判断当前看到的是旧进程,还是刷新后新建的进程。
  • 多 Agent 工作台中的状态会因为一次普通刷新而变得不可靠。

v0.8.6 的方向是让 Agent 进程独立于前端页面生命周期。页面刷新后,前端应当重新连接到已有进程,并通过进程标识、会话标识或其他持久状态判断该 Agent 是否已经运行,而不是把“没有本地 UI 状态”理解成“需要启动一个新 Agent”。

这是一条适用于终端型应用的通用原则:

UI 可以重建,任务进程不能因为 UI 重建而被隐式重启。

终端改用屏幕状态重放

本版还调整了终端恢复思路:重新连接或尺寸变化后,终端不再只依赖零散的输出文本,而是使用屏幕状态进行重放。

传统的输出回放通常类似于保存一段日志,再把日志重新写入终端。但终端并不是普通文本框。光标位置、清屏控制序列、颜色、换行和覆盖写入都会影响最终画面。同一段输出,如果在不同的终端尺寸或不同的光标状态下重放,结果可能并不一致。

屏幕状态重放更接近终端当前真正展示的内容:

  • 保存当前屏幕网格中的字符和样式。
  • 记录光标位置以及必要的终端属性。
  • 连接恢复后,先重建屏幕,再继续接收实时输出。
  • 尺寸变化后,根据新的终端尺寸重新计算显示状态。

这对交互式 Agent 尤其重要。Claude Code、Codex、OpenCode 或真实 shell 往往会更新同一行、刷新进度信息、切换界面区域。恢复时重建“屏幕长什么样”,比简单追加历史日志更符合用户实际看到的内容。

一个可落地的状态模型

下面是一个可以改造到终端前端或桌面工作台中的最小示例。它使用浏览器 sessionStorage 保存 UI 侧的 Agent 引用,并在加载时优先恢复现有会话。示例假设后端提供 GET /api/agents/{id}POST /api/agents 接口;真正的进程管理仍应由后端负责。

<script>
  const STORAGE_KEY = "termexo.active-agent";

  async function getExistingAgent(agentId) {
    const response = await fetch(`/api/agents/${encodeURIComponent(agentId)}`);
    if (response.status === 404) return null;
    if (!response.ok) throw new Error(`agent lookup failed: ${response.status}`);
    return response.json();
  }

  async function createAgent(kind) {
    const response = await fetch("/api/agents", {
      method: "POST",
      headers: { "content-type": "application/json" },
      body: JSON.stringify({ kind })
    });
    if (!response.ok) throw new Error(`agent creation failed: ${response.status}`);
    return response.json();
  }

  async function restoreOrCreateAgent(kind) {
    const savedId = sessionStorage.getItem(STORAGE_KEY);

    if (savedId) {
      const existing = await getExistingAgent(savedId);
      if (existing && ["running", "waiting", "idle"].includes(existing.status)) {
        return existing;
      }
    }

    const created = await createAgent(kind);
    sessionStorage.setItem(STORAGE_KEY, created.id);
    return created;
  }

  restoreOrCreateAgent("codex")
    .then(agent => console.log("connected to agent", agent.id, agent.status))
    .catch(error => console.error("agent restore failed", error));
</script>

这个示例的关键不在于 sessionStorage 本身,而在于启动条件:只有确认没有可复用的 Agent 时,前端才请求创建新进程。生产环境还应把 Agent 状态放在后端或桌面主进程维护,并处理多个窗口、应用重启、权限校验和僵尸进程清理。

终端画面可以采用类似的结构保存:

{
  "agentId": "agent-42",
  "cols": 120,
  "rows": 36,
  "cursor": { "x": 18, "y": 4, "visible": true },
  "screen": [
    { "text": "Working on src/main.ts", "style": "default" },
    { "text": "Tests: 12 passed", "style": "success" }
  ]
}

这里的 screen 只是便于理解的简化表示。实际实现通常需要按行、按单元格保存字符、前景色、背景色、粗体和其他终端属性,并由终端解析器根据控制序列更新屏幕缓冲区。

这次更新对日常使用意味着什么

如果你经常让 Agent 执行持续数分钟甚至更久的任务,刷新页面时可以更放心地恢复原有工作现场。连接中断或窗口调整后,终端显示也更有机会保持与断开前一致,而不是出现重复输出、残留旧画面或布局错乱。

不过,状态恢复并不等于所有问题都自动消失。部署或改造类似系统时,仍需要明确以下边界:

  • Agent 进程的真实所有者是谁,是后端服务还是桌面主进程。
  • Agent 标识是否稳定,是否能防止刷新后误连到其他用户的进程。
  • 进程已退出、崩溃或失去权限时,前端如何展示并决定是否重建。
  • 终端尺寸变化发生在前端、PTY 还是 Agent 进程一侧,三者是否同步。
  • 屏幕状态与实时输出之间如何排序,避免恢复快照覆盖新到达的数据。

采用建议

Termexo v0.8.6 的改动可以归纳为一份很实用的检查清单:

  • 把页面生命周期和 Agent 进程生命周期分开。
  • 刷新时先查找并连接已有进程,再考虑创建新进程。
  • 为每个 Agent 保存稳定的会话标识和明确的状态机。
  • 恢复终端时优先重建屏幕状态,而不是盲目追加输出日志。
  • 对刷新、断线重连、终端缩放和进程退出分别编写测试。
  • 在多窗口和多 Agent 场景下验证不会发生错误复用或重复启动。

对于终端工作台,这些变化不是表面上的刷新优化,而是对“任务是否连续”的一次修正。用户真正需要的是一个不会因为 UI 暂时重载,就忘记后台工作进度的工具。


相关推荐