Skip to content

feat: 支持单实例连接多个 opencode server + 运行时内存优化 #16

@laozhoulaile

Description

@laozhoulaile

你的问题

首先感谢作者做出这个项目!在 B 站看到介绍之后马上试用,飞书 ↔ opencode 的双向消息桥接开箱即用,streaming card 的实时渲染体验也很顺滑。对于日常想用 IM 远程操控 opencode 的场景来说,目前这是我见过最便捷的方案了,感谢作者的无偿贡献 🙏

背景

在实际使用中遇到两个问题,提出来和作者探讨下可行性和思路。

一、支持单实例连接多个 opencode server(一拖多)

现状

当前 im-bridge 是严格的 1:1 架构:一个 OPENCODE_SERVER_URL → 一个 opencode 进程。如果需要同时跑多个 opencode worker(不同端口 4096/4097/4098,各自独立工作区),就必须:

  • 每个 worker 启动一个 im-bridge 实例
  • 每个实例创建一个独立的飞书应用(因为 WebSocket 长连接互斥)
    3 个 worker = 3 个 im-bridge 进程 × ~200MB = ~600MB 内存,代价过高。

期望

希望一个 im-bridge 实例能同时连接多个 opencode server,根据消息来源(如不同的飞书群/用户/指令前缀)路由到不同的 opencode 实例,实现"一拖多"。

可能的设计思路

  1. 配置侧opencode-lark.jsonc 新增 servers 数组,每个 entry 包含 idurldefaultAgent 等字段;向后兼容,不配 servers 时行为不变
    {
      "servers": [
        { "id": "main", "url": "http://127.0.0.1:4096", "defaultAgent": "build" },
        { "id": "worker-1", "url": "http://127.0.0.1:4097", "defaultAgent": "build" },
        { "id": "worker-2", "url": "http://127.0.0.1:4098", "defaultAgent": "build" }
      ]
    }
  2. 路由侧:新增路由策略配置,支持:
    • 按飞书群 chat_id 映射到指定 server
    • 按指令前缀路由(如 /w1 xxx → worker-1)
    • 自动轮询/负载均衡(可选)
  3. Session 侧:SessionManager 改为按 server 分片,feishu_key 映射到 (serverId, sessionId) 二元组,数据库表增加 server_id 列
  4. SSE 侧:对每个 server 建立独立的 SSE 订阅,事件分发时带上 serverId 区分
  5. 飞书侧:仍共用一个飞书应用,不同 server 的回复通过不同群/话题区分
    实际使用场景
  • OPOP(参数优化)工作流中,多个方向并行探索,每个方向一个 opencode worker
  • 主 agent 派生 subagent 时,subagent 正在执行期间主 agent 会被 QUEUED 无法接收新指令,因此需要独立的 opencode 实例来处理用户的其他交互

二、运行时内存优化

现状
im-bridge 长期运行后内存占用 200MB+(Bun 运行时基线约 160-180MB,加上业务逻辑后增长到 200MB+)。对于需要 7×24 运行的桥接服务来说偏高。
可能的优化方向

  1. SSE 事件缓冲区:eventProcessor 和 sessionObserver 在长连接中可能累积未释放的监听器/闭包,建议加定期 GC 审计(比如 ownedSessions Set 和 eventListeners Map 的增长曲线)
  2. SQLite 连接池:当前用 bun:sqlite 的同步 API,连接持有时间长,看是否有未及时 finalize 的 statement
  3. streaming card 模板缓存:CardKitClient / cardBuilder 的模板渲染是否有内存缓存膨胀
  4. Bun 运行时自身开销:Bun 的 GC 策略偏向吞吐而非延迟,可以考虑:
    • 启动参数 --max-old-space-size 限制
    • 定期 Bun.gc(true) 强制回收(如果 Bun 支持的话)
    • 或者提供 lightweight 模式,关闭 streaming card 改用纯文本回复,减少渲染路径的内存占用
  5. 可选的 headless 模式:提供一个 --lightweight 启动参数,关闭非核心功能(streaming card、heartbeat、cron),只保留最基础的收发消息,目标内存 < 100MB

总结
两个需求的核心诉求是一样的:让 im-bridge 在资源受限的环境下也能支撑多 agent 并行工作。一拖多解决的是"需要多个 opencode 但不想开 N 个 im-bridge"的问题,内存优化解决的是"单个 im-bridge 就占 200MB+ 太重"的问题。

背景信息

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    questionFurther information is requested

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions