dsh-agy-link 0.4.43 → 0.4.46
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +108 -0
- package/README.md +3 -0
- package/dist/client.js +510 -131
- package/dist/index.js +1438 -373
- package/docs/KNOWN-GAPS.md +16 -0
- package/docs/README.en.md +1 -0
- package/docs/README.es.md +1 -0
- package/docs/README.pt-BR.md +1 -0
- package/docs/adr-012-account-pool.md +6 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,9 +1,116 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.4.46 (2026-10-12)
|
|
4
|
+
|
|
5
|
+
### English
|
|
6
|
+
|
|
7
|
+
- **Fix (review cycle 2026-10-12): concurrency-slot leak in the adapter spawn window.** `stream()` acquired a `maxConcurrent` slot and only released it from the process-outcome closure — a caller that abandoned the generator while it was suspended on the burst-spacing throttle (steer abort, DSH closing the stream) dropped the release closure, and each incident permanently leaked one slot until every future run dead-locked in the queue. The spawn window now owns the slot through try/finally, an already-aborted signal short-circuits before spawn, and an abort that lands during the window kills the process immediately instead of running a full turn nobody reads.
|
|
8
|
+
- **Fix (review cycle): a stale pool-auth flow could kill the new login or commit a ghost account.** `finishWithCode` resolved against `this.flow` without checking WHICH flow the callback belonged to: flow A's late `exchangeCode` resolution during flow B either failed B with `invalid_state` (deleting B's staging dir) or, worse, wrote A's token file into A's freshly cleaned dir and committed a one-file ghost account. Settlement is now flow-identity-checked.
|
|
9
|
+
- **Fix (review cycle): long agy tools no longer look like a frozen session.** ACTIVE tool envelopes now emit a one-time `[agy tool running: …]` note into the reasoning block, so a ten-minute maven build shows live progress instead of silence (the 5-minute heartbeat only ever reached the logs). Subagent reasoning snapshots also stop duplicating the whole transcript (suffix-delta like the thinking branch), and a tool-cut span forwards the last per-call usage sample instead of a hard 0/0 that reset DSH's token meter on every tool hop.
|
|
10
|
+
- **Fix (review cycle): synthetic-message filtering can no longer eat the user's real message.** When the sniffed synthetic-looking text is the ONLY user content of the trailing span (a pasted `<system-reminder>` block being the actual question), the bridge now forwards it instead of failing with "request carries no user text" — while an image-only turn still never digs up an older question.
|
|
11
|
+
- **Fix (review cycle): pool/data hardening.** `deleteAccount` only ever `rmSync`s directories under the pool base dir (a hand-edited `dir: "~"` used to be deleted recursively); `pool.json` persists through a known-ids merge so web + headless stop erasing each other's accounts (corrupt files are backed up before defaults overwrite them, and persist failures are surfaced on stderr); `/agy add-account` and `POST /pool/add` quarantine the new slot with `authRequired` until the terminal login is verified, so the scheduler can no longer route real runs to an account nobody signed into; a drained quota window with an UNPARSEABLE reset now counts as exhausted in eligibility and rotation instead of "already reset".
|
|
12
|
+
- **Fix (review cycle): quota/OAuth robustness.** All Google endpoint calls carry a 10s default timeout (a hung refresh-token/quota endpoint used to park `/agy refresh-quota` for minutes); keychain/Secret Service/Credential-Manager reads are async (`execFileSync` up to 8s used to freeze the whole DSH event loop on every poll); concurrent `getValidAccessToken` calls for one account share one in-flight refresh; quota fractions are clamped to [0,1] with NaN rejected; refreshed token files are written 0600.
|
|
13
|
+
- **Fix (review cycle): auth flow lifecycle.** Cancelling during the URL wait now resolves the pending `begin()` (the `/plugins/agy-link/auth` HTTP route used to hang forever), a superseded `begin()` can no longer overwrite the newer flow's state, and the probe/settle timers are cleaned up.
|
|
14
|
+
- **Fix (review cycle): agy conversation DB reads.** A missing `sqlite3` binary or oversized/locked DB used to re-spawn sqlite3 on EVERY step event with the failure silently swallowed (cache still marked loaded, so the storm never converged); failures now back off (ENOENT for the full window, transient for 300ms), log once, and concurrent readers share one in-flight load. The DB copy is taken into a private `mkdtemp` dir with 0600 instead of a predictable /tmp path.
|
|
15
|
+
- **Fix (review cycle): misc.** The OAuth callback page HTML-escapes the reflected `error` parameter; Windows `openBrowser` refuses URLs containing quotes/newlines before the cmd string build; doctor redaction covers `1//0…` refresh tokens, `AIza…` keys and credentialed proxy URLs, and the config dump scrubs `proxyUrl` credentials; `/agy pool` prints proxy URLs redacted; fallback-source model discovery re-probes at most once per minute instead of spawning `agy models` on every list; fallback conversation-id discovery watches the pool account's isolated HOME; mermaid's CDN fallback is removed entirely (floating-version unsigned script in the app origin) and the mermaid/reasoning overlay observers are disposed through `ctx.effect`.
|
|
16
|
+
- **Add: token-speed statistics.** Every recorded event now carries its arrival time; per-step generation windows (≥500 ms) yield `lastTps`/output-weighted `avgTps`/output-token totals on the recording, surfaced through `/agy status` ("last run tokens: N output tokens — avg X tok/s (last generation step: Y tok/s)") and the `lastRun` status payload.
|
|
17
|
+
- **Fix (issue #43): thinking and tool activity are no longer invisible on desktop hosts.** Two compounding causes: (1) thought prose comes from the agy conversation SQLite DB, and the reader required the external `sqlite3` CLI — which GUI/desktop hosts often lack on PATH (macOS GUI apps do not inherit the shell PATH; Windows never ships one). The reader now prefers Node's built-in `node:sqlite` (no external binary) and keeps the CLI as fallback, so reasoning text resolves on desktop hosts. (2) When prose is unavailable, high-effort turns rendered nothing at all; a banner-only `[agy thinking turn · N thinking tokens]` chip now streams before the first visible text (and on thinking-only turns), with the real prose appended seamlessly when the DB resolves later — no duplicate banner, no dropped text, and no clutter on tool-heavy steps after text already streamed.
|
|
18
|
+
- **Fix (issue #45): Windows pool-credential isolation is now an explicit, visible limitation.** agy on Windows stores its login in the system-wide Credential Manager slot `gemini:antigravity` (go-keyring); HOME isolation moves files only, so every isolated pool account still authenticates — and bills — as the system login. The plugin now (1) exposes `credentialIsolationLimited` in `/plugins/agy-link/status`, rendered as a warning banner in the settings panel, (2) logs once per isolated account when it is selected on Windows, and (3) documents the boundary (and why per-run `CredWrite` slot-swapping is not safe with `maxConcurrent > 1`) in KNOWN-GAPS.md. Full isolation needs an upstream agy change (per-HOME keyring namespace or file fallback when the keyring slot is empty).
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
- **Fix: the stuck-run heartbeat no longer lies about how long the run has been silent.** With no tool step open the silence clock was seeded from `Date.now()` over an empty map, so the every-5-minutes log permanently claimed "no new output for 1m" while the run had actually been quiet for hours. It now reports the time since the last stdout line (`lastOutputAt`), which is the number a human needs when deciding whether to press Stop.
|
|
22
|
+
- **Fix: `agy_tool` no longer blames a "recycled" output for a cursor that never pointed at one.** An out-of-range step index (or a non-tool event) and a genuinely evicted recording both used to return the "recorded output is no longer resident" notice — telling the model that output was lost when it was never recorded at all. The degraded message now states the actual reason ("outside this recording — not recorded yet / not a completed tool step" vs. "the in-memory recording was recycled").
|
|
23
|
+
- **Fix: account failover now actually continues the session — including after a completed tool step (the "quota exhausted, turn lost" bug).** DSH re-issues the failed step, and a step that failed inside a tool continuation carried a trailing tool result, so it was resumed from the SETTLED recording and re-emitted the identical failure: a quota/region/auth refusal after any tool call ended the turn while a healthy account was sitting idle (reproduced offline against `test/fake-agy.mjs`). The continuation branch now refuses to re-drive a settled recording whose failure is account-scoped, forgets it, and re-assembles on the next account — inside the same step, with no visible interruption. The failover is bounded (at most `enabled accounts - 1` re-spawns per session per 2 minutes) and never applies to request-level failures, so a deterministic error cannot loop through the pool re-running the user's tools.
|
|
24
|
+
- **Fix: transport-shaped "not logged in" is no longer reported as AUTH (the "API 密钥无效 / API key is invalid" hunt).** agy reports "not logged into Antigravity" both for a real sign-out and for a healthy login whose token it could not VALIDATE (live 2026-10-10 14:17: the retry account's token had expired 9 minutes earlier and its refresh died on `Post https://oauth2.googleapis.com/token: EOF`, next to TLS handshake timeouts). The adapter classified that as `AUTH`, which (a) ended the turn on a healthy account, (b) flagged the account for re-login, and (c) made DSH render its `message.failure.auth` label — "API key is invalid" — for a credential that was never the problem. Transport evidence in the auth-shaped stdout banner, stderr or the result envelope now yields a retryable `NETWORK` failure that rotates to the next account and never quarantines a login.
|
|
25
|
+
- **Fix: the retry budget follows the pool, and a sign-out can continue on another account.** `maxRetries` was a flat 1, so a 3-account pool could never reach the third account — and the live incident needed exactly that (primary ELIGIBILITY → second account "not signed in" → turn lost, though the third was healthy). The budget is now `min(enabled accounts - 1, 2)`, and `AUTH` is retryable when at least one other account exists (the failed one is flagged `authRequired` and leaves rotation).
|
|
26
|
+
- **Fix: soft capacity refusals rotate instead of dead-ending the turn.** "model overloaded" / "experiencing high traffic" used to be a deterministic `AGY_ERROR` — terminal, no rotation, no retry — so a turn died while another account could serve it. They are now `OVERLOADED`: retryable, pointer rotated, and deliberately WITHOUT a cooldown (nothing was spent). The hard-quota matcher also recognises real phrasings it used to miss (`Resource has been exhausted (e.g. check quota).`, `You have exhausted your quota`, `out of quota`, `check quota`), which previously fell through to a bare "agy exited with code 1" on the SAME account.
|
|
27
|
+
- **Fix: the idle watchdog no longer kills a run that is demonstrably working.** 12 of the 37 failures in one week of real logs were exactly `agy run was idle for 600000ms without output`, each costing a turn and a resend. stderr now counts as liveness (agy prints progress there), and once a run has produced ANY output the long budget applies (`longToolIdleMinutes`, default 240m) — before the first event the strict `timeoutMs` stays, which is the genuinely wedged / Google-unreachable shape. The 5-minute heartbeat now also covers a silent-but-alive run instead of only open tool steps, so the user can see it is waiting and press Stop.
|
|
28
|
+
- **Fix: prompts no longer re-send tool output the live agy conversation already owns, and synthetic harness telemetry is filtered.** A bound conversation was piping prior tool results back into `-p` (a live command line was captured carrying a 6.4 KB Godot simulation dump) — stale output ahead of the actual question, which is one of the ways the model ends up answering the previous work. Tool payloads are now dropped when the conversation already has them (they still ride the prompt on a fresh conversation, where agy has never seen them). Separately, DSH runtime telemetry messages injected with `role: 'user'` (`time-context`, `runtime-context`, `<system-reminder>`) are filtered so timestamps never overwrite the human prompt, and an image-only (text-less) newest message no longer falls back to older questions.
|
|
29
|
+
- **Fix: an interrupted turn can no longer make agy answer the message you interrupted.** DSH persists the partial reply of a Stop/steer as a normal assistant message, so the plugin treated the interrupted user turn as answered agy-native history while agy's server-side turn had no finalized reply — the next prompt was just the new message, and the model answered the interrupted one (live: `session-c65a826e` turns 17→19, the user re-asked verbatim with "这个咋不回答呢"). The binding is now flagged `interrupted` when a run is aborted or times out, the next prompt carries an explicit "do not continue that unfinished work" boundary, and a successful turn clears the flag. Images staged by an interrupted run are no longer marked delivered either (re-sending the same screenshot after a Stop was silently deduped away and an image-only follow-up failed with "request carries no user text or images").
|
|
30
|
+
- **Fix: a run that already produced its result is no longer killed by the next call.** Steer preemption aborted a process that had already streamed its answer (recording a false `ABORTED` and cutting agy mid-finalize); it now waits briefly for a natural exit and only preempts a still-running turn. The bounded settle wait reports when it expires, and a superseded run's late write-back can no longer regress `lastMessageCount` / `sentImageIds`.
|
|
31
|
+
- **Fix: pool and binding robustness.** A partial `pool.json` (account missing `cooldowns`/`quotas`) threw a `TypeError` inside `selectAccount`, so every turn failed with an opaque internal error and no failover — records are normalized on load. Rate limits no longer delete the `(session, account)` binding, so a resumable native conversation is not thrown away for a 15-minute cooldown (only a real sign-out or an agy-side "conversation not found" invalidates it). Conversation adoption from a live run is scoped to the SAME account (adopting account A's id under account B produced a wasted "conversation not found" turn). `sessions.json` now performs the dirty-key merge its own docs promised, so the web and headless hosts stop clobbering each other's bindings. A failed turn reports the last per-call context sample instead of a hard-coded 0/0. ADR-012 no longer claims a flat "zero interruption" fallback with a 10-minute cooldown.
|
|
32
|
+
|
|
33
|
+
### 中文 (Chinese)
|
|
34
|
+
|
|
35
|
+
- **修复(2026-10-12 审查周期):适配器 spawn 窗口的并发槽位泄漏。** `stream()` 取得 `maxConcurrent` 槽位后只由进程结算闭包释放——调用方在突发节流 sleep 处放弃生成器(插话中止 / DSH 关闭流)会直接丢掉 release 闭包,每次事故永久泄漏一个槽位,累积后所有后续请求在队列里死锁。现在 spawn 窗口用 try/finally 持有槽位;已中止的 signal 会在 spawn 前短路;窗口内到达的中止会立刻杀进程,而不是跑完一轮没人读的 turn。
|
|
36
|
+
- **修复(审查周期):滞后的 pool-auth 流程可能杀死新登录或提交幽灵账号。** `finishWithCode` 直接对 `this.flow` 结算、不校验回调属于哪个 flow:用户取消 A 并开始 B 后,A 的 `exchangeCode` 迟到返回,要么以 `invalid_state` 杀掉 B(连带删掉 B 的 staging 目录),要么把 A 的 token 文件写进刚清理的 A 目录并提交一个只剩 token 文件的幽灵账号。现在结算带 flow 身份校验。
|
|
37
|
+
- **修复(审查周期):长时间 agy 工具不再让会话看起来卡死。** ACTIVE 工具信封现在会在推理块输出一次性 `[agy tool running: …]` 进行中注解——十分钟的 maven 构建期间界面有实时进展,而不是只有日志里的 5 分钟心跳。subagent 推理快照改用与 thinking 分支相同的 suffix-delta,不再整段重复;工具切割 span 转发最后一次 per-call 用量样本,不再用硬编码 0/0 在每个工具 hop 重置 DSH 的 token 计量。
|
|
38
|
+
- **修复(审查周期):合成消息过滤不再吞掉用户的真实消息。** 当被嗅探命中的文本是尾随 span 里唯一的用户内容(用户粘贴 `<system-reminder>` 块本身就是要问的问题),桥接现在会转发它,而不是报「request carries no user text」;纯图片轮次依旧不会回捞更早的问题。
|
|
39
|
+
- **修复(审查周期):账号池与数据加固。** `deleteAccount` 只会删除池 baseDir 下的目录(手改 `dir: "~"` 曾会被递归删除);`pool.json` 持久化改为 known-ids 合并,web 与 headless 不再互相清掉对方账号(损坏文件先备份再被默认值覆盖,写盘失败打到 stderr);`/agy add-account` 与 `POST /pool/add` 在登录验证通过前用 `authRequired` 隔离新槽位,调度器无法再把真实 run 路由到没人登录过的账号;额度耗尽但 reset 时间不可解析时按「已耗尽」参与资格判定与轮换,而不是「已重置」。
|
|
40
|
+
- **修复(审查周期):配额 / OAuth 健壮性。** 所有 Google 端点调用默认 10s 超时(挂死的 refresh-token / 配额端点曾让 `/agy refresh-quota` 卡死数分钟);钥匙串 / Secret Service / Windows 凭据管理器读取全部异步化(`execFileSync` 最长 8s 曾在每个轮询周期冻结整个 DSH 事件循环);同账号并发 `getValidAccessToken` 共享一次 in-flight 刷新;配额比例钳制到 [0,1] 并拒绝 NaN;刷新后的 token 文件以 0600 落盘。
|
|
41
|
+
- **修复(审查周期):登录流程生命周期。** URL 等待期间取消会 resolve 挂起的 `begin()`(`/plugins/agy-link/auth` HTTP 路由曾永久挂起);被取代的 `begin()` 不会再覆盖新流程状态;probe/settle 计时器均已清理。
|
|
42
|
+
- **修复(审查周期):agy 会话数据库读取。** 缺 `sqlite3` 或库超大/被锁时,之前每个 step 事件都会重新 spawn 一次 sqlite3 且失败被静默吞掉(缓存仍标记 loaded,风暴永不收敛);现在失败退避(ENOENT 按整个缓存窗口、瞬时失败 300ms)、告警一次、并发读者共享一次 in-flight 加载;DB 拷贝改为私有 `mkdtemp` 目录 + 0600,不再落在可预测的 /tmp 路径。
|
|
43
|
+
- **修复(审查周期):其他。** OAuth 回调页对反射的 `error` 参数做 HTML 转义;Windows `openBrowser` 在拼 cmd 字符串前拒绝含引号/换行的 URL;doctor 脱敏覆盖 `1//0…` refresh token、`AIza…` key 与带凭据的代理 URL,config dump 会抹掉 `proxyUrl` 凭据;`/agy pool` 打印脱敏后的代理;fallback 模型目录每分钟最多重探一次(未登录时不再每次列表调用都 spawn `agy models`);会话 id 兜底发现改为监视池账号隔离 HOME;彻底移除 mermaid 的公网 CDN 回退(应用 origin 内的浮动版本无签名脚本),mermaid/reasoning 的 overlay observer 通过 `ctx.effect` 释放。
|
|
44
|
+
- **新增:token 速度统计。** 每条录制事件现在带到达时间;≥500ms 的分步生成窗口给出 `lastTps` / 按输出加权的 `avgTps` / 输出 token 总量,通过 `/agy status`(「last run tokens: N output tokens — avg X tok/s」)与 `lastRun` 状态载荷暴露。
|
|
45
|
+
- **修复(issue #43):桌面端不再看不到思考过程与工具活动。** 两个叠加原因:(1) 思维正文来自 agy 会话 SQLite 库,而读取器依赖外部 `sqlite3` CLI——桌面/GUI 宿主的 PATH 经常没有它(macOS GUI 应用不继承 shell PATH,Windows 从不自带)。读取器现在优先用 Node 内置的 `node:sqlite`(无需外部二进制),CLI 退居兜底,桌面端也能解析出推理文本。(2) 拿不到正文时高强度轮次此前什么都不渲染;现在首段可见文本之前(以及纯思考轮次)会先流出 `[agy thinking turn · N thinking tokens]` 横幅,DB 正文稍后解析出来时无缝追加——不重复横幅、不丢文本,正文已开始后也不在工具密集步骤上刷屏。
|
|
46
|
+
- **修复(issue #45):Windows 号池凭据无法隔离现在是明确、可见的已知限制。** Windows 上 agy 把登录存进系统级 Credential Manager 的单一槽位 `gemini:antigravity`(go-keyring);HOME 隔离只隔离文件,所有池账号实际仍以系统登录认证与扣额度。插件现在 (1) 在 `/plugins/agy-link/status` 暴露 `credentialIsolationLimited` 并在设置面板渲染警告横幅,(2) Windows 下选中隔离账号时告警一次,(3) 在 KNOWN-GAPS.md 记录边界(以及为何 `maxConcurrent > 1` 时逐 run 的 `CredWrite` 槽位互换不安全)。彻底解决需要上游 agy 改动(按 HOME 命名空间的 keyring,或 keyring 槽位为空时回落文件)。
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
- **修复:卡死 run 的心跳日志不再谎报静默时长。** 当没有未完成的工具步骤时,静默时钟从一个空 map 上的 `Date.now()` 起算,于是每 5 分钟一次的日志永远显示「无新输出 1m」,而 run 实际已经安静了数小时。现在报告的是距最后一条 stdout 行的真实时长(`lastOutputAt`)——这正是用户决定是否按 Stop 时需要的数字。
|
|
50
|
+
- **修复:`agy_tool` 不再把「从未指向过任何步骤的游标」归因为「输出被回收」。** 越界的 step 索引(或非工具事件)与真正被淘汰的录像此前返回同一句「录制输出已不在内存中」——告诉模型输出丢了,而它其实从未被录制过。降级消息现在说明真实原因(「索引在此录像范围之外——尚未录制 / 不是已完成的工具步骤」vs「内存中的录像已被回收」)。
|
|
51
|
+
- **修复:账号故障转移现在真的能续上会话——包括在工具步骤之后(「额度用完、整轮作废」问题)。** DSH 重发失败步骤时,如果失败发生在工具续跑 span 内,消息尾部带着工具结果,于是适配器从**已 settle** 的录像里恢复、把同一个失败原样重放一遍:任何在工具调用之后出现的额度/地区/认证拒绝都会让整轮失败,而旁边还有健康账号闲着(已用 `test/fake-agy.mjs` 离线复现)。现在续跑分支拒绝重放「账号级失败的已 settle 录像」,改为丢弃它并在下一个账号上重新组装——仍在同一步内完成,用户看不到中断。故障转移有界(每会话每 2 分钟最多 `启用账号数 - 1` 次重发),且绝不适用于请求级失败,因此确定性错误不会在账号池里反复重跑用户的工具。
|
|
52
|
+
- **修复:传输形态的「未登录」不再被报成 AUTH(「API 密钥无效」误导)。** agy 对于真正的登出、以及**无法校验** token 的健康登录,都会说「not logged into Antigravity」(线上 2026-10-10 14:17:重试账号的 token 早 9 分钟就过期,刷新死在 `Post https://oauth2.googleapis.com/token: EOF`,同时伴随 TLS 握手超时)。适配器把它归类为 `AUTH`,后果有三:(a) 在健康账号上终止本轮;(b) 把该账号标记为「需重新登录」;(c) 让 DSH 渲染 `message.failure.auth` 文案——「API 密钥无效」——而凭据从来不是问题。现在,只要认证形态的 stdout banner、stderr 或结果信封里出现传输层证据,就会得到可重试的 `NETWORK` 失败:轮换到下一个账号,且绝不隔离任何登录状态。
|
|
53
|
+
- **修复:重试预算跟随账号池,登出也能在另一个账号上继续。** `maxRetries` 原先固定为 1,3 账号池永远到不了第三个账号——而线上事故恰好需要它(主账号 ELIGIBILITY → 第二账号「未登录」→ 整轮丢失,尽管第三个账号健康)。现在预算是 `min(启用账号数 - 1, 2)`;当至少还有一个账号时 `AUTH` 可重试(失败账号被标记 `authRequired` 并退出轮换)。
|
|
54
|
+
- **修复:软容量拒绝改为轮换,而不是直接终止本轮。** 「model overloaded」/「experiencing high traffic」原先归类为确定性 `AGY_ERROR`——终止、不轮换、不重试——于是明明还有别的账号可用,本轮却失败了。现在它们是 `OVERLOADED`:可重试、指针已轮换、且**故意不加冷却**(没有消耗任何额度)。硬额度识别也补上了过去漏掉的真实措辞(`Resource has been exhausted (e.g. check quota).`、`You have exhausted your quota`、`out of quota`、`check quota`)——这些以前会退化成一句「agy exited with code 1」,并且重试仍打在同一个已耗尽账号上。
|
|
55
|
+
- **修复:空闲看门狗不再杀掉「明显还在干活」的 run。** 真实日志一周内 37 次失败里有 12 次正是 `agy run was idle for 600000ms without output`,每次都赔上一轮和一次重发。现在 stderr 也算活跃(agy 会把进度写在 stderr),并且只要 run 产出过任何输出就适用长预算(`longToolIdleMinutes`,默认 240 分钟)——首个事件之前仍用严格的 `timeoutMs`,那才是真正卡死/连不上 Google 的形态。5 分钟心跳也从「仅有未完成工具步骤」扩展为覆盖「安静但存活」的 run,用户能看到它在等,并可以按 Stop。
|
|
56
|
+
- **修复:提示词不再重发当前 agy 会话已有的工具输出,并严格过滤 DSH 合成遥测消息。** 已绑定的会话会把历史工具结果重新塞回 `-p`(线上抓到一条命令行里带着 6.4 KB 的 Godot 模拟输出)——陈旧输出排在真正的问题前面,这正是模型转去回答「上一件事」的原因之一。现在会话已拥有工具输出时不再重发(全新会话仍会带上,因为那时 agy 从未见过)。此外,DSH 在运行时高频注入的 `role: 'user'` 合成遥测消息(如 `time-context` 时间戳、`runtime-context` 上下文快照、`<system-reminder>` 等)现在会被严格过滤,彻底解决时间戳冲掉真实用户任务导致 agy 忽略最新输入的问题;纯图片(无文本)的最新消息也不再回溯拾取旧问题。
|
|
57
|
+
- **修复:被中断的轮次不会再让 agy 回答你打断的那条消息。** DSH 会把 Stop / 插话时的半截回复当作普通 assistant 消息持久化,于是插件把「被打断的用户轮次」当成 agy 原生历史(而 agy 服务端那一轮并没有最终回复)——下一条提示词只有新消息,模型却去回答被打断的那条(线上 `session-c65a826e` 第 17→19 轮,用户原样重问并追问「这个咋不回答呢」)。现在 run 被中断或超时时会在 binding 上标记 `interrupted`,下一条提示词带上明确的「不要继续那件未完成的事」边界,成功一轮后清除该标记。被中断的 run 暂存的图片也不再被记为「已投递」(Stop 之后重发同一张截图会被静默去重,纯图片追问则直接报「request carries no user text or images」)。
|
|
58
|
+
- **修复:已经产出结果的 run 不会再被下一次调用杀掉。** 插话抢占原先会中止一个已经流完答案的进程(记为假的 `ABORTED`,并把 agy 的收尾切断);现在会短暂等待它自然退出,只抢占仍在运行的轮次。有界的 settle 等待在超时时会记录日志,被取代的 run 的迟到回写也无法再回退 `lastMessageCount` / `sentImageIds`。
|
|
59
|
+
- **修复:账号池与会话绑定的健壮性。** 残缺的 `pool.json`(账号缺 `cooldowns`/`quotas`)会让 `selectAccount` 抛 `TypeError`,导致每一轮都以不透明的内部错误失败、且完全没有故障转移——现在加载时会规范化记录。限流不再删除 `(会话, 账号)` 绑定,因此不会为了 15 分钟冷却丢掉一个可续跑的原生会话(只有真正的登出或 agy 侧「conversation not found」才会作废它)。从存活 run 采纳会话 id 时限定为**同一账号**(把账号 A 的 id 用到账号 B 上会产生一次白跑的「conversation not found」)。`sessions.json` 现在真正实现其文档承诺的 dirty-key 合并,web 与 headless 宿主不再互相覆盖绑定。失败的轮次会报告最后一次 per-call 上下文用量,而不是硬编码的 0/0。ADR-012 不再声称「零中断」的平铺回退与 10 分钟冷却。
|
|
60
|
+
|
|
61
|
+
### English (continued)
|
|
62
|
+
|
|
63
|
+
- **Fix: a long-running span can no longer lose its recording to the shared run registry (`no recorded agy run`).** `RunRegistry` kept only the 8 most recently **created** runs (global FIFO across every DSH session). A run whose span waited hours on a wedged agy tool step (e.g. a headless test scene that hit a script error and never quit) was evicted while it was still in flight, and the `agy_tool` mirror call the span had already emitted — `agy_tool({run, step})` — failed with "no recorded agy run", which sent the model off to debug the bridge instead of finishing the user's task (flash-blast incident, 2026-10-10; the same shape recurred on 2026-10-09). The registry now (1) pins a run for the whole lifetime of the span driving it, (2) exempts pinned and unsettled runs from eviction, (3) never evicts the most recent entry, and (4) `remember()` now refreshes recency (delete-then-set) instead of silently keeping the old slot. Spans re-register their recording when they start and when they finish, so the run an `agy_tool` dispatch addresses is always resident, while memory stays bounded by evicting the oldest settled, unpinned run.
|
|
64
|
+
- **Fix: a missing recording now degrades instead of throwing a harness-internal error at the model.** `agy_tool` returning `no recorded agy run` was unrecoverable for the agent: it read the error as an environment fault and spent a whole turn reverse-engineering the plugin bundle (including a stale published copy from the pnpm store). When a run's recording is gone the mirror now returns an explicit, task-facing notice stating that the step did run, that its replay is unavailable, that there is nothing to debug, and that the operation can simply be re-run — then the agent continues its real work.
|
|
65
|
+
- **Add: configurable long-tool idle budget + stuck-tool heartbeat.** The watchdog raise for open tool steps (previously hard-coded to the ≥ 4 h print-mode ceiling) is now `longToolIdleMinutes` / `DSH_AGY_LONG_TOOL_IDLE_MINUTES` (default 240; `0` disables the raise so a wedged tool fails the turn after `timeoutMs` instead of holding the session for hours). While any tool step is open the adapter now logs a heartbeat every 5 minutes (open count + age + budget), so a stalled turn is visible instead of looking like a dead session.
|
|
66
|
+
- **Fix: `toolStepBrief` reads `CommandLine`.** The code-mode/step preview for `run_command` steps showed "run command" whenever agy sent the modern `CommandLine` key; it now shows `$ <command>` like the native card does.
|
|
67
|
+
- **Fix: cross-conversation & cross-account assistant replies are now digested when returning.** In multi-account pool scenarios where turns alternated between accounts, an assistant message emitted under another agy conversation id was previously ignored by `isForeignAssistant` (because `provider` was identically `antigravity`). The returning conversation never saw that intervening answer in its context digest. `isForeignAssistant` now verifies `source.replayState` conversation IDs against the current binding, guaranteeing complete cross-conversation context.
|
|
68
|
+
- **Fix: `forwardSystemPrompt` falls back to `role: 'system'` messages.** When `options.system` is omitted on `GenerateOptions` but system instructions are provided as an explicit system message in the chat history, the prompt now correctly includes the system instructions.
|
|
69
|
+
- **Add: native card presentations for web search, URL fetching, task management, scheduling, and subagents.** Mirrored cards and step previews now cleanly project `search_web`, `read_url_content` / `web_fetch`, `manage_task`, `schedule`, and `invoke_subagent` / `send_message`, avoiding generic raw JSON fallbacks. `TerminalResultView` also extracts process exit codes (`The command exited with code X`) from `run_command` output to render native status pills in DSH terminal cards.
|
|
70
|
+
|
|
71
|
+
### 中文(续)
|
|
72
|
+
|
|
73
|
+
- **修复:长时间运行的 span 不会再因为共享 run 注册表而丢失录像(`no recorded agy run`)。** `RunRegistry` 原先只按**创建顺序**保留最近 8 条 run(跨全部 DSH 会话的全局 FIFO)。当某条 run 的 span 因为 agy 工具步骤卡死(例如无头测试场景脚本报错后不退出)等待数小时,它会在仍在飞行时被淘汰,而该 span 已经排好队的 `agy_tool({run, step})` 镜像调用随即报 "no recorded agy run"——模型据此掉头去调试桥接插件,而不是继续用户的任务(flash-blast 事故,2026-10-10;2026-10-09 出现过同样形态)。现在注册表:(1) 在 span 驱动期间**钉住**该 run;(2) 被钉住与未 settle 的 run 免于淘汰;(3) 永不淘汰最近使用的那一条;(4) `remember()` 改为真正的 `delete` 再 `set`,刷新最近使用顺序而不是原地保留旧位置。span 在启动与结束时都会重新登记自己的录像,因此 `agy_tool` 派发时寻址的 run 必定仍在内存中,同时内存仍通过淘汰「最老的、已 settle 且未钉住」的 run 保持有界。
|
|
74
|
+
- **修复:录像缺失时改为优雅降级,而不是向模型抛桥接内部错误。** `agy_tool` 返回 `no recorded agy run` 对 agent 来说不可恢复:它把该错误理解为环境故障,整轮都在逆向插件产物(还是一份 pnpm store 里的旧发布副本)。现在录像不存在时,镜像工具返回一条明确面向任务的提示:该步骤确实执行过、只是回放不可用、这里没有可调试的东西、需要输出就重跑一次同样的操作——随后 agent 继续原本的工作。
|
|
75
|
+
- **新增:可配置的长工具空闲预算 + 卡死工具心跳。** 未完成工具步骤期间的空闲预算(原先硬编码为 ≥ 4 小时的 print-mode 上限)现在是 `longToolIdleMinutes` / `DSH_AGY_LONG_TOOL_IDLE_MINUTES`(默认 240;设为 `0` 表示不抬高预算,卡死的工具会在 `timeoutMs` 后让本轮失败,而不是把会话挂住数小时)。只要存在未完成的工具步骤,适配器每 5 分钟记录一条心跳(未完成数量 + 最久时长 + 当前预算),让卡住的轮次可见,而不是看起来像会话已死。
|
|
76
|
+
- **修复:`toolStepBrief` 会读取 `CommandLine`。** 当 agy 发送新式 `CommandLine` 键时,`run_command` 步骤的 Code Mode / 预览标题只会显示 "run command";现在与原生卡片一致,显示 `$ <命令>`。
|
|
77
|
+
- **修复:跨会话 / 跨账号的助理回复在切回时现在会被完整消化(跨会话上下文丢失漏洞)。** 在多账号池轮换场景下,当某轮切到备用账号并在新 agy 会话中回答后,切回原账号会话时,由于原先 `isForeignAssistant` 仅比对 `provider !== 'antigravity'`,导致另一会话产出的 assistant 回复被误认为“本机历史”而从补充摘要中剔除,使原会话完全缺失该轮的回答上下文。现在通过对比 `source.replayState` 中的会话 ID,跨会话回复会准确作为外部上下文消化到提示词中。
|
|
78
|
+
- **修复:`forwardSystemPrompt` 在 `options.system` 缺省时自动回退读取 `role: 'system'` 消息。** 当宿主未在选项顶层传入 `options.system`、但在消息历史中携带了系统指示时,提示词现在仍能准确拼接系统指示。
|
|
79
|
+
- **新增:全面支持网页搜索、网页抓取、后台任务管理、定时任务及子 Agent 的原生工具卡片渲染。** 镜像卡片与步骤摘要现已原生支持 `search_web`、`read_url_content` / `web_fetch`、`manage_task`、`schedule` 以及 `invoke_subagent` / `send_message`,避免退化为生硬的 raw JSON;终端卡片 `TerminalResultView` 现在会从 `run_command` 输出中提取真实退出码(`The command exited with code X`),以便 DSH 渲染原生状态药丸。
|
|
80
|
+
|
|
81
|
+
## 0.4.45 (2026-10-10)
|
|
82
|
+
|
|
83
|
+
### English
|
|
84
|
+
|
|
85
|
+
- **Fix (macOS): `ensureIsolatedKeychain` no longer causes modal SecurityAgent password popups on startup (issue #42).** On macOS, `ensureIsolatedKeychain` applied `security set-keychain-settings` on existing isolated keychains on every boot and spawn. When the keychain was locked across app restarts, macOS's SecurityAgent raised blocking GUI dialogs demanding the password for each account — an unanswerable prompt because the isolated keychain was created with an ephemeral random passphrase. The settings (never auto-lock, no timeout) are already persisted on creation, so `ensureIsolatedKeychain` now returns `false` immediately when the keychain file exists on disk, never poking the security CLI again. New keychains are also provisioned with an empty passphrase (`-p ""`) and unlocked upon creation.
|
|
86
|
+
- **Fix: reasoning thinking thoughts arriving asynchronously are no longer dropped (issue #43).** In `EventMapper`, the thinking announcement gate prematurely consumed `thinkingAnnounced` when `thoughtTokens > 0` even before thought prose had finished resolving from the SQLite database. Later fragments or DONE tails carrying the resolved thought prose were subsequently dropped as "already announced". The announcement gate now only marks thoughts as announced when thought text is actually present. In addition, `readStepThoughts` in the adapter now adds a retry interval to accommodate SQLite WAL flush latencies during active model generation.
|
|
87
|
+
- **Fix (Mermaid): prevent "Syntax error in text" bomb SVG from leaking into the document body.** When a code block containing invalid diagram syntax was processed, Mermaid's fallback error-renderer appended a 2412px-wide SVG with a bomb icon directly into `document.body`. Due to an internal throw before cleanup in Mermaid v11, the leaked elements remained permanently attached to the window footer. `mermaid.initialize` now sets `suppressErrorRendering: true`, pre-validates syntax using `api.parse()`, passes a scoped mount container to `api.render()`, unconditionally sweeps temporary and stray elements (`#dagy-mmd*`, `#iagy-mmd*`) in a `finally` block, and injects protective CSS preventing body-level leaked nodes from rendering.
|
|
88
|
+
|
|
89
|
+
### 中文 (Chinese)
|
|
90
|
+
|
|
91
|
+
- **修复 (macOS):`ensureIsolatedKeychain` 不再在每次启动时触发 SecurityAgent 钥匙串密码弹窗(issue #42)。** 在 macOS 上,`ensureIsolatedKeychain` 原先在每次 DSH 启动和进程拉起时都会对已存在的隔离钥匙串执行 `security set-keychain-settings`。当钥匙串在应用重启后处于锁定状态时,macOS 的 SecurityAgent 会对每个隔离账号弹出阻塞式系统密码框——由于此前钥匙串是使用未持久化的随机密码创建的,用户输入任何密码都无法通过。钥匙串的“永不自动锁”设置在首次创建时已持久化落盘,因此当钥匙串文件已存在时,`ensureIsolatedKeychain` 现在直接返回 `false`,绝不再调用 security CLI;新建钥匙串时也改用空密码(`-p ""`)创建并立即静默解锁。
|
|
92
|
+
- **修复:异步从数据库解析的思考过程正文不再被静默丢弃(issue #43)。** 在 `EventMapper` 中,思考公布逻辑原先只要检测到 `thoughtTokens > 0`,即使 SQLite 中的思考正文尚未完成异步提取,也会过早消耗 `thinkingAnnounced` 标记,导致后续分片或 DONE 尾包即使成功提取到了思考正文也被判定为“已公布”而直接丢弃。现在公布标记仅在实际存在思考正文时才消耗;同时适配器中的 `readStepThoughts` 增加了重试等待,以包容模型生成期间 SQLite WAL 写入的延迟。
|
|
93
|
+
- **修复 (Mermaid):彻底解决 Mermaid 语法错误导致巨大的“Syntax error in text”炸弹图标残留在窗口底部的问题。** 当代码块包含不合法的图表语法时,Mermaid 内部的兜底错误渲染逻辑会向 `document.body` 追加一个 2412px 宽的巨大炸弹图标(💣)SVG;由于 Mermaid v11 在内部抛错前未执行清理,该临时元素会永久留在窗口底部污染界面。现在初始化时开启了 `suppressErrorRendering: true`,在渲染前通过 `api.parse()` 预校验语法,向 `api.render()` 传入局部挂载容器,在 `finally` 块中无条件清理临时节点(`#dagy-mmd*`、`#iagy-mmd*`),并通过安全 CSS 全面隐藏逃逸到 body 层级的任何错误元素。
|
|
94
|
+
|
|
95
|
+
## 0.4.44 (2026-10-09)
|
|
96
|
+
|
|
97
|
+
### English
|
|
98
|
+
|
|
99
|
+
- **Fix: a conversation stalled on a tool step no longer dead-ends after a host restart.** Continuation spans resolve their run from an **in-memory** `RunRegistry`; after DSH restarts (or the run is evicted) the recording is gone, and `stream()` used to fail that turn — and every retry of it — with "agy run … is no longer available (server restarted?) — please resend your message", an advice that could never succeed because the stale tool result stays at the end of the message list. The adapter now logs a warning and falls back to fresh-turn prompt assembly instead: the history digest carries the recorded tool result, and the session's `sessions.json` binding still points at the same agy conversation, so the next turn heals the conversation with no user action. Related hardening in the same change: (1) the `agy_tool` mirror now bypasses DSH's auto-review / permission gates via a `tools/pre-execute` hook (it only replays output agy already executed — routing it through the reviewer caused redundant review LLM calls, timeouts, and crashes on reviewer tool-call endings); (2) review-mode calls (`REVIEW_POLICY` system prompt) and calls with explicit `tools: []` are treated as auxiliary and never cut spans on tools; (3) on Windows, `.mjs`/`.js`/`.cjs` bins are spawned via `process.execPath` instead of failing with `EFTYPE` (this also makes the full test suite pass natively on Windows — the 33 pre-existing platform failures are gone). (PR #40)
|
|
100
|
+
- **Add: hide models from the DSH model picker (`hiddenModels`).** The Antigravity settings section (below account-pool scheduling) now renders a "Model visibility" row with one toggle per known model: hidden models disappear from the `/model` picker, everything else stays visible (deny-list semantics, so newly discovered models appear by default). Hiding is picker-only by design — `resolveModel` still accepts hidden ids, so in-flight sessions and direct model references keep working, and no catalog-cache invalidation is needed. The list is served from `/status` (`catalogModels` + `hiddenModels`) through the same sanitizer that feeds `listModels`, so the UI and the picker can never disagree; writes go through the existing `POST /config` allowlist (validated as an array of model ids) and persist to the runtime-overrides file immediately. `DSH_AGY_HIDDEN_MODELS` (comma-separated) also works as an env fallback. The plugin now also emits the payload-free `llm/adapters-updated` event whenever picker output can change (`hiddenModels` writes, boot-probe discovery, re-login, manual quota refresh) — the webview picker caches its catalog snapshot and only re-reads after that event, so without it toggles would not show up until the next app restart. (PR #39)
|
|
101
|
+
- **Fix: the Windows node-shim spawn merged from #40 now really runs the script instead of booting a second app instance.** `process.execPath` is the Electron binary in the packaged desktop host, so the `isNode` branch now sets `ELECTRON_RUN_AS_NODE=1`; plain node ignores the variable, so POSIX and the test suite are unaffected.
|
|
102
|
+
|
|
103
|
+
### 中文 (Chinese)
|
|
104
|
+
|
|
105
|
+
- **修复:停在工具步骤上的会话在宿主重启后不再进入死胡同。** 续接 span 依赖的 run 录像存放在**纯内存**的 `RunRegistry` 里;DSH 重启(或录像被淘汰)后录像即消失,`stream()` 会让该轮失败——而且每次重试都失败,报 "agy run … is no longer available (server restarted?) — please resend your message"。这个"请重发消息"的建议永远不可能成功:失效的工具结果始终钉在消息列表末尾,续接检测每轮都命中同一个 runId。现在适配器会记录一条警告并**回退到全新轮次的 prompt 组装**:历史 digest 携带已记录的工具结果,会话在 `sessions.json` 里的 conversation 绑定仍指向同一个 agy 会话,下一轮即自动自愈,无需用户做任何事。同一批提交中的相关加固:(1) `agy_tool` 镜像现在通过 `tools/pre-execute` 钩子绕过 DSH 的 auto-review / 权限门(它只是重放 agy 已经执行过的输出——送审会导致重复审查 LLM 调用、审查超时,以及审查员以 tool-calls 结尾时的崩溃);(2) 审查模式调用(`REVIEW_POLICY` 系统提示)与显式 `tools: []` 的调用按辅助调用对待,不再在工具步骤上切分 span;(3) Windows 下 `.mjs`/`.js`/`.cjs` 形式的 bin 改为经 `process.execPath` 启动,不再触发 `EFTYPE`(这也让整个测试套件在 Windows 上原生全绿——33 个既有平台失败清零)。(PR #40)
|
|
106
|
+
- **新增:在 DSH 模型选择器中隐藏指定模型(`hiddenModels`)。** Antigravity 设置区(号池调度下方)新增"模型显示"一行,每个已知模型一个开关:关闭的模型从 `/model` 选择器中消失,其余照常显示(黑名单语义——新发现的模型默认可见)。隐藏只作用于选择器:`resolveModel` 仍接受被隐藏的模型 id,进行中的会话与直接引用不受影响,也无需清空模型目录缓存。模型列表由 `/status`(`catalogModels` + `hiddenModels`)提供,与 `listModels` 共用同一清洗逻辑,UI 与选择器永远不会不一致;写入走现有 `POST /config` 白名单(校验必须是模型 id 数组),立即持久化到 runtime-overrides 文件。环境变量 `DSH_AGY_HIDDEN_MODELS`(逗号分隔)亦可作为回退。插件现在会在所有会影响选择器输出的时机发出无负载的 `llm/adapters-updated` 事件(`hiddenModels` 写入、启动探测发现模型、重新登录、手动刷新额度)——webview 的模型选择器缓存目录快照、只在该事件后重读,缺少它时开关要到下次重启应用才会生效。(PR #39)
|
|
107
|
+
- **修复:合入自 #40 的 Windows node 脚本启动现在真正执行脚本,而不是再启动一个 App 实例。** 打包桌面端里 `process.execPath` 是 Electron 二进制,因此 `isNode` 分支现在会设置 `ELECTRON_RUN_AS_NODE=1`;纯 node 会忽略该变量,POSIX 与测试不受影响。
|
|
108
|
+
|
|
3
109
|
## 0.4.43 (2026-10-06)
|
|
4
110
|
|
|
5
111
|
### English
|
|
6
112
|
|
|
113
|
+
|
|
7
114
|
- **Fix (Windows): Chinese tool output is no longer mangled (issue #37).** Windows pipes carry bytes in the child's console code page: on a zh-CN system agy captures pwsh output as CP936 (GBK), and the plugin decoded every stream as UTF-8 — so the Chinese refusal text arrived as mojibake, and because that text is what agy stores in its conversation database the damage was permanent. stdout/stderr are now read as raw bytes and decoded **per line** through the console code page (`chcp` probe → GBK/Big5/Shift_JIS/EUC-KR/Windows-125x), falling back to UTF-8 whenever a line is valid UTF-8; POSIX behaviour is bit-for-bit unchanged (the probe returns `utf-8`). Lines — not chunks — are the decoding unit because a multi-byte character can straddle a chunk boundary but never a newline.
|
|
8
115
|
- **Fix: `dsh plugin add git+https://…` installs now build the plugin (issue #38).** `dist/` is not committed and only `prepack` existed, which never runs for git dependencies — so a hub/git install produced a package without `dist/` and failed to load. A `prepare` script now builds on git installs (npm/pnpm install devDependencies for git deps first); npm consumers are unaffected because `prepare` does not run for published tarballs. The install also aborted **earlier** than that: `@deepseek-ai/dsh-client-locale` was declared as a **non-optional** peer, so npm's automatic peer installation tried to fetch the unpublished `@deepseek-ai/dsh-paths@^0.0.1-rc.1` chain from the public registry and failed with a 404 — every `@deepseek-ai/*` peer is now optional (the host provides them at runtime and the bundle keeps them external), matching how third-party DSH plugins declare theirs.
|
|
9
116
|
- **Fix: the live "User location is not supported for the API use" refusal is now recognized, explained and routed around.** agy exits 3 with a `FAILED_PRECONDITION (code 400)` result envelope for this refusal, but the classifier only knew the older issue-#32 wording — so it surfaced as a bare `PROCESS_EXIT`, the sticky account never moved, and every retry hit the same unsupported location (hence the recurring failure). The signature is now matched, the failure carries a dedicated, retryable `ELIGIBILITY` code plus the actionable hint, and the refused account is rotated off the sticky pointer before the error surfaces (no cooldown penalty) — the automatic retry is then served by an account whose own proxy/egress region is supported.
|
|
@@ -17,6 +124,7 @@
|
|
|
17
124
|
|
|
18
125
|
### 中文 (Chinese)
|
|
19
126
|
|
|
127
|
+
|
|
20
128
|
- **修复(Windows):中文工具输出不再乱码(issue #37)。** Windows 管道里的字节使用**子进程的控制台代码页**:中文系统上 agy 捕获到的 pwsh 输出是 CP936(GBK),而插件把整条流按 UTF-8 解码——中文报错于是变成乱码;又因为这段文本正是 agy 写入会话库的内容,损坏不可追回。现在 stdout/stderr 以**原始字节**读取并按**行**用控制台代码页解码(`chcp` 探测 → GBK/Big5/Shift_JIS/EUC-KR/Windows-125x),凡是合法的 UTF-8 行仍按 UTF-8 处理;POSIX 行为逐字节不变(探测直接返回 `utf-8`)。以「行」而非「块」为解码单位,是因为多字节字符可能跨块但绝不会跨换行。
|
|
21
129
|
- **修复:`dsh plugin add git+https://…` 安装现在会构建插件(issue #38)。** 仓库里没有提交 `dist/`,而只有 `prepack`——它**不会**在 git 依赖安装时执行,所以市场/git 安装得到的包没有 `dist/`,加载失败。现在新增 `prepare` 脚本,git 安装时会构建(npm/pnpm 会先为 git 依赖安装 devDependencies);从 npm 安装的用户不受影响,因为 `prepare` 不会对已发布的 tarball 执行。安装其实在更早一步就已经失败:`@deepseek-ai/dsh-client-locale` 曾被声明为**非可选** peer,npm 的自动 peer 安装因此去公共 registry 拉取未发布的 `@deepseek-ai/dsh-paths@^0.0.1-rc.1` 依赖链并报 404 —— 现在所有 `@deepseek-ai/*` peer 都标为 optional(运行时由宿主提供,打包时保持 external),与第三方 DSH 插件的声明方式一致。
|
|
22
130
|
- **修复:线上「User location is not supported for the API use」区域拒绝现在被正确识别、解释并绕开。** 该拒绝报文是 agy 以退出码 3 + `FAILED_PRECONDITION (code 400)` 结果信封抛出的,而分类器只认得 issue #32 时期的旧措辞——于是它被当成裸 `PROCESS_EXIT`,粘性账号也不会移动,每次重试都撞同一个不支持的地区,所以你会觉得"总是出现这个问题"。现在该签名已被匹配,失败会带专用且**可重试**的 `ELIGIBILITY` 错误码与可操作提示,同时在错误抛出前把被拒账号从粘性指针上换掉(**不扣冷却**),自动重试就会落到代理/出口地区受支持的账号上。
|
package/README.md
CHANGED
|
@@ -133,7 +133,9 @@ dsh plugin --profile web add dsh-agy-link
|
|
|
133
133
|
| `permissionMode` | `DSH_AGY_MODE` | `skip` | 权限模式:`skip`(无人值守执行)/ `plan` / `accept-edits` |
|
|
134
134
|
| `defaultModel` | `DSH_AGY_DEFAULT_MODEL` | `(agy 默认)` | 默认模型 slug |
|
|
135
135
|
| `defaultEffort` | `DSH_AGY_DEFAULT_EFFORT` | `(模型默认)` | 思考预算:`low` / `medium` / `high` |
|
|
136
|
+
| `hiddenModels` | `DSH_AGY_HIDDEN_MODELS` | `[]` | 在 `/model` 选择器中隐藏的模型 slug 列表(黑名单语义,新模型默认可见;建议直接在设置面板"模型显示"中点选管理) |
|
|
136
137
|
| `timeoutMs` | `DSH_AGY_TIMEOUT_MS` | `600000` | 单轮活跃看门狗超时(毫秒) |
|
|
138
|
+
| `longToolIdleMinutes` | `DSH_AGY_LONG_TOOL_IDLE_MINUTES` | `240` | 存在未完成工具步骤(ACTIVE)时的空闲预算(分钟);`0` = 不抬高预算,卡死的工具按 `timeoutMs` 快速失败 |
|
|
137
139
|
| `workspaceRoot` | `DSH_AGY_WORKSPACE_ROOT` | 会话 cwd | agy 工作区根目录(默认跟随当前会话工作区) |
|
|
138
140
|
|
|
139
141
|
---
|
|
@@ -269,6 +271,7 @@ dsh plugin --profile web add dsh-agy-link
|
|
|
269
271
|
| `permissionMode` | `DSH_AGY_MODE` | `skip` | `skip` (unattended execution) / `plan` / `accept-edits` |
|
|
270
272
|
| `defaultModel` | `DSH_AGY_DEFAULT_MODEL` | `(agy default)` | Default model slug |
|
|
271
273
|
| `defaultEffort` | `DSH_AGY_DEFAULT_EFFORT` | `(model default)` | Thinking budget: `low` / `medium` / `high` |
|
|
274
|
+
| `hiddenModels` | `DSH_AGY_HIDDEN_MODELS` | `[]` | Model slugs hidden from the `/model` picker (deny-list, newly discovered models stay visible; manage them via the "Model visibility" row in the settings panel) |
|
|
272
275
|
| `timeoutMs` | `DSH_AGY_TIMEOUT_MS` | `600000` | Activity watchdog timeout in milliseconds |
|
|
273
276
|
| `workspaceRoot` | `DSH_AGY_WORKSPACE_ROOT` | session cwd | Working directory root |
|
|
274
277
|
|