Repository navigation
Releases
v1.8.0 — 429 按滑动窗口退避重试
v1.8.0 — 429 按滑动窗口退避重试
问题
插件此前对 429 主动拒绝重试:errors.ts 的 retryable 仅对 kind === 'server' 为真,视频轮询循环也直接抛出。免费档限额是每 key 每 60 秒 6 次请求,一旦并发或短时间多次调用,工具就立刻失败,没有任何恢复机会。
改动
新增 _core/rate-limit.ts
RateLimiter:滑动窗口主动限速。按 API key 记录请求时间戳,配额用尽时先排队等待,从源头避免撞限流。limiterFor(apiKey, ...):进程内按 key 共享限速器 —— 与网关的计数维度一致,多个工具共用同一把 key 时也共用同一份额度。backoffDelay(attempt, retryAfterMs, base, max, gatewayWindowMs):指数退避 + 抖动,优先遵循Retry-After,并以下限方式保证不低于网关窗口。policyFromConfig:把插件配置映射为完整策略。
_core/http.ts
agnesJson 现在是唯一的请求出口,两条机制都在这里生效:
- 请求前调
limiter.acquire()排队; - 收到 429 后计算退避并重试,耗尽才抛出。
非 429 错误(401/400 等)不重试,立即抛出。
修复的关键缺陷(实测发现)
首版按本地 windowMs 计算退避上限。端到端实测暴露问题:当本地窗口(10s)短于网关窗口(60s)时,退避只有 1–15 秒,重试落在同一个已耗尽的窗口内,12 次里丢掉 5 次。
修复为:策略中新增 gatewayWindowMs,退避结果以它为下限。修复后同样场景 12/12 全部成功。
_core/sleep.ts(新增)
sleep 从 http.ts 抽到独立模块,避免 rate-limit.ts 与 http.ts 互相导入形成循环依赖。http.ts 仍重导出 sleep,调用方无需改动。
配置项(三个工具包)
| 配置 | 默认值 | 说明 |
|---|---|---|
rateLimitRequestsPerWindow |
6 |
每窗口请求上限;0 关闭主动限速 |
rateLimitWindowMs |
60000 |
限速窗口长度 |
rateLimitMaxRetries |
4 |
遇到 429 的重试次数 |
rateLimitBaseDelayMs |
3000 |
首次退避基准,指数增长 |
验证
- 单元测试 24 项全部通过:滑动窗口淘汰、指数退避、抖动量、
Retry-After解析与优先级、按 key 共享、429 重试成功/耗尽、401 不重试、取消中断退避、requestsPerWindow=0关闭限速,以及两条网关窗口下限回归。 - 真实 API 端到端:故意把本地窗口设为 10s(短于网关 60s),连发 12 次 —— 修复前 7/12(丢 5 次),修复后 12/12 全部成功,两次退避耗时 60–67 秒,符合等满网关窗口的预期。
- 三包
tsdown构建通过,产物已确认包含新配置项。
行为变化
- 撞到限流时不再立刻报错,而是等待后重试;调用方可能观察到更长的耗时(最坏为
maxRetries × 60s)。 - 取消信号依然即时生效:等待中的退避会被打断。
- 429 文案已更新,不再写"不要重试",改为说明重试已耗尽及可调参数。
- 顺带更新了
auth失败的提示,不再硬编码AGNES_AI_API_KEY,改为指引检查llm-pi-ai中的apiKeyEnv引用。
三包同步发布,版本号一致为 1.8.0。
v1.7.0 — 凭据解析改为跟随 DSH 配置的 Agnes key
v1.7.0 — 凭据解析改为跟随 DSH 配置的 Agnes key
问题
图像 / 视频工具此前把凭据名硬编码为 AGNES_AI_API_KEY(回退 AGNES_API_KEY),完全不读取用户在 DSH 中配置的 Agnes provider 凭据。
后果是:即使用户在 llm-pi-ai 设置段里正确配置了 AGNESCOM_API_KEY / AGNESCN_API_KEY,图像与视频工具仍然只认那个遗留的固定名字。该名字一旦失效(例如返回 401 This token status is unavailable),工具就会持续报错,而用户明明已经配好了可用的 key。
改动
凭据解析改为三层优先级,优先跟随 DSH 已配置的 key:
- 插件配置
apiKeyEnv(新增,显式指定时最高优先) - DSH
llm-pi-ai设置段中 Agnes provider 声明的apiKeyEnv,按 provider 声明顺序 - 兼容回退:
AGNES_AI_API_KEY→AGNES_API_KEY
具体实现(_core/credential.ts)
- 新增
listKeyCandidates(ctx, options):只做候选排序、不去解析,便于诊断与测试 - 新增
resolveCredential(ctx, options):解析出 key 并带回来源引用名 readCredential(ctx, options):保持原签名向后兼容,新增可选第二参数- 从
llm-pi-ai设置段读取providers.*.apiKeyEnv,只挑选路由 id 以agnes开头的 provider - 所有候选统一经
ctx.credentials.resolve()解析,因此 key 轮换无需重启即可生效 - 未配置的引用会被跳过而非报错,使失效的遗留 key 与可用的新 key 能够共存
- 设置服务不可用、命名空间缺失或 profile 未写
apiKeyEnv时,均优雅降级为空列表
各子包
三个工具包均新增可选配置项 apiKeyEnv(默认 '',即自动跟随 DSH 配置):
- id: tool-agnes-image
name: '@dingpenghui/agnes-image'
config:
model: agnes-image-2.5-flash
apiKeyEnv: AGNESCOM_API_KEY # 可选:留空则自动读取 DSH 中的 Agnes provider 配置验证
- 新增
tests/credential-priority.test.mjs,覆盖 6 项优先级场景,全部通过:- DSH 配置多个 Agnes provider 时的顺序
- 忽略非
agnes前缀的 provider - provider 未写
apiKeyEnv时跳过 - 无 settings 服务时降级到遗留名字
- 重复引用去重
- 显式
apiKeyEnv优先级最高
- 三包
tsdown构建通过,产物已确认包含新逻辑 - 类型检查通过
升级说明
仅新增可选配置,默认行为即自动跟随 DSH 配置,无需修改现有配置即可获得修复。
三包同步发布,版本号一致为 1.7.0。
v1.6.2
发布说明 v1.6.2
日期: 2026-10-03
修复 / Fixes
workspace:^协议误发:1.6.1 的@dingpenghui/agnes(profile bundle)把组件包依赖原样写成了workspace:^(pnpm monorepo 专用协议),发布到 npm 后消费端解析失败。现在改为显式^1.6.1版本语义。- 组件包(
agnes-image/agnes-video/agnes-img2vid)的 1.6.1 发布本身正确(无 workspace 协议),无需重发;本版本仅修正 profile bundle。
- 组件包(
不变 / Unchanged
- 1.6.1 的全部修复(宿主模块
dsh-*从dependencies移到peerDependencies,消除插件树第二份dsh-tools实例)保持不变。 - 四个工具的调用逻辑、模型配置、credential 解析链全部不变。
升级指引 / Upgrade
- 从 1.6.1 升到 1.6.2 无 breaking change,直接
pnpm update @dingpenghui/agnes即可。
v1.6.1
发布说明 v1.6.1
日期: 2026-10-03
修复 / Fixes
- 依赖模型重构:三个组件包(
agnes-image/agnes-video/agnes-img2vid)把宿主模块@deepseek-ai/dsh-agent、dsh-attachment、dsh-credentials、dsh-jobs、dsh-llm、dsh-tools、schemastery从运行时dependencies移到peerDependencies(标optional: true),仅保留@deepseek-ai/cordis作为必选 peer。- 根因:这些包是 DSH 宿主扩展,运行时在宿主进程内执行。宿主已经把
dsh-*加载进同一进程作为宿主模块。组件包若再以dependencies携带同版本包,pnpm 会在插件树里再实例化一份,dsh-tools内部的TOOL_RUNTIME_SCHEDULERSymbol 跨实例查不到,宿主调度器取到undefined,触发Cannot read properties of undefined (reading 'prepare')整轮崩溃(详见 10-03 崩溃调查报告)。 - 影响:插件自身代码行为不变,只改变了"谁提供这些包"——现在统一由 DSH 宿主提供,单实例,Symbol 身份不分裂。
- 根因:这些包是 DSH 宿主扩展,运行时在宿主进程内执行。宿主已经把
@dingpenghui/agnes(profile bundle):版本 1.6.0 → 1.6.1,跟随组件包修复(其dependencies仍写workspace:^,发布后保持^1.6.1语义,指向修复后的组件包)。
不变 / Unchanged
- 四个工具(
generate_image/generate_video/get_video_task/generate_img2vid)的调用逻辑、模型配置、credential 解析链全部不变。 smoke-test不变。
升级指引 / Upgrade
- 从 1.6.0 升到 1.6.1 无 breaking change,直接
pnpm update @dingpenghui/agnes即可。 - 插件安装后宿主行为不变,但不再在插件树里携带
dsh-*副本。
v1.6.0 — SDK 0.2.0-rc.2 + official 1-bundle-3-components shell
dsh-tool-agnes v1.6.0
本次更新(中文)
1. SDK 依赖升到 0.2.0-rc.2
所有 @deepseek-ai/* 依赖从 ^0.1.7-rc.2 升到 ^0.2.0-rc.2(与 DSH 桌面端 0.2.0-rc.2 的 next 线对齐)。0.2.0 沿用了 0.1.7 的 producer 契约(同步 run(job)、JobOutcome.result、JobRead),typecheck / 构建 / 单元测试 / 运行时验收全部通过。
2. 官方"一个 bundle + 三个组件"形态
新增 bundle 壳包 @dingpenghui/agnes(dsh-tool-agnes-profile/),对齐官方 dsh-base / dsh-experimental-agent-team-profile 的模式:
lib/index.js是空壳,全部作用是通过cordis.patch.yml的insert把 3 个组件包一次性挂载- UI 里"一个开关"即可同时启用
generate_image/generate_video+get_video_task/generate_img2vid - 组件包仍可单独安装、单独关闭;走 bundle 则整体开关
接入(只需一条依赖):
{
"dependencies": {
"@dingpenghui/agnes": "^1.6.0"
}
}3. 工程化
- 4 个包(3 组件 + 1 bundle 壳)纳入同一
pnpm-workspace.yaml,bundle 对组件的依赖自动走本地 link - 新增
.gitignore(node_modules/、lib/构建产物、.npmrc) _verify/bundle-shell-check.mjs验证 bundle 壳结构 + 3 组件入口可解析可导出
npm 发布
4 个包均已发布为 1.6.0:
@dingpenghui/agnes(bundle 壳)@dingpenghui/agnes-image@dingpenghui/agnes-video@dingpenghui/agnes-img2vid
What's Changed (English)
1. SDK dependencies bumped to 0.2.0-rc.2
All @deepseek-ai/* deps moved from ^0.1.7-rc.2 to ^0.2.0-rc.2 (aligned with the DSH 0.2.0-rc.2 next line). 0.2.0 reuses 0.1.7's producer contract (sync run(job), JobOutcome.result, JobRead); typecheck / build / unit tests / runtime acceptance all pass.
2. Official "1 bundle + 3 components" shape
New bundle shell package @dingpenghui/agnes (dsh-tool-agnes-profile/) follows the official dsh-base / dsh-experimental-agent-team-profile pattern:
lib/index.jsis an empty shell; its only job is toinsertthe three component rows viacordis.patch.yml- A single UI toggle enables all three tool sets (
generate_image/generate_video+get_video_task/generate_img2vid); components can still be installed/disabled individually - One dependency to install:
"@dingpenghui/agnes": "^1.6.0"
3. Engineering
- All 4 packages (3 components + 1 bundle shell) share one
pnpm-workspace.yaml; the bundle's component deps auto-link locally .gitignoreadded (node_modules/,lib/build output,.npmrc)_verify/bundle-shell-check.mjsvalidates the shell structure and component entry points
npm
All 4 packages published as 1.6.0: @dingpenghui/agnes, @dingpenghui/agnes-image, @dingpenghui/agnes-video, @dingpenghui/agnes-img2vid.
环境要求 / Requirements
| 项 | 要求 |
|---|---|
| DSH | 0.2.0-rc.2(SDK 0.2.0-rc.2) |
| Node.js | >= 22(开发机 24.x) |
| 凭据 / Credential | AGNES_AI_API_KEY(旧名 AGNES_API_KEY 仍兼容) |
v1.5.1 — DSH 0.2.0-rc.2 support + official 1-bundle-3-components shell
dsh-tool-agnes v1.5.1
本次更新(中文)
1. 适配 DSH 0.2.0-rc.2(SDK 0.1.7-rc.2)
跟随 DSH 主线从 0.1.5-rc.2 升到 0.2.0-rc.2,三个组件包全部升级:
dsh-jobs服务定义重写:新版 producer 契约改为同步run(job)返回{ cancel, done };owner 由 Agent 改为裸SessionId;终值经JobOutcome.result传递,读侧从{ snapshot, text }改为JobRead { chunks, result, job }。_core/video-job.ts已按新契约重写,get_video_task对外行为不变。- 消息源声明:
dsh-llm移除了共享的kind: 'plugin'消息源,生产者需在自己的模块里合并MessageSourceMap。三个插件各自声明tool-agnes-image/tool-agnes-video/tool-agnes-img2vid。 - 依赖升级:所有
@deepseek-ai/*依赖升到^0.1.7-rc.2,schemastery升到^3.18.4。
2. 新增 Bundle 壳包:官方"一个插件 + 3 组件"模式
参考 DSH 官方 dsh-experimental-agent-team-profile 的形态,新增 bundle 壳包 @dingpenghui/agnes(dsh-tool-agnes-profile/):
lib/index.js是空壳,全部作用是把 3 个组件包通过cordis.patch.yml的insert一次性挂载- UI 里"一个开关"即可同时启用
generate_image/generate_video+get_video_task/generate_img2vid三套工具 - 组件包仍可单独安装、单独关闭;走 bundle 则整体开关
接入(只需一条依赖):
{
"dependencies": {
"@dingpenghui/agnes": "^1.5.1"
}
}3. 工程化
- 4 个包纳入同一
pnpm-workspace.yaml,bundle 对组件的依赖自动走本地 link - 新增
.gitignore(node_modules/、lib/构建产物) _verify/bundle-shell-check.mjs验证 bundle 壳结构 + 3 组件入口可解析可导出- 单元 11/11、运行时验收、bundle 结构检查全部通过
What's Changed (English)
1. DSH 0.2.0-rc.2 (SDK 0.1.7-rc.2) support
The plugin now tracks the DSH 0.2.0 line; all three component packages are upgraded:
dsh-jobsservice rewritten: the new producer contract is a synchronousrun(job)returning{ cancel, done }; owner is now a bareSessionId; the terminal value travels viaJobOutcome.resultand the reader returnsJobRead { chunks, result, job }instead of{ snapshot, text }._core/video-job.tsis rewritten to match;get_video_taskbehavior is unchanged.- Message-source declarations:
dsh-llmremoved the sharedkind: 'plugin'source; producers now merge their own kinds intoMessageSourceMap. Each plugin declares its own (tool-agnes-image/-video/-img2vid). - Dependency bumps: all
@deepseek-ai/*deps →^0.1.7-rc.2,schemastery→^3.18.4.
2. New bundle shell package — official "1 plugin + 3 components" pattern
Following the official dsh-experimental-agent-team-profile shape, a new bundle shell package @dingpenghui/agnes (dsh-tool-agnes-profile/) composes the three components:
lib/index.jsis an empty shell; its only job is toinsertthe three component rows viacordis.patch.yml- A single toggle in the UI enables all three tool sets (
generate_image/generate_video+get_video_task/generate_img2vid); components can still be installed/disabled individually - One dependency to install:
"@dingpenghui/agnes": "^1.5.1"
3. Engineering
- All 4 packages share one
pnpm-workspace.yaml; the bundle's component deps auto-link locally .gitignoreadded (node_modules/,lib/build output)_verify/bundle-shell-check.mjsvalidates the shell structure and component entry points- Unit tests 11/11, runtime acceptance, and bundle structure checks all pass
环境要求 / Requirements
| 项 | 要求 |
|---|---|
| DSH | 0.2.0-rc.2(SDK 0.1.7-rc.2) |
| Node.js | >= 22(开发机 24.x) |
| 凭据 / Credential | AGNES_AI_API_KEY(旧名 AGNES_API_KEY 仍兼容) |
v1.5.0 — 默认使用最新免费模型 / latest free models by default
中文
默认模型切换到最新一代免费模型:agnes-image-2.5-flash 与 agnes-video-2.5-flash。
变更
- 两个视频工具的默认模型由
agnes-video-v2.0改为agnes-video-2.5-flash—— 实测现价$0/秒(原$0.025/秒) - 新增
DEFAULT_VIDEO_MODEL常量,默认值不再依赖模型数组的顺序 cordis.yml与 profile 配置同步更新
修正(只有实测才能发现)
| 事实 | 影响 |
|---|---|
2.5 系列的图生视频要求 mode: "reference" + images 数组 |
传 mode: "image" 或裸 image 字段会 400 invalid mode;请求构造现按模型族分开 |
2.5 完成时 internal_status 停在 pending、internal_progress 停在 0 |
仅 status/completed_at/progress 推进;状态机优先判定 completed_at,天然兼容 |
agnes-video-2.5-flash 的 size 仅接受 720P |
Flash 专属限制,与默认值一致 |
验证
- 2.5-flash 文生视频端到端通过(5 秒 720P 实测渲染 191 秒)
- 2.5-flash 图生视频对公网 URL 与内联 data URL 均返回 200 —— 会话图片、DSH 附件、本地文件、公网图片四条来源全部可用
- 类型检查、构建、11 项单元测试全部通过
安装
pnpm add @dingpenghui/agnes-image @dingpenghui/agnes-video @dingpenghui/agnes-img2vid
提醒
免费额度仍有速率限制:短时间连续创建任务会返回 429 rate_limit_exceeded,等待窗口重置即可恢复,并非模型不可用。
English
Default models moved to the latest free generation: agnes-image-2.5-flash and agnes-video-2.5-flash.
Changed
- Both video tools now default to
agnes-video-2.5-flashinstead ofagnes-video-v2.0— measured current price$0/second(down from$0.025) - New
DEFAULT_VIDEO_MODELconstant, so the default no longer depends on array order cordis.ymland the profile config updated to match
Fixed (found only by measuring)
| Fact | Impact |
|---|---|
The 2.5 family's image-to-video requires mode: "reference" with an images array |
mode: "image" or a bare image field is rejected with 400 invalid mode; request construction is now per-family |
A finished 2.5 task leaves internal_status at pending and internal_progress at 0 |
Only status/completed_at/progress advance; the state machine already prefers completed_at, so no change was needed |
agnes-video-2.5-flash accepts only size: "720P" |
A Flash-specific limit, matching the default |
Verified
- 2.5-flash text-to-video end to end (5s of 720P rendered in a measured 191s)
- 2.5-flash image-to-video returns 200 for both a public URL and an inline data URL — session images, DSH attachments, local files and public images all work
- Typecheck, build and the 11 unit tests all pass
Install
pnpm add @dingpenghui/agnes-image @dingpenghui/agnes-video @dingpenghui/agnes-img2vid
Note
The free tier is still rate limited: creating several tasks in quick succession returns 429 rate_limit_exceeded; it recovers once the window resets. The models themselves are available.
v1.4.0 — 适配 DSH 0.1.5-rc.2 / DSH 0.1.5-rc.2 compatibility
中文
本版本让插件在 DSH 0.1.5-rc.2 上真正可用,并完成三轮优化。升级前三个插件处于完全不可用状态:从未构建过,且同时踩中 DSH 契约变更与 Agnes 线上 API 的参数收紧。
修复(12 项阻断问题)
| 问题 | 实测现象 |
|---|---|
请求体带 stream / format |
400 ... is not supported by text image queue,生图必然失败 |
凭据名写死 AGNES_API_KEY |
实际存储的是 AGNES_AI_API_KEY,一律报未配置 |
视频 URL 读 metadata.url |
完成报文里 URL 在顶层 url,任务完成却拿不到地址 |
轮询只看 status |
实测首次轮询根本没有该字段 |
detectImage 导入 |
该符号未从 @deepseek-ai/dsh-attachment-local 入口导出 |
依赖 ^0.1.0-rc.5 |
npm 上不存在该版本;三个包从未构建 |
cordis.yml 配置 |
代码里没有 Config schema,配置被静默丢弃 |
| 输出 schema | 可选字段被标为 required,下载失败时整次调用被拒 |
新增与优化
- 视频异步化:改用 DSH 后台任务(
ctx.jobs),单次调用从实测 272 秒降到约 1 秒 - 新增
get_video_task:幂等读取后台结果,返回视频 URL 与本地副本 - 图片不再需要公网 URL:实测
POST /v1/videos接受data:URL,因此公网 URL、DSH 附件、本地文件、内联数据四类来源均可用 - GUI 粘贴的图片可直接引用:订阅
session/event建立会话图片索引,image参数可省略 - 产物落盘:完成的视频下载进附件存储,落盘失败也不丢 provider URL
- 错误可行动化:10 类失败各带
Next step:建议,只有瞬时错误可重试 - 工具卡片:三个工具均实现
presentCall/presentResult - 共享
_core/:消除 video 与 img2vid 之间逐字节重复的客户端
工具
| 工具 | 说明 |
|---|---|
generate_image |
文生图,结果内联渲染在对话中 |
generate_video |
文生视频,默认后台渲染 |
get_video_task |
读取后台视频任务 |
generate_img2vid |
图生视频,image 可省略以使用会话中最近一张图 |
安装
pnpm add @dingpenghui/agnes-image @dingpenghui/agnes-video @dingpenghui/agnes-img2vid
凭据:AGNES_AI_API_KEY(回退旧名 AGNES_API_KEY),写入 $DSH_HOME/.credentials.yaml 的 refs 下,或使用同名环境变量。
已知限制
- 图生图 / 图像编辑不可用:网关的文本图像队列实测拒绝
images与image形状,因此未提供该工具 - 2.5 系列视频按秒计费,免费 Key 会返回
429 - 内联图片上限 8 MB(
maxInlineImageBytes,可配)
English
Makes the plugins actually work on DSH 0.1.5-rc.2, plus three rounds of optimisation. Before this release the three plugins were entirely unusable: never built, and simultaneously broken by a DSH contract change and by Agnes tightening its live API.
Fixed (12 blocking issues)
| Issue | Observed behaviour |
|---|---|
stream / format in the image body |
400 ... is not supported by text image queue — generation always failed |
Credential hard-coded as AGNES_API_KEY |
this deployment stores AGNES_AI_API_KEY, so every call reported "not configured" |
Video URL read from metadata.url |
the finished URL is the top-level url — tasks completed but no address was returned |
Polling keyed only on status |
the earliest polls do not carry that field at all |
detectImage import |
not exported from @deepseek-ai/dsh-attachment-local's entry point |
Dependency ^0.1.0-rc.5 |
does not exist on npm; the packages had never been built |
cordis.yml config |
no matching Config schema, so configuration was silently dropped |
| Output schema | optional fields declared required — a failed download rejected the whole call |
Added and improved
- Async video: renders as a DSH background job (
ctx.jobs); a call drops from a measured 272s to ~1s - New
get_video_task: idempotent read of the background result, with the video URL and a local copy - No public URL required: the gateway accepts a
data:URL, so public URLs, DSH attachments, local files and inline data all work - GUI-pasted images work directly: a session image index built from
session/eventmakesimageoptional - Artifacts persisted: finished videos are stored in the attachment store; a storage failure never loses the provider URL
- Actionable errors: 10 failure classes, each carrying a
Next step:line; only transient failures are retryable - Tool cards:
presentCall/presentResulton all three tools - Shared
_core/: removes the byte-identical client previously duplicated by video and img2vid
Tools
| Tool | Purpose |
|---|---|
generate_image |
text to image, rendered inline in the conversation |
generate_video |
text to video, background render by default |
get_video_task |
read a background video task |
generate_img2vid |
animate an image; omit image to use the most recent one in the session |
Install
pnpm add @dingpenghui/agnes-image @dingpenghui/agnes-video @dingpenghui/agnes-img2vid
Credentials: AGNES_AI_API_KEY (legacy AGNES_API_KEY still accepted), stored under refs in $DSH_HOME/.credentials.yaml or exported under the same name.
Known limitations
- Image editing / image-to-image is unavailable: the gateway's text image queue rejects both
imagesandimageshapes, so no such tool is provided - 2.5-family video is billed per second and returns
429on a free key - Inline images are capped at 8 MB (
maxInlineImageBytes, configurable)