🎯 OpenCode插件系列:

类型: OpenCode Plugin — DCP 上下文限制同步器


1. 这是什么插件?

opencode-dcp-dynamic-limits 是一个专门为 DCP (@tarquinen/opencode-dcp) 服务的 OpenCode 插件。核心概念:

  • DCP(Dynamic Context Pruning)是个独立的上下文裁剪插件
  • DCP 不知道你当前用的模型上下文窗口有多大
  • 当你切换模型时,DCP 经常被留下陈旧的限制 —— 该剪的时候不剪,不该剪的时候乱剪,更糟的是把 dcp-system-reminder 持续塞进聊天里
  • 这个插件在真实的 chat 请求上钩入 OpenCode,识别当前模型即时更新 DCP 配置

写这个插件的人是个本地 GGUF 玩家(用 llm-server + ik_llama.cpp / llama.cpp),经常在云端模型和本地 GGUF 之间来回切,所以吃了这个亏。

与"自动配置 DCP"的区别:

方面 静态 DCP 配置 dcp-dynamic-limits
上下文窗口 写死在 `dcp.jsonc` 跟随当前模型动态计算
切换模型 需手动改配置 自动同步
检测来源 进程参数 → `/slots` → `/v1/models` → manifest 逐级回退
限制区间 单一值 60%(min)/ 85%(max)随上下文缩放
安静模式 min=max,跳过软警告区

2. 用来做什么?

使用它来:

  • ✅ 本地 ↔ 云端模型 切换时自动同步上下文窗口
  • ✅ 修复 DCP 在错误时机裁剪 的问题
  • ✅ 消除 dcp-system-reminder 在聊天里持续刷屏
  • ✅ 支持 llm-server / ik_llama.cpp / llama.cpp / Ollama / LM Studio / Jan / text-generation-webui
  • ✅ 同时支持 OpenCode model manifest 里的云端模型
  • ✅ 写一个进程参数 → /slots → /v1/models 的多层回退检测
  • ✅ 5 秒节流,不打扰正常 chat 流程

典型场景:

你:把模型从云端 Claude 切到本地 ik_llama 的 Qwen2.5-1M.gguf

[dynamic-limits]
- chat.params 钩子触发
- 读 ps ax → 找到 ik_llama 进程的 --ctx-size 262144
- 计算 dcpMin=157286, dcpMax=222822
- 写入 ~/.config/opencode/dcp.jsonc
- 把 pruneNotificationType 改成 toast,nudgeForce 改成 soft

DCP 重新加载,立即知道自己的限制 = 222822
后续对话不再误剪,不再乱塞 reminder

3. 如何使用?

安装

需要先装 DCP(本插件是 DCP 的"修正"层):

npm install -g @tarquinen/opencode-dcp
npm install -g opencode-dcp-dynamic-limits

在 ~/.config/opencode/opencode.json 中:

{
  "$schema": "https://opencode.ai/config.json",
  "plugin": [
    "@tarquinen/opencode-dcp@latest",
    "opencode-dcp-dynamic-limits"
  ]
}

DCP 必须先加载。本插件只在 DCP 已存在的基础上调整它的配置。

检测逻辑

对于本地 llama.cpp 风格的服务

  1. 优先读运行时 -ctx-size(通过 ps ax
  2. 回退到 /slots 的 n_ctx
  3. 再回退到 /v1/models 的 max_model_len / n_ctx_train
  4. 最后用 model manifest 的 context
  • -parallel 的 slot 大小只作为诊断信息,不会被当作完整上下文窗口。

对于云端模型

  • 直接用 OpenCode model manifest 里的 limit.context

    具体来说,OpenCode 在 chat.params 钩子里会传入 input.model 对象,其中:

  • model.limit.context — OpenCode 内置的该模型上下文窗口

  • model.limit.output — OpenCode 内置的该模型最大输出 token 对 Anthropic / OpenAI / Google 等 OpenCode 内置 provider,这些字段是 OpenCode 自己知道并自动填的。calculateOnlineLimits 直接读它们: const contextLimit = model.limit?.context ?? 128000 const outputLimit = model.limit?.output ?? 8192 如果某个云端模型 OpenCode 不认识(limit 字段缺失),就会落到硬编码的默认值 128000 / 8192 —— 这是个已知盲点,但常见云端模型都被 OpenCode 内置覆盖了。

一个边界情况需要你注意 如果你配的是自定义 cloud provider(比如自己 proxy 转发的非标准 OpenAI 兼容端),isLocalModel(index.ts:24)会通过 provider.source === “custom” 误判为本地,走 llama.cpp 检测路径,那八成会失败。 解决方法:要么把 endpoint 指向 localhost(被 url.startsWith("http://localhost") 兜底

安静模式

默认开启安静模式(避免软警告区反复触发):

{
  "pruneNotificationType": "toast",
  "compress": {
    "nudgeForce": "soft",
    "nudgeFrequency": 50,
    "iterationNudgeThreshold": 50
  }
}

安静模式下 minContextLimit = maxContextLimit,DCP 只在硬上限处裁剪,跳过中间的软警告刷屏。


4. 何时使用?

在以下情况使用:

  • ✅ 你的 OpenCode 在多个模型间切换(尤其本地 ↔ 云端)
  • ✅ 用 llm-server / ik_llama.cpp / llama.cpp / Ollama 之类的本地后端
  • ✅ DCP 在错误时机裁剪 —— 上下文远没满就开始剪
  • ✅ 看到 dcp-system-reminder 持续出现在聊天 里
  • ✅ 不同模型的上下文窗口差异很大(例如 32K vs 262K)
  • ✅ 想要零配置切换 —— 不用每次手动改 dcp.jsonc

不要在以下情况使用:

  • ❌ 不使用 DCP —— 没装 DCP 这个插件就是空转
  • ❌ 只用单一模型且上下文窗口稳定 —— 写死配置就够
  • ❌ 本地后端不是 llama.cpp / Ollama 风格 API —— 检测可能失败
  • ❌ 不希望 DCP 配置被自动改写 —— 这个插件会直接写 dcp.jsonc

⚠️ 重要注意事项

插件加载顺序:

{
  "plugin": [
    "@tarquinen/opencode-dcp@latest",
    "opencode-dcp-dynamic-limits"
  ]
}

DCP 不存在时这个插件不会报错,但也没意义。

限制值固定为 60% / 85%:

  • dcpMin = 上下文 × 0.6
  • dcpMax = 上下文 × 0.85
  • 安静模式下 dcpMin 被强制等于 dcpMax

这两个百分比不在配置里暴露,需要不同比例得改源码。

输出 token 估算(仅本地):

  • 估算为 perSlotCtx / 4
  • 限制在 [8192, 16384] 区间
  • 这个值不会写进 DCP 配置,只用于日志

节流:

5 秒内不会重复同步。但模型 ID 变化计算结果变化会强制同步。

跳过的 agent:

title agent 触发的 chat 请求不会触发同步 —— 否则每次生成标题都会把 DCP 限制改一遍。

配置文件位置:

插件会写两个常见位置:

~/.config/opencode/dcp.jsonc
~/.opencode/dcp.jsonc

与 oh-my-opencode 等无关:

这个插件是纯配置同步层,不引入任何 agent / 工具 / 通知。和 opencode-background-agents 这类异步委派插件完全正交


🔗 有用链接