dsh-client-auto-continue 0.9.0 → 0.10.1
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/README.md +20 -15
- package/README.zh.md +11 -6
- package/lib/client.js +71 -38
- package/lib/client.js.map +3 -3
- package/lib/index.js +101 -32
- package/lib/types/client/locales.d.ts +5 -5
- package/lib/types/host/engine.d.ts +1 -0
- package/lib/types/index.d.ts +5 -1
- package/lib/types/shared/core.d.ts +22 -1
- package/package.json +2 -2
- package/src/client/index.ts +12 -1
- package/src/client/locales.ts +12 -1
- package/src/client/settings-card.tsx +6 -6
- package/src/host/engine.ts +68 -16
- package/src/index.ts +24 -6
- package/src/shared/core.ts +37 -11
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<h1 align="center">dsh-auto-continue</h1>
|
|
9
9
|
|
|
10
10
|
<p align="center">
|
|
11
|
-
<em>DSH Web UI plugin — when a request is interrupted by a network error or any other non-human cause, it automatically
|
|
11
|
+
<em>DSH Web UI plugin — when a request is interrupted by a network error or any other non-human cause, it automatically sends “Continue” for you.</em>
|
|
12
12
|
</p>
|
|
13
13
|
|
|
14
14
|
<p align="center">
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
<a href="https://github.com/HsiangNianian/dsh-auto-continue/stargazers"><img src="https://img.shields.io/github/stars/HsiangNianian/dsh-auto-continue?logo=github&label=Stars" alt="GitHub stars"></a>
|
|
18
18
|
<a href="https://github.com/HsiangNianian/dsh-auto-continue/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-65a30d?style=flat" alt="MIT license"></a>
|
|
19
19
|
<a href="https://awesome-dsh-plugin.com"><img src="https://awesome-dsh-plugin.com/badge.svg" alt="awesome · DSH plugin"></a>
|
|
20
|
+
<a href="https://www.dsh.so/artifact/dsh-auto-continue/"><img src="https://www.dsh.so/badge/install/dsh-auto-continue.svg" alt="dsh.so install"></a>
|
|
20
21
|
<br>
|
|
21
22
|
<img src="https://img.shields.io/badge/TypeScript-3178C6?style=flat&logo=typescript&logoColor=fff" alt="TypeScript">
|
|
22
23
|
<img src="https://img.shields.io/badge/esbuild-FFCF00?style=flat&logo=esbuild&logoColor=000" alt="esbuild">
|
|
@@ -31,7 +32,7 @@
|
|
|
31
32
|
|
|
32
33
|
## What It Does
|
|
33
34
|
|
|
34
|
-
For [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (`dsh web`): whenever a request in the web GUI gets interrupted by a **non-human cause**, the plugin simulates the user typing
|
|
35
|
+
For [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (`dsh web`): whenever a request in the web GUI gets interrupted by a **non-human cause**, the plugin simulates the user typing **“Continue”** and sends it, so the agent keeps working without manual intervention. The message enters the session log exactly like a manual prompt — the model sees it, and the interrupted work resumes. Since 0.8.0 the engine runs **inside the host process** (single instance), so it keeps watching even with every browser tab closed, and multiple open tabs can never double-send.
|
|
35
36
|
|
|
36
37
|

|
|
37
38
|
|
|
@@ -39,7 +40,8 @@ For [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (`dsh we
|
|
|
39
40
|
|
|
40
41
|
- **Error classification** — transient failures (network / timeout / 5xx / 429…) are auto-resumed; permanent ones are **skipped** and notified, because retrying them never helps. A failure counts as permanent when its HTTP status is 401/403 or its code/message matches auth, credential/API-key, balance/quota, unknown-model, or context-length/overflow keywords. Provider-specific exceptions can be opted into with literal custom retryable patterns; turn classification off to resume everything
|
|
41
42
|
- **Adaptive backoff** — consecutive failures wait longer each time (cooldown × factor: 20s → 40s → 80s…), capped at the max backoff, instead of hammering a broken upstream
|
|
42
|
-
- **
|
|
43
|
+
- **English / Chinese localization** — the settings card, built-in resume / guard / loop text, and browser notifications follow DSH's active UI language (initially selected from the browser language). Only `en` and `zh` are supported; other languages fall back to Chinese. Switching languages updates built-in defaults without overwriting custom text
|
|
44
|
+
- **Templated continue text** — `continueText` supports `{code}` `{message}` `{status}` `{tool}` `{turn}` `{errorCount}` `{sessionTitle}` `{elapsed}` placeholders, so the resume message can carry the failure context ("Continue ({tool} failed: {code})"); a **separate template** fires on `max-tokens` (e.g. "Continue the output without repeating anything already generated")
|
|
43
45
|
- **Idempotency guard** — before resuming, the plugin inspects the last tool call: if its result is unconfirmed (the turn died mid-tool, e.g. a `git push` that may have gone through), the resume message tells the model to check state first and not to rerun; if the tool is confirmed done, it says so and asks not to repeat it; a failed tool gets no guard (retrying it is the point). Both guard texts are configurable (`{tool}` / `{result}` placeholders)
|
|
44
46
|
- **Pause** — a global **Pause auto-continue** toggle in the settings card stops everything (live + scan) instantly; per-session pauses (e.g. via a notification button) suspend only one session until they expire. The **Resume now** notification button is the one explicit exception: pressing it is the user asking for exactly one send, pause or not
|
|
45
47
|
- **Notification buttons** — notifications carry **Resume now** (send immediately, ignoring cooldown, the consecutive cap and any pause) and **Pause this session 1h** actions
|
|
@@ -146,16 +148,19 @@ dsh web
|
|
|
146
148
|
|
|
147
149
|
Everything is configurable from the GUI — no file or console edits needed. Open **Settings → Plugins** and find the **dsh-client-auto-continue** configuration card, right where every other plugin's config lives. Besides the fields below, the card shows a live **stats panel** (today's activity with a reset button) and the list of **paused sessions** (each with a per-session resume button).
|
|
148
150
|
|
|
149
|
-
**Or skip the GUI and edit the config file directly** — the engine reads the plugin's section from `~/.dsh/settings.yaml` (one shared file for every plugin's sections), so this works in any install, patched or not. The file is watched and re-read automatically, so changes apply live; restart `dsh web` if a page that was already open doesn't pick them up. Fields you leave out fall back to the defaults in the table below
|
|
151
|
+
**Or skip the GUI and edit the config file directly** — the engine reads the plugin's section from `~/.dsh/settings.yaml` (one shared file for every plugin's sections), so this works in any install, patched or not. The file is watched and re-read automatically, so changes apply live; restart `dsh web` if a page that was already open doesn't pick them up. Fields you leave out fall back to the defaults in the table below.
|
|
152
|
+
|
|
153
|
+
The browser mirrors DSH's active language into the internal `locale` field. Leave the five localized text fields empty or omit them to follow that language automatically; any non-empty value is treated as your own template and is never rewritten when the language changes:
|
|
150
154
|
|
|
151
155
|
```yaml
|
|
152
156
|
auto-continue:
|
|
157
|
+
locale: 'en' # normally managed by the browser
|
|
153
158
|
paused: false
|
|
154
|
-
continueText: '
|
|
155
|
-
continueTextMaxTokens: '
|
|
159
|
+
continueText: ''
|
|
160
|
+
continueTextMaxTokens: ''
|
|
156
161
|
guardTools: true
|
|
157
|
-
guardPendingText: '
|
|
158
|
-
guardDoneText: '
|
|
162
|
+
guardPendingText: ''
|
|
163
|
+
guardDoneText: ''
|
|
159
164
|
graceMs: 3000
|
|
160
165
|
cooldownMs: 20000
|
|
161
166
|
maxConsecutive: 3
|
|
@@ -174,7 +179,7 @@ auto-continue:
|
|
|
174
179
|
loopShortCount: 12
|
|
175
180
|
loopRepeatText: 4
|
|
176
181
|
loopToolRepeat: 5
|
|
177
|
-
loopText: '
|
|
182
|
+
loopText: ''
|
|
178
183
|
```
|
|
179
184
|
|
|
180
185
|
**How the card works:**
|
|
@@ -191,8 +196,8 @@ auto-continue:
|
|
|
191
196
|
| Field | Default | Description |
|
|
192
197
|
| --- | --- | --- |
|
|
193
198
|
| Pause auto-continue | `off` | Global pause: no live or scan auto-send fires, queued pending sends are cancelled |
|
|
194
|
-
| Continue text |
|
|
195
|
-
| Continue text (max tokens) |
|
|
199
|
+
| Continue text | `Continue` | Text automatically sent after an interruption |
|
|
200
|
+
| Continue text (max tokens) | `Continue` | Text sent when the output token ceiling is reached (same placeholders) |
|
|
196
201
|
| Idempotency guard | `on` | Inspect the last tool call before resuming and steer the model (see What It Does) |
|
|
197
202
|
| Loop guard | `on` | Detect a running turn spinning in place and restart it (see What It Does) |
|
|
198
203
|
| Short-sentence max (chars) | `40` | A model message shorter than this counts as a short sentence (spinning signal) |
|
|
@@ -200,9 +205,9 @@ auto-continue:
|
|
|
200
205
|
| Short-sentence threshold | `12` | Consecutive short sentences inside the window, with no tool call in between, trip the loop guard |
|
|
201
206
|
| Identical message count | `4` | Consecutive identical messages (any length) trip the loop guard — the strongest spinning signal |
|
|
202
207
|
| Same-tool repeat count | `5` | Consecutive calls of the same tool with identical arguments and results trip the loop guard |
|
|
203
|
-
| Loop text | `(
|
|
204
|
-
| Guard text (unconfirmed result) | `(
|
|
205
|
-
| Guard text (tool succeeded) | `(
|
|
208
|
+
| Loop text | `(You may be stuck in a loop. Stop repeating the last action and continue with a different approach.)` | Text sent after the loop guard restarts a turn; `{tool}` placeholder |
|
|
209
|
+
| Guard text (unconfirmed result) | `(The previous tool "{tool}" may not have completed. Check its state before continuing and do not run it again.)` | Appended when the last tool may have partially executed; `{tool}` placeholder |
|
|
210
|
+
| Guard text (tool succeeded) | `(The previous tool "{tool}" completed successfully. Result: {result}; do not run it again. Continue from there.)` | Appended when the last tool is confirmed done; `{tool}` / `{result}` placeholders |
|
|
206
211
|
| Grace period (ms) | `3000` | Wait after an interruption; cancelled if the host recovers on its own |
|
|
207
212
|
| Cooldown (ms) | `20000` | Min interval between auto-continues per session (failed attempts count too) |
|
|
208
213
|
| Max consecutive | `3` | Max consecutive auto-continues; stops until a user intervenes or a turn completes |
|
|
@@ -226,7 +231,7 @@ auto-continue:
|
|
|
226
231
|
|
|
227
232
|
Patterns are literal substrings, not regular expressions. Blank lines are ignored; any matching line wins before the built-in permanent-error rules. Cooldown and consecutive-attempt limits still apply.
|
|
228
233
|
|
|
229
|
-
`continueText` (and `continueTextMaxTokens`) accept the placeholders `{code}`, `{message}`, `{status}`, `{tool}` (last tool call before the failure), `{turn}`, `{errorCount}` (consecutive failures including this one), `{sessionTitle}` (from the session list) and `{elapsed}` (time since the failure, e.g. `1m5s`) — e.g.
|
|
234
|
+
`continueText` (and `continueTextMaxTokens`) accept the placeholders `{code}`, `{message}`, `{status}`, `{tool}` (last tool call before the failure), `{turn}`, `{errorCount}` (consecutive failures including this one), `{sessionTitle}` (from the session list) and `{elapsed}` (time since the failure, e.g. `1m5s`) — e.g. `Continue ({tool}: {code})` becomes `Continue (git push: UPSTREAM)`. The guard texts accept `{tool}` and `{result}` (a truncated excerpt of the last tool output).
|
|
230
235
|
|
|
231
236
|
---
|
|
232
237
|
|
package/README.zh.md
CHANGED
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
<a href="https://github.com/HsiangNianian/dsh-auto-continue/stargazers"><img src="https://img.shields.io/github/stars/HsiangNianian/dsh-auto-continue?logo=github&label=Stars" alt="GitHub stars"></a>
|
|
18
18
|
<a href="https://github.com/HsiangNianian/dsh-auto-continue/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-65a30d?style=flat" alt="MIT license"></a>
|
|
19
19
|
<a href="https://awesome-dsh-plugin.com"><img src="https://awesome-dsh-plugin.com/badge.svg" alt="awesome · DSH plugin"></a>
|
|
20
|
+
<a href="https://www.dsh.so/artifact/dsh-auto-continue/"><img src="https://www.dsh.so/badge/install/dsh-auto-continue.svg" alt="dsh.so install"></a>
|
|
20
21
|
<br>
|
|
21
22
|
<img src="https://img.shields.io/badge/TypeScript-3178C6?style=flat&logo=typescript&logoColor=fff" alt="TypeScript">
|
|
22
23
|
<img src="https://img.shields.io/badge/esbuild-FFCF00?style=flat&logo=esbuild&logoColor=000" alt="esbuild">
|
|
@@ -39,6 +40,7 @@
|
|
|
39
40
|
|
|
40
41
|
- **错误分类** — 临时性错误(网络 / 超时 / 5xx / 429 等)自动续跑; 永久性错误跳过并通知, 因为重试也没用。判定为永久性的条件: HTTP 状态码 401/403, 或 code/message 命中认证、凭据/API Key、余额/配额、模型不存在、上下文长度/超限等关键词。provider 专属例外可由用户显式填写普通文本匹配; 关闭分类后则全部自动继续
|
|
41
42
|
- **自适应退避** — 连续失败时等待时间递增(冷却 × 系数: 20s → 40s → 80s…), 有上限, 不再对故障上游狂轰滥炸
|
|
43
|
+
- **中英文本地化** — 设置卡片、内置续跑 / 护栏 / 循环文案以及浏览器通知都跟随 DSH 当前界面语言(初始值来自浏览器语言)。只支持 `en` 和 `zh`, 其他语言回落中文; 切换语言只会替换内置默认值, 不会覆盖用户自定义文本
|
|
42
44
|
- **模板化继续文本** — `continueText` 支持 `{code}` `{message}` `{status}` `{tool}` `{turn}` `{errorCount}` `{sessionTitle}` `{elapsed}` 占位符, 续跑消息可携带失败上下文(如「继续 (git push 失败: UPSTREAM)」); 达到 `max-tokens` 时使用**另一套模板**(如「继续输出, 不要重复已生成的内容」)
|
|
43
45
|
- **幂等护栏** — 续跑前检查上一步工具调用: 结果未确认(回合在工具执行中途夭折, 如 `git push` 可能已经推上去了)时, 续跑消息会提示模型先确认状态、不要重复执行; 工具已确认成功时说明已完成、请勿重复; 工具失败则不加护栏(重试本来就是目的)。两段护栏文本都可配置(支持 `{tool}` / `{result}` 占位符)
|
|
44
46
|
- **暂停** — 设置卡片里的全局 **暂停自动继续** 开关可立即停掉一切(实时 + 扫描); 会话级暂停(如通过通知按钮)只挂起单个会话, 到期自动恢复。唯一的显式例外是通知里的 **立即续跑** 按钮——按下它等于用户明确要求发送这一次, 不受暂停限制
|
|
@@ -146,16 +148,19 @@ dsh web
|
|
|
146
148
|
|
|
147
149
|
所有参数都可以在 GUI 里配置——无需改文件或控制台。打开 **设置 → 插件**, 找到 **dsh-client-auto-continue** 的配置卡片, 和其他插件的配置放在一起。除了下面的字段, 卡片还带一个**统计面板**(今日活动, 可一键清零)和**已暂停会话**列表(每个都可单独解除)。
|
|
148
150
|
|
|
149
|
-
**或者跳过 GUI, 直接编辑配置文件** — 引擎从 `~/.dsh/settings.yaml` 读取插件段落(所有插件的设置都在这一个文件里), 因此无论是否打过补丁都能用。文件被监听、自动重读, 改动即时生效; 若已打开的页面没反应, 重启 `dsh web`
|
|
151
|
+
**或者跳过 GUI, 直接编辑配置文件** — 引擎从 `~/.dsh/settings.yaml` 读取插件段落(所有插件的设置都在这一个文件里), 因此无论是否打过补丁都能用。文件被监听、自动重读, 改动即时生效; 若已打开的页面没反应, 重启 `dsh web` 即可。没填写的字段会回落到下表中的默认值。
|
|
152
|
+
|
|
153
|
+
浏览器会把 DSH 当前语言同步到内部 `locale` 字段。下面五个本地化文本字段保持留空或直接省略时, 会自动跟随语言; 任何非空值都视为用户自己的模板, 切换语言时不会改写:
|
|
150
154
|
|
|
151
155
|
```yaml
|
|
152
156
|
auto-continue:
|
|
157
|
+
locale: 'zh' # 通常由浏览器自动维护
|
|
153
158
|
paused: false
|
|
154
|
-
continueText: '
|
|
155
|
-
continueTextMaxTokens: '
|
|
159
|
+
continueText: ''
|
|
160
|
+
continueTextMaxTokens: ''
|
|
156
161
|
guardTools: true
|
|
157
|
-
guardPendingText: '
|
|
158
|
-
guardDoneText: '
|
|
162
|
+
guardPendingText: ''
|
|
163
|
+
guardDoneText: ''
|
|
159
164
|
graceMs: 3000
|
|
160
165
|
cooldownMs: 20000
|
|
161
166
|
maxConsecutive: 3
|
|
@@ -174,7 +179,7 @@ auto-continue:
|
|
|
174
179
|
loopShortCount: 12
|
|
175
180
|
loopRepeatText: 4
|
|
176
181
|
loopToolRepeat: 5
|
|
177
|
-
loopText: '
|
|
182
|
+
loopText: ''
|
|
178
183
|
```
|
|
179
184
|
|
|
180
185
|
**卡片操作说明:**
|
package/lib/client.js
CHANGED
|
@@ -35,6 +35,50 @@ __export(index_exports, {
|
|
|
35
35
|
});
|
|
36
36
|
module.exports = __toCommonJS(index_exports);
|
|
37
37
|
|
|
38
|
+
// src/shared/core.ts
|
|
39
|
+
var LOCALIZED_TEXT_DEFAULTS = {
|
|
40
|
+
zh: {
|
|
41
|
+
continueText: "继续",
|
|
42
|
+
continueTextMaxTokens: "继续",
|
|
43
|
+
guardPendingText: "(上一步工具「{tool}」可能未完成, 先确认状态再继续, 不要重复执行)",
|
|
44
|
+
guardDoneText: "(上一步工具「{tool}」已完成, 结果: {result}; 不要重复执行, 直接继续)",
|
|
45
|
+
loopText: "(检测到你可能陷入循环, 请停止重复刚才的动作, 换一种方式继续)"
|
|
46
|
+
},
|
|
47
|
+
en: {
|
|
48
|
+
continueText: "Continue",
|
|
49
|
+
continueTextMaxTokens: "Continue",
|
|
50
|
+
guardPendingText: '(The previous tool "{tool}" may not have completed. Check its state before continuing and do not run it again.)',
|
|
51
|
+
guardDoneText: '(The previous tool "{tool}" completed successfully. Result: {result}; do not run it again. Continue from there.)',
|
|
52
|
+
loopText: "(You may be stuck in a loop. Stop repeating the last action and continue with a different approach.)"
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
var DEFAULT_CONFIG = {
|
|
56
|
+
locale: "zh",
|
|
57
|
+
...LOCALIZED_TEXT_DEFAULTS.zh,
|
|
58
|
+
guardTools: true,
|
|
59
|
+
graceMs: 3e3,
|
|
60
|
+
cooldownMs: 2e4,
|
|
61
|
+
maxConsecutive: 3,
|
|
62
|
+
scanOnBoot: true,
|
|
63
|
+
scanLimit: 8,
|
|
64
|
+
freshMs: 15 * 60 * 1e3,
|
|
65
|
+
verbose: true,
|
|
66
|
+
classify: true,
|
|
67
|
+
retryableErrorPatterns: "",
|
|
68
|
+
backoffFactor: 2,
|
|
69
|
+
backoffMaxMs: 3e5,
|
|
70
|
+
notify: false,
|
|
71
|
+
paused: false,
|
|
72
|
+
loopGuard: true,
|
|
73
|
+
loopShortChars: 40,
|
|
74
|
+
loopWindowMs: 3e4,
|
|
75
|
+
loopShortCount: 12,
|
|
76
|
+
loopRepeatText: 4,
|
|
77
|
+
loopToolRepeat: 5
|
|
78
|
+
};
|
|
79
|
+
var RECOVERY_WINDOW_MS = 10 * 60 * 1e3;
|
|
80
|
+
var ECHO_WINDOW_MS = 10 * 60 * 1e3;
|
|
81
|
+
|
|
38
82
|
// src/client/locales.ts
|
|
39
83
|
var zh = {
|
|
40
84
|
"card.title": "自动继续",
|
|
@@ -43,14 +87,18 @@ var zh = {
|
|
|
43
87
|
"field.pausedHint": "全局暂停: 实时与扫描都不会再自动发送, 已排队的待发送也会取消。",
|
|
44
88
|
"field.continueText": "继续文本",
|
|
45
89
|
"field.continueTextHint": "中断后自动发送的消息内容。",
|
|
90
|
+
"default.continueText": LOCALIZED_TEXT_DEFAULTS.zh.continueText,
|
|
46
91
|
"field.continueTextMaxTokens": "超限时的继续文本",
|
|
47
92
|
"field.continueTextMaxTokensHint": "达到输出 token 上限时自动发送的文本, 支持与继续文本相同的占位符。",
|
|
93
|
+
"default.continueTextMaxTokens": LOCALIZED_TEXT_DEFAULTS.zh.continueTextMaxTokens,
|
|
48
94
|
"field.guardTools": "幂等护栏",
|
|
49
95
|
"field.guardToolsHint": "续跑前检查上一步工具调用: 结果未确认时提示先确认状态, 已成功时提示不要重复执行, 避免重复 commit/调 API。",
|
|
50
96
|
"field.guardPendingText": "结果未确认时的护栏文本",
|
|
51
97
|
"field.guardPendingTextHint": "上一步工具可能已部分执行时附加到继续文本之后, 支持 {tool} 占位符。",
|
|
98
|
+
"default.guardPendingText": LOCALIZED_TEXT_DEFAULTS.zh.guardPendingText,
|
|
52
99
|
"field.guardDoneText": "工具已成功时的护栏文本",
|
|
53
100
|
"field.guardDoneTextHint": "上一步工具已确认成功时附加到继续文本之后, 支持 {tool} 与 {result}(结果摘要)占位符。",
|
|
101
|
+
"default.guardDoneText": LOCALIZED_TEXT_DEFAULTS.zh.guardDoneText,
|
|
54
102
|
"field.graceMs": "宽限期 (ms)",
|
|
55
103
|
"field.graceMsHint": "检测到中断后等待的时长; 期间宿主自行恢复则取消。",
|
|
56
104
|
"field.cooldownMs": "冷却时间 (ms)",
|
|
@@ -96,6 +144,7 @@ var zh = {
|
|
|
96
144
|
"field.loopToolRepeatHint": "同工具+同参数+同结果的连续调用多少次时判定死循环; 参数或结果有变化视为有进展。",
|
|
97
145
|
"field.loopText": "循环提示文本",
|
|
98
146
|
"field.loopTextHint": "打断后重启回合时发送的文本, 支持 {tool} 占位符。",
|
|
147
|
+
"default.loopText": LOCALIZED_TEXT_DEFAULTS.zh.loopText,
|
|
99
148
|
"stats.byCode": "按错误码统计",
|
|
100
149
|
"stats.empty": "今天还没有自动继续记录。",
|
|
101
150
|
"stats.reset": "清零",
|
|
@@ -121,19 +170,23 @@ var zh = {
|
|
|
121
170
|
};
|
|
122
171
|
var en = {
|
|
123
172
|
"card.title": "Auto continue",
|
|
124
|
-
"card.description":
|
|
173
|
+
"card.description": 'When a request is interrupted by a non-human cause, automatically send "Continue" to resume.',
|
|
125
174
|
"field.paused": "Pause auto-continue",
|
|
126
175
|
"field.pausedHint": "Globally pause: no live or scan auto-send fires, and queued pending sends are cancelled.",
|
|
127
176
|
"field.continueText": "Continue text",
|
|
128
177
|
"field.continueTextHint": "Message automatically sent after an interruption.",
|
|
178
|
+
"default.continueText": LOCALIZED_TEXT_DEFAULTS.en.continueText,
|
|
129
179
|
"field.continueTextMaxTokens": "Continue text (max tokens)",
|
|
130
180
|
"field.continueTextMaxTokensHint": "Text sent when the output token ceiling is reached; same placeholders as the continue text.",
|
|
181
|
+
"default.continueTextMaxTokens": LOCALIZED_TEXT_DEFAULTS.en.continueTextMaxTokens,
|
|
131
182
|
"field.guardTools": "Idempotency guard",
|
|
132
183
|
"field.guardToolsHint": "Before resuming, inspect the last tool call: if its result is unconfirmed, tell the model to check state first; if it succeeded, tell it not to rerun — avoids duplicate commits / API calls.",
|
|
133
184
|
"field.guardPendingText": "Guard text (unconfirmed result)",
|
|
134
185
|
"field.guardPendingTextHint": "Appended when the last tool may have partially executed; supports the {tool} placeholder.",
|
|
186
|
+
"default.guardPendingText": LOCALIZED_TEXT_DEFAULTS.en.guardPendingText,
|
|
135
187
|
"field.guardDoneText": "Guard text (tool succeeded)",
|
|
136
188
|
"field.guardDoneTextHint": "Appended when the last tool is confirmed done; supports {tool} and {result} (result excerpt).",
|
|
189
|
+
"default.guardDoneText": LOCALIZED_TEXT_DEFAULTS.en.guardDoneText,
|
|
137
190
|
"field.graceMs": "Grace period (ms)",
|
|
138
191
|
"field.graceMsHint": "Wait after an interruption; cancelled if the host recovers on its own.",
|
|
139
192
|
"field.cooldownMs": "Cooldown (ms)",
|
|
@@ -179,6 +232,7 @@ var en = {
|
|
|
179
232
|
"field.loopToolRepeatHint": "How many consecutive calls of the same tool with identical arguments and results trip the loop guard; a changed argument or result counts as progress.",
|
|
180
233
|
"field.loopText": "Loop text",
|
|
181
234
|
"field.loopTextHint": "Text sent after the loop guard restarts a turn; supports the {tool} placeholder.",
|
|
235
|
+
"default.loopText": LOCALIZED_TEXT_DEFAULTS.en.loopText,
|
|
182
236
|
"stats.byCode": "By error code",
|
|
183
237
|
"stats.empty": "No auto-continue activity today.",
|
|
184
238
|
"stats.reset": "Reset",
|
|
@@ -206,37 +260,6 @@ var en = {
|
|
|
206
260
|
// src/client/settings-card.tsx
|
|
207
261
|
var import_react = require("react");
|
|
208
262
|
|
|
209
|
-
// src/shared/core.ts
|
|
210
|
-
var DEFAULT_CONFIG = {
|
|
211
|
-
continueText: "继续",
|
|
212
|
-
continueTextMaxTokens: "继续",
|
|
213
|
-
guardTools: true,
|
|
214
|
-
guardPendingText: "(上一步工具「{tool}」可能未完成, 先确认状态再继续, 不要重复执行)",
|
|
215
|
-
guardDoneText: "(上一步工具「{tool}」已完成, 结果: {result}; 不要重复执行, 直接继续)",
|
|
216
|
-
graceMs: 3e3,
|
|
217
|
-
cooldownMs: 2e4,
|
|
218
|
-
maxConsecutive: 3,
|
|
219
|
-
scanOnBoot: true,
|
|
220
|
-
scanLimit: 8,
|
|
221
|
-
freshMs: 15 * 60 * 1e3,
|
|
222
|
-
verbose: true,
|
|
223
|
-
classify: true,
|
|
224
|
-
retryableErrorPatterns: "",
|
|
225
|
-
backoffFactor: 2,
|
|
226
|
-
backoffMaxMs: 3e5,
|
|
227
|
-
notify: false,
|
|
228
|
-
paused: false,
|
|
229
|
-
loopGuard: true,
|
|
230
|
-
loopShortChars: 40,
|
|
231
|
-
loopWindowMs: 3e4,
|
|
232
|
-
loopShortCount: 12,
|
|
233
|
-
loopRepeatText: 4,
|
|
234
|
-
loopToolRepeat: 5,
|
|
235
|
-
loopText: "(检测到你可能陷入循环, 请停止重复刚才的动作, 换一种方式继续)"
|
|
236
|
-
};
|
|
237
|
-
var RECOVERY_WINDOW_MS = 10 * 60 * 1e3;
|
|
238
|
-
var ECHO_WINDOW_MS = 10 * 60 * 1e3;
|
|
239
|
-
|
|
240
263
|
// src/client/dsh-store-compat.ts
|
|
241
264
|
function resolveSnapshotStore() {
|
|
242
265
|
const current = ["@deepseek-ai/dsh-client", "-store"].join("");
|
|
@@ -1065,7 +1088,7 @@ function AutoContinueSettingsCard(props) {
|
|
|
1065
1088
|
...shared,
|
|
1066
1089
|
...state2.continueText,
|
|
1067
1090
|
onEdit: (text) => props.edit("continueText", text),
|
|
1068
|
-
placeholder:
|
|
1091
|
+
placeholder: t("default.continueText"),
|
|
1069
1092
|
onReset: () => props.resetField("continueText")
|
|
1070
1093
|
}
|
|
1071
1094
|
),
|
|
@@ -1078,7 +1101,7 @@ function AutoContinueSettingsCard(props) {
|
|
|
1078
1101
|
...shared,
|
|
1079
1102
|
...state2.continueTextMaxTokens,
|
|
1080
1103
|
onEdit: (text) => props.edit("continueTextMaxTokens", text),
|
|
1081
|
-
placeholder:
|
|
1104
|
+
placeholder: t("default.continueTextMaxTokens"),
|
|
1082
1105
|
onReset: () => props.resetField("continueTextMaxTokens")
|
|
1083
1106
|
}
|
|
1084
1107
|
),
|
|
@@ -1103,7 +1126,7 @@ function AutoContinueSettingsCard(props) {
|
|
|
1103
1126
|
...shared,
|
|
1104
1127
|
...state2.guardPendingText,
|
|
1105
1128
|
onEdit: (text) => props.edit("guardPendingText", text),
|
|
1106
|
-
placeholder:
|
|
1129
|
+
placeholder: t("default.guardPendingText"),
|
|
1107
1130
|
onReset: () => props.resetField("guardPendingText")
|
|
1108
1131
|
}
|
|
1109
1132
|
),
|
|
@@ -1116,7 +1139,7 @@ function AutoContinueSettingsCard(props) {
|
|
|
1116
1139
|
...shared,
|
|
1117
1140
|
...state2.guardDoneText,
|
|
1118
1141
|
onEdit: (text) => props.edit("guardDoneText", text),
|
|
1119
|
-
placeholder:
|
|
1142
|
+
placeholder: t("default.guardDoneText"),
|
|
1120
1143
|
onReset: () => props.resetField("guardDoneText")
|
|
1121
1144
|
}
|
|
1122
1145
|
),
|
|
@@ -1359,7 +1382,7 @@ function AutoContinueSettingsCard(props) {
|
|
|
1359
1382
|
...shared,
|
|
1360
1383
|
...state2.loopText,
|
|
1361
1384
|
onEdit: (text) => props.edit("loopText", text),
|
|
1362
|
-
placeholder:
|
|
1385
|
+
placeholder: t("default.loopText"),
|
|
1363
1386
|
onReset: () => props.resetField("loopText")
|
|
1364
1387
|
}
|
|
1365
1388
|
),
|
|
@@ -1375,8 +1398,18 @@ var SETTINGS_NS = "auto-continue";
|
|
|
1375
1398
|
var inject = ["slots", "locale", "settingsScope"];
|
|
1376
1399
|
function apply(ctx) {
|
|
1377
1400
|
ctx.effect(() => ctx.locale.register(NS, { zh, en }), "auto-continue: dictionaries");
|
|
1378
|
-
ctx.effect(() => startBridge(), "auto-continue: host bridge");
|
|
1379
1401
|
const scope = ctx.settingsScope.bind({ namespace: SETTINGS_NS });
|
|
1402
|
+
const syncLocale = () => {
|
|
1403
|
+
const active = ctx.locale.getLocale().active;
|
|
1404
|
+
const snapshot = scope.getSnapshot();
|
|
1405
|
+
if (snapshot.status !== "ready" || !snapshot.writable || snapshot.mode !== "host") return;
|
|
1406
|
+
if (snapshot.value?.locale === active) return;
|
|
1407
|
+
void scope.set("locale", active);
|
|
1408
|
+
};
|
|
1409
|
+
ctx.effect(() => scope.subscribe(syncLocale), "auto-continue: locale settings sync");
|
|
1410
|
+
ctx.on("locale/change", syncLocale);
|
|
1411
|
+
syncLocale();
|
|
1412
|
+
ctx.effect(() => startBridge(), "auto-continue: host bridge");
|
|
1380
1413
|
const controller = new AutoContinueSettingsCardController(scope);
|
|
1381
1414
|
ctx.slots.inject(
|
|
1382
1415
|
"settings.plugin.item",
|