npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

opencode-sse-retry

v0.4.0

Published

Configurable bounded retries for SSE transport and application errors in OpenCode

Readme

opencode-sse-retry

简体中文 | English

为 OpenCode 提供可配置、有上限、使用原模型执行的 SSE 错误重试能力。

插件既能处理意外的 ReadableStream 读取失败,也能按用户配置检查完整 SSE 事件的 JSON data。命中规则后,插件将本次失败归类为可重试的传输错误,再由 OpenCode 现有的会话重试循环使用同一模型重新执行请求。插件本身不重新调用模型,也不内置任何供应商名称或错误文本。

当前状态

  • V1 适配器:用于当前 OpenCode 1.18.x 会话运行时。
  • V2 适配器:基于较新的 AISDK 插件接口独立实现。宿主必须显式提供能够稳定标识单个逻辑模型请求的 correlationHeader;缺少该配置时,V2 会拒绝启动。当前 1.18.x 主会话路径应使用 V1。
  • 传输读取失败默认最多重试两次;应用层错误由每条 rules 分别设置上限。

环境要求

  • OpenCode 1.18.x
  • 开发和测试需要 Node.js 22.18 或更高版本

构建与测试

npm install
npm run check
npm run test:integration

test:integration 需要系统中存在可执行的 opencode。该测试会启动一个仅监听本机回环地址的模拟 SSE 网关,并在完全隔离的临时配置和数据目录中运行已安装的 CLI。

通过 npm 安装

将 npm 包名和插件选项添加到 ~/.config/opencode/opencode.json

{
  "plugin": [
    [
      "opencode-sse-retry",
      {
        "maxRetries": 2,
        "providers": ["*"],
        "rules": [
          {
            "providers": ["*"],
            "path": "/error/*",
            "match": [
              {
                "type": "prefix",
                "value": "upstream stream error:"
              },
              {
                "type": "contains",
                "value": "Stream error:"
              }
            ],
            "maxRetries": 2
          }
        ]
      }
    ]
  ]
}

OpenCode 会从 npm registry 获取插件。修改插件配置后,需要重启 OpenCode 服务。

顶层 maxRetriesproviders 只控制原有的 SSE reader 传输失败;为保持 0.1.x 配置兼容,两者默认仍分别为 2["*"]

每条应用层错误规则包含:

  • providers:供应商 ID 列表,支持 "*";省略时默认为 ["*"]
  • path:从 JSON data 根节点开始的路径;* 匹配恰好一个对象属性或数组元素,例如 /error/*
  • match:可以是单个匹配对象,也可以是非空数组;数组中的条件按 OR 判断,支持 existsexactprefixcontains
  • maxRetries:该规则允许的重试次数;2 表示初始请求后最多再请求两次。

规则按配置顺序判断,同一个 SSE 事件只采用第一条命中的规则。同一规则中的多个 match 条件共享该规则的 maxRetries 计数。当前 V1 接口要求目标供应商在 OpenCode 配置的 provider 中有对应条目,因为适配器通过 config hook 安装 fetch 包装器。

同一个供应商和路径需要匹配多种错误时,可以合并到一条规则中:

{
  "providers": ["*"],
  "path": "/error/*",
  "match": [
    { "type": "prefix", "value": "upstream stream error:" },
    { "type": "contains", "value": "Stream error:" }
  ],
  "maxRetries": 2
}

只检查字段是否存在:

{
  "path": "/error/message",
  "match": { "type": "exists" },
  "maxRetries": 1
}

完整匹配:

{
  "path": "/error/message",
  "match": { "type": "exact", "value": "temporary failure" },
  "maxRetries": 2
}

包含匹配(目标字符串可出现在字段值的任意位置):

{
  "path": "/error/message",
  "match": { "type": "contains", "value": "Stream error:" },
  "maxRetries": 2
}

运行机制

对于每个已启用的供应商,V1 适配器会:

  1. 根据会话、消息、Agent、供应商和模型标识生成一个内部关联 header。
  2. 包装供应商现有的 fetch 实现。
  3. 在 HTTP 请求离开 OpenCode 前删除内部关联 header。
  4. 只包装 Content-Type 包含 text/event-stream 的响应。
  5. 组装完整 SSE 事件,解析其中的 data JSON,再应用目标供应商的规则。
  6. 保留调用方的取消操作,不将其标记为可重试。
  7. 将规则允许范围内的命中或 reader 失败标记为 code: "ECONNRESET"
  8. 超过规则上限后转换为不可重试的 SSEApplicationRetryLimitError;reader 失败超过顶层上限时使用 SSEStreamRetryLimitError
  9. 在成功、取消、终止失败或五分钟过期后清理重试状态。

核心模块不会根据 URL 或请求体内容猜测请求身份。缺少稳定的关联 header 时,它会直接返回未包装的响应。这样可以避免无关的并发请求共享重试计数,同时确保重试状态不会保存提示词内容。

因此,V2 适配器要求在插件选项中配置 correlationHeader。该 header 必须由宿主提供,在同一逻辑请求的多次重试之间保持稳定,并且能够区分并发请求。与 V1 的插件内部 header 不同,V2 配置的宿主 header 会被保留并发送至上游。

架构

核心模块对外提供一个刻意保持精简的接口:

createStreamRetryFetch({
  fetch: upstreamFetch,
  maxRetries: 2,
  rules: [
    {
      path: "/error/*",
      match: [
        { type: "prefix", value: "upstream stream error:" },
        { type: "contains", value: "Stream error:" },
      ],
      maxRetries: 2,
    },
  ],
})

调用方必须在需要进行失败归类的请求上添加导出的 INTERNAL_RETRY_HEADER。如果高级宿主已经提供安全的逻辑请求 header,也可以改为设置 correlationHeaderstripCorrelationHeader: false

  • src/core/index.ts:负责 SSE 包装、请求关联、失败上限、状态清理和取消处理。
  • src/adapters/v1.ts:使用 @opencode-ai/pluginconfigchat.headers hook。
  • src/adapters/v2.ts:使用 @opencode-ai/plugin/v2/promisectx.aisdk.sdk 接口。

兼容性边界

OpenCode 1.18.x 没有向外部插件公开会话重试策略 hook,也没有公开内部的 ResponseStreamError 类。因此,V1 适配器利用 OpenCode 当前对 Node 风格 ECONNRESET 错误的结构化处理进入内置重试循环。

这段兼容逻辑被集中隔离在核心模块中,并且已有测试覆盖,但它仍然属于兼容性接缝,而不是稳定的 OpenCode 插件契约。升级 OpenCode 时,应重新运行 npm run check,确认 MessageV2.fromError 中仍然存在 ECONNRESET 映射,并执行真实网关的冒烟测试。

插件只限制由自身归类的 SSE reader 失败和规则命中。对于 HTTP 429、HTTP 5xx 或其他由 OpenCode 自己触发的重试,插件不会额外限制其次数。

安全限制

OpenCode 会重试整个模型流。如果失败的尝试已经产生了部分文本、推理内容或工具调用,现有重试循环可能保留部分内容,或者重复工具调用带来的副作用。本插件不会尝试回滚会话状态。

供应商认证插件可能在 V1 config hook 之后安装自己的 fetch。后加载的认证逻辑可能覆盖本适配器,因此这类供应商需要单独进行集成测试。对于直接配置的供应商,例如本地 OpenAI-compatible 网关,当前实现已经覆盖其预期路径。