@goodandready/dsh-dsml-artifact-guard 0.2.12 → 0.2.14
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 +29 -107
- package/README.md +22 -100
- package/README.ru.md +27 -81
- package/README.zh.md +33 -87
- package/lib/client.js +303 -20
- package/lib/index.js +118 -8
- package/lib/telemetry.js +128 -0
- package/lib/updater.js +6 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
+
## [0.2.14] - 2026-11-05
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- **Live Intercept Telemetry & Stats**: in `lib/telemetry.js`, implemented in-memory telemetry gathering `totalCleaned`, `sessionsGuarded`, `lastCleanedAt`, `lastModel`, `lastProvider`, and an in-memory ring buffer of recent incidents (#68).
|
|
14
|
+
- **Telemetry Web Endpoint**: mounted `/api/dsh-dsml-artifact-guard/stats` (GET for telemetry payload, POST with loopback/same-origin validation to reset counters) (#68).
|
|
15
|
+
- **Settings Card Telemetry Dashboard**: in `lib/client.js`, added a responsive telemetry block displaying live counters, a reset button, and an expandable recent incidents log (#68).
|
|
16
|
+
- **Reasoning Think Artifact Cleaning**: in `lib/index.js`, added `cleanThinkArtifacts` configuration option to strip orphan `</think>` tags, trailing reasoning markers (`<|end of sentence|>`, `<|thought|>`), and auto-heal unclosed reasoning blocks at stream finish (#69).
|
|
17
|
+
- **Incomplete Trailing DSML Sanitization**: in `lib/index.js`, added detection and stripping of incomplete trailing DSML closing tag tokens (`</|DSML|...`) at stream finish when balanced tags precede it (#69).
|
|
18
|
+
|
|
19
|
+
## [0.2.13] - 2026-10-21
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
- **Desktop Profile Auto-Detection**: in `lib/updater.js`, updated `runtime()` to detect profile from `process.cwd()` when `cordis.yml` or `cordis.patch.yml` exists, properly resolving the `desktop` profile in DSH Desktop without requiring `DSH_PROFILE_DIR` (#66).
|
|
23
|
+
- **DSH Desktop Origin Trust**: in `lib/updater.js`, updated `isTrustedUpdateRequest()` to accept loopback requests from Electron UI origin `dsh-app://app` (#66).
|
|
24
|
+
|
|
10
25
|
## [0.2.12] - 2026-10-15
|
|
11
26
|
|
|
12
27
|
### Fixed
|
|
@@ -31,121 +46,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
31
46
|
## [0.2.9] - 2026-10-07
|
|
32
47
|
|
|
33
48
|
### Fixed
|
|
34
|
-
- **
|
|
35
|
-
- **
|
|
36
|
-
- **
|
|
49
|
+
- **Safe Locale Extraction**: safely extracted active language string from `LocaleSnapshot` object (`snap?.active`), resolving fatal `TypeError: rawLang.startsWith is not a function` on settings card render (#50, #57).
|
|
50
|
+
- **Locale Dictionary Isolation**: removed embedded `ru` dictionary from the plugin bundle to avoid `(namespace, 'ru')` collision in DSH core with `dsh-russian-lang` (#58).
|
|
51
|
+
- **Fallback Translator Binding**: bound fallback translator to `ctx.locale.bind(NS)` inside `PluginCard` for clean localization rendering.
|
|
37
52
|
|
|
38
53
|
## [0.2.8] - 2026-09-26
|
|
39
54
|
|
|
40
55
|
### Added
|
|
41
|
-
- **
|
|
42
|
-
- **
|
|
43
|
-
- **
|
|
44
|
-
|
|
45
|
-
### Changed
|
|
46
|
-
- **De-identification**: removed proprietary `opencode-go` default in public package configuration.
|
|
47
|
-
- **Backward Compatibility**: user configs with legacy `providerId` and `modelId` continue to work as an additional exact rule, with a deprecation notice and one-click clear button in the Web UI settings card.
|
|
48
|
-
- **Documentation**: added dedicated section explaining lack of DSML processing in core DSH 0.1.7-rc.2.
|
|
56
|
+
- **Global Model Regex Scoping**: replaced rigid single `providerId`/`modelId` requirements with universal case-insensitive `modelPattern` RegExp (default `deepseek`), automatically protecting all DeepSeek models across all providers (#48).
|
|
57
|
+
- **Whitelist Provider Filtering**: added optional `providers` array parameter to restrict protection to specified provider IDs while allowing empty array to guard all providers (#48).
|
|
58
|
+
- **Backward-Compatible Legacy Scope**: added automatic backward compatibility for existing user configs with legacy `providerId`/`modelId`, displaying an informational notice and clean action in the settings card (#48).
|
|
59
|
+
- **De-identified Defaults**: removed proprietary `opencode-go` default from public package distribution (#48).
|
|
49
60
|
|
|
50
61
|
## [0.2.7] - 2026-09-25
|
|
51
62
|
|
|
52
63
|
### Fixed
|
|
53
|
-
- **
|
|
54
|
-
|
|
55
|
-
## [0.2.6] - 2026-09-25
|
|
56
|
-
|
|
57
|
-
### Fixed
|
|
58
|
-
- **SettingsForms Migration (DSH 0.1.7)**: marked Config schema as volatile and configured settings policy (`auto: false`) to suppress generic auto-generated form duplicates, while resolving row ID `dsh-dsml-artifact-guard` via client `configForms` with live subscription support (#17).
|
|
59
|
-
- **Client Locale Lifecycle**: wrapped client locale registration in `ctx.effect` to ensure clean namespace disposal on HMR and avoid collision on module reload (#44).
|
|
60
|
-
|
|
61
|
-
## [0.2.5] - 2026-09-24
|
|
62
|
-
|
|
63
|
-
### Fixed
|
|
64
|
-
- **Preflight & Locale Contract**: eliminated nonexistent `locale.get()` call in `lib/client.js`, using injected `props.t` with canonical `ctx.locale.bind(NS)` fallback (#36).
|
|
65
|
-
- **Streaming Buffer & Tag Balancing**: replaced fixed 64-character buffer slicing with delimiter-based tag boundary scanning (`<` and `>`), ensuring DSML parameter tags of arbitrary length preserve open/close tag balance without premature truncation (#37).
|
|
66
|
-
- **One-Click Updater LAN Support**: updated `isTrustedUpdateRequest` to allow same-origin requests matching Host/Origin, enabling one-click updates from LAN and reverse-proxy Web UIs while retaining strict loopback verification for local endpoints (#38).
|
|
67
|
-
- **Dead Code Elimination**: connected `checkRequestMethod` helper to updater POST handler (#39).
|
|
68
|
-
|
|
69
|
-
## [0.2.4] - 2026-09-22
|
|
70
|
-
|
|
71
|
-
### Fixed
|
|
72
|
-
- The settings card no longer waits for the removed `settingsScope` service. It uses `configForms` on current DeepSeek Harness (#41).
|
|
73
|
-
|
|
74
|
-
## [0.2.3] - 2026-09-19
|
|
75
|
-
|
|
76
|
-
### Fixed
|
|
77
|
-
- **Settings reachable again on the plugin's own page**: the card registered into
|
|
78
|
-
`settings.plugin.item` / `plugins.row.config`, and the current DSH core
|
|
79
|
-
(0.1.6-alpha.2) only renders a plugin's configuration page for entries registered
|
|
80
|
-
in the plugin list seat `plugins.item` — that is how `dsh-agentrouter` and
|
|
81
|
-
`dsh-agent-orchestrator` show their settings. The view-aware `PluginItem` is now
|
|
82
|
-
registered there as well (`id: 'dsh-dsml-artifact-guard'`, order 95, static label),
|
|
83
|
-
with the row seat and the legacy card kept as fallbacks.
|
|
84
|
-
- The render path was hardened on the way: `PluginCard` is wrapped in its own error
|
|
85
|
-
boundary so a throw inside this card cannot take the whole client batch down.
|
|
86
|
-
|
|
87
|
-
## [0.2.2] - 2026-09-18
|
|
88
|
-
|
|
89
|
-
### Fixed
|
|
90
|
-
- **Settings reachable again (`lib/client.js`)**: the settings card registered into `settings.plugin.item`, a slot the current DSH core no longer renders, so the plugin's settings were unreachable. The surface now registers into the Plugins page row seat `plugins.row.config`, keyed `@goodandready/dsh-dsml-artifact-guard#dsh-dsml-artifact-guard`: the plugin's row gains a configure control whose page is the settings form (`view: 'page'`, rendered bare — `PluginCard` accepts `bare` and drops the card wrapper because the host page draws the title, icon, crumb and padding) plus a one-line state under the title (`view: 'summary'`). The legacy seat stays registered as a fallback for older cores ([#31](http://192.168.1.111:3005/goodandready/dsh-dsml-artifact-guard/issues/31)).
|
|
91
|
-
- **Row-seat guard (`test/row-config-seat.test.js`)**: asserts the row key, the seat order (row seat first, legacy seat kept) and the bare page render.
|
|
92
|
-
|
|
93
|
-
---
|
|
94
|
-
|
|
95
|
-
## [0.2.1] - 2026-09-18
|
|
96
|
-
|
|
97
|
-
### Fixed
|
|
98
|
-
- **Theme Semantic Standardization (`lib/client.js`)**: Eliminated all 42 hardcoded hex/rgba color literals in favor of canonical DeepSeek Harness theme CSS custom properties (`--dsw-alias-...`) and `color-mix()` tints, guaranteeing high contrast and legibility across Dark and Light modes ([#26](https://github.com/GooDAnDReaDY/dsh-dsml-artifact-guard/issues/26)).
|
|
99
|
-
- **Theme Regression Test Guard (`test/theme.test.js`)**: Added automated regression test asserting zero hardcoded hex and rgba color literals in client surfaces.
|
|
100
|
-
- **Repository Hygiene**: Fixed `.gitignore` whitespace rule for `AGENTS.md` and untracked `package-lock.json` in alignment with zero-dependency architecture.
|
|
64
|
+
- **Client Locale Lifecycle**: bound client locale registration lifecycle via `ctx.effect` to ensure clean unregistration on HMR and card reload (#44).
|
|
65
|
+
- **DSH 0.1.7 SettingsForms Discovery**: marked each user-editable schema field volatile and registered fiber-attributed settings policy with `auto: false` (#17).
|
|
101
66
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
## [0.2.0] - 2026-09-17
|
|
105
|
-
|
|
106
|
-
### Added
|
|
107
|
-
- **Native Settings Card (`lib/client.js`)**: Registered UI card in slot `settings.plugin.item` with snapshot status check, configuration inputs, and disabled warning indicator ([#17](https://github.com/GooDAnDReaDY/dsh-dsml-artifact-guard/issues/17)).
|
|
108
|
-
- **One-Click In-Place Updater (`lib/updater.js`)**: Standard HTTP endpoint `/api/dsh-dsml-artifact-guard/update` with SemVer comparison, loopback/same-origin protection, and update execution ([#18](https://github.com/GooDAnDReaDY/dsh-dsml-artifact-guard/issues/18)).
|
|
109
|
-
- **Core Primitive Chevron**: Requested `IconChevronDownOutline14` with SVG fallback.
|
|
110
|
-
|
|
111
|
-
### Fixed
|
|
112
|
-
- **Package Hygiene**: Deduplicated multilingual READMEs in `docs/` and restricted `package.json#files` allowlist, reducing package size by ~40% ([#20](https://github.com/GooDAnDReaDY/dsh-dsml-artifact-guard/issues/20)).
|
|
113
|
-
- **Repository Cleanliness**: Removed `AGENTS.md` from git tracking ([#19](https://github.com/GooDAnDReaDY/dsh-dsml-artifact-guard/issues/19)) and eliminated legacy `.tgz` archives from source tree ([#21](https://github.com/GooDAnDReaDY/dsh-dsml-artifact-guard/issues/21)).
|
|
114
|
-
|
|
115
|
-
---
|
|
116
|
-
|
|
117
|
-
## [0.1.5] - 2026-09-17
|
|
118
|
-
|
|
119
|
-
### Documentation
|
|
120
|
-
- Fixed Mermaid diagram edge label syntax on GitHub and added standard community support block ([#15](https://github.com/GooDAnDReaDY/dsh-dsml-artifact-guard/issues/15)).
|
|
121
|
-
|
|
122
|
-
---
|
|
123
|
-
|
|
124
|
-
## [0.1.4] - 2026-09-12
|
|
125
|
-
|
|
126
|
-
### Changed
|
|
127
|
-
- Schema `mode` default set to `sanitize` for out-of-the-box protection ([#11](https://github.com/GooDAnDReaDY/dsh-dsml-artifact-guard/issues/11)).
|
|
128
|
-
- Added robust open/close tag balancing in `sanitizeDsmlArtifacts` to handle prior closed blocks in prose ([#11](https://github.com/GooDAnDReaDY/dsh-dsml-artifact-guard/issues/11)).
|
|
129
|
-
- Updated design contract documentation and verified package hygiene ([#11](https://github.com/GooDAnDReaDY/dsh-dsml-artifact-guard/issues/11)).
|
|
130
|
-
|
|
131
|
-
---
|
|
132
|
-
|
|
133
|
-
## [0.1.3] - 2026-09-06
|
|
134
|
-
|
|
135
|
-
### Changed
|
|
136
|
-
- Wrapped `llm/stream` handler in `ctx.effect` for clean lifecycle unmount ([#8](https://github.com/GooDAnDReaDY/dsh-dsml-artifact-guard/issues/8)).
|
|
137
|
-
- Updated `cordis.patch.yml` to use `config: {}`, allowing schema defaults to apply automatically unless overridden ([#9](https://github.com/GooDAnDReaDY/dsh-dsml-artifact-guard/issues/9)).
|
|
138
|
-
|
|
139
|
-
---
|
|
140
|
-
|
|
141
|
-
## [0.1.2] - 2026-09-02
|
|
67
|
+
## [0.2.6] - 2026-09-24
|
|
142
68
|
|
|
143
69
|
### Fixed
|
|
144
|
-
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
## [0.1.1] - 2026-08-30
|
|
149
|
-
|
|
150
|
-
### Added
|
|
151
|
-
- Initial release: synchronous, fail-open DSML protocol closing tag sanitizer for DeepSeek Harness model streams.
|
|
70
|
+
- **Deep Audit Resolution**: removed nonexistent `ctx.locale.get()` calls in favor of injected `props.t` with `ctx.locale.bind(NS)` fallback (#36).
|
|
71
|
+
- **Arbitrary Tag Length Buffer Scanning**: upgraded stream buffer scanning to delimiter-based boundary tracking supporting DSML tags of arbitrary length without buffer truncation (#37).
|
|
72
|
+
- **LAN Same-Origin Security**: allowed same-origin update requests from LAN/reverse-proxy UIs while enforcing strict Host/Origin match and loopback origin security (#38).
|
|
73
|
+
- **Request Method Verification Integration**: integrated `checkRequestMethod` helper into updater POST handler, eliminating dead export (#39).
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
<div align="center">
|
|
4
4
|
|
|
5
|
-
<h3>
|
|
5
|
+
<h3>Zero-dependency streaming guard and sanitizer for leaked DeepSeek DSML protocol tags and reasoning artifacts</h3>
|
|
6
6
|
|
|
7
7
|
<p align="center">
|
|
8
8
|
<a href="https://www.npmjs.com/package/@goodandready/dsh-dsml-artifact-guard"><img src="https://img.shields.io/npm/v/@goodandready/dsh-dsml-artifact-guard.svg?style=for-the-badge&color=6366f1&labelColor=1e1b4b" alt="npm version"></a>
|
|
@@ -24,9 +24,9 @@
|
|
|
24
24
|
<table align="center">
|
|
25
25
|
<tr>
|
|
26
26
|
<td align="center">
|
|
27
|
-
⭐ <strong>If you
|
|
27
|
+
⭐ <strong>If you find this plugin helpful, please star it on GitHub</strong> — your support helps maintain and develop the project.
|
|
28
28
|
<br><br>
|
|
29
|
-
🐛 <strong>
|
|
29
|
+
🐛 <strong>Found a bug or have a feature idea?</strong> Feel free to open an issue on GitHub in any language.
|
|
30
30
|
</td>
|
|
31
31
|
</tr>
|
|
32
32
|
</table>
|
|
@@ -35,103 +35,25 @@
|
|
|
35
35
|
|
|
36
36
|
---
|
|
37
37
|
|
|
38
|
-
## ⚡
|
|
38
|
+
## ⚡ Problem & Purpose
|
|
39
39
|
|
|
40
|
-
When
|
|
40
|
+
When streaming responses from DeepSeek models via third-party proxies, gateways, or incompatible providers, protocol closing tags for tool invocations (DSML — DeepSeek Markup Language) occasionally leak into the visible text channel. Users observe raw markup at the end of their conversation:
|
|
41
41
|
|
|
42
42
|
```text
|
|
43
|
-
|
|
43
|
+
Response completed successfully.
|
|
44
44
|
</|DSML|parameter> </|DSML|invoke> </|DSML|tool_calls>
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
Additionally, reasoning models (such as DeepSeek-R1 / V3) or interrupted network streams can leave orphan `</think>` tags, dangling tokens (`<|end of sentence|>`), or unclosed thinking blocks that corrupt markdown rendering.
|
|
48
48
|
|
|
49
|
-
**`@goodandready/dsh-dsml-artifact-guard`** is a
|
|
49
|
+
**`@goodandready/dsh-dsml-artifact-guard`** is a high-performance runtime guard for DeepSeek Harness that cleans these protocol artifacts in real time before they reach the user interface:
|
|
50
50
|
|
|
51
|
-
1. **Synchronous
|
|
52
|
-
2. **
|
|
53
|
-
3. **
|
|
54
|
-
4. **
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
## 💡 Why Not in DSH Core?
|
|
59
|
-
|
|
60
|
-
As of DeepSeek Harness **0.1.7-rc.2**, the core upstream stream pipeline (`dsh-llm-pi-ai`, `dsh-llm-deepseek*`, etc.) does not perform terminal DSML protocol cleanup — there is zero mention or handling of `|DSML|` anywhere in the core engine. When upstream gateways (e.g. `commandcode`, `deepseek-official`, or custom proxies) leak protocol closing tags at the conclusion of an assistant turn, DSH forwards them directly to the frontend.
|
|
61
|
-
|
|
62
|
-
`dsh-dsml-artifact-guard` serves as the universal runtime guard across all DeepSeek models regardless of provider gateway or routing configuration.
|
|
63
|
-
|
|
64
|
-
---
|
|
65
|
-
|
|
66
|
-
## 🏗️ Architecture
|
|
67
|
-
|
|
68
|
-
```mermaid
|
|
69
|
-
graph TD
|
|
70
|
-
subgraph DSH ["DeepSeek Harness Runtime"]
|
|
71
|
-
Turn["Agent Turn Execution<br/>(LLM Stream Request)"]
|
|
72
|
-
ChatUI["Chat UI Stream Consumer<br/>(Renders clean markdown text)"]
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
subgraph Guard ["@goodandready/dsh-dsml-artifact-guard"]
|
|
76
|
-
Hook["Synchronous llm/stream Hook<br/>(Returns AsyncIterable synchronously)"]
|
|
77
|
-
ScopeCheck{"Scope Match?<br/>(providerId & modelId)"}
|
|
78
|
-
PassThrough["Raw Stream Pass-Through<br/>(Zero overhead for other models)"]
|
|
79
|
-
Buffer["Sliding Tail Buffer<br/>(Preserves trailing 96 bytes across deltas)"]
|
|
80
|
-
Detector{"Terminal Artifact?<br/>(Matches leaked DSML tail at finish)"}
|
|
81
|
-
Sanitize["Sanitize Mode<br/>(Strips leaked closing tags)"]
|
|
82
|
-
Audit["Audit Mode<br/>(Emits ctx.logger warning only)"]
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
Turn -->|llm/stream hook| Hook
|
|
86
|
-
Hook --> ScopeCheck
|
|
87
|
-
ScopeCheck -->|No| PassThrough
|
|
88
|
-
ScopeCheck -->|Yes| Buffer
|
|
89
|
-
PassThrough --> ChatUI
|
|
90
|
-
Buffer --> Detector
|
|
91
|
-
Detector -->|No Artifact| ChatUI
|
|
92
|
-
Detector -->|Artifact detected: sanitize| Sanitize --> ChatUI
|
|
93
|
-
Detector -->|Artifact detected: audit| Audit --> ChatUI
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
---
|
|
97
|
-
|
|
98
|
-
## ✨ Features & Capabilities
|
|
99
|
-
|
|
100
|
-
### 1. Synchronous Hook Guarantee
|
|
101
|
-
Under Cordis and DSH service lifecycles, event listeners on `llm/stream` must return the transformed stream synchronously. An asynchronous hook wrapper will return a `Promise<AsyncIterable>`, causing the runtime dispatcher to immediately throw `TypeError: stream is not async iterable`. `dsh-dsml-artifact-guard` wraps the stream generator in a pure synchronous registration.
|
|
102
|
-
|
|
103
|
-
### 2. Multi-Chunk Tail Buffering
|
|
104
|
-
In real-world streaming, the artifact `</|DSML|parameter> </|DSML|invoke> </|DSML|tool_calls>` is frequently fractured into fragments:
|
|
105
|
-
* Chunk 1: `All tasks complete. </|DSML|pa`
|
|
106
|
-
* Chunk 2: `rameter> </|DSML|invoke> `
|
|
107
|
-
* Chunk 3: `</|DSML|tool_calls>`
|
|
108
|
-
|
|
109
|
-
The guard retains a minimal 96-byte window until the next chunk or `finish` event arrives, ensuring fractured tags are seamlessly detected and sanitized as a single terminal artifact.
|
|
110
|
-
|
|
111
|
-
### 3. Fail-Open Architecture
|
|
112
|
-
* If the text contains genuine prose about DSML (e.g. `<|DSML|tool_calls>example</|DSML|tool_calls>`), it is **never** removed.
|
|
113
|
-
* Non-text chunks (`tool-call-delta`, `usage`, `finish`) are forwarded immediately without delay.
|
|
114
|
-
* Any malformed chunk structure passes through transparently to preserve session stability.
|
|
115
|
-
|
|
116
|
-
### 4. Flexible Operating Modes
|
|
117
|
-
* **`sanitize`** *(default)*: Strips terminal DSML closing tags and logs a warning with the count of removed artifacts.
|
|
118
|
-
* **`audit`**: Emits diagnostic logs with `ctx.logger.info(...)` without modifying the user-visible stream.
|
|
119
|
-
* **`disabled`**: Bypasses processing entirely.
|
|
120
|
-
|
|
121
|
-
### 5. Native Web UI Settings Card
|
|
122
|
-
Registered directly in DeepSeek Harness `plugins.row.config` and `plugins.item` slots (`lib/client.js`):
|
|
123
|
-
* **Reactive Configuration**: Adjust `mode`, `providers`, and `modelPattern` on the fly without restarting the harness.
|
|
124
|
-
* **Snapshot State Awareness**: Gracefully handles snapshot loading, ready, and unavailable states.
|
|
125
|
-
* **Protection Bypass Warning**: Displays a prominent `OFF` badge and warning banner when the guard is set to `disabled`.
|
|
126
|
-
|
|
127
|
-
### 6. One-Click In-Place Auto-Updater
|
|
128
|
-
A canonical HTTP management route (`/api/dsh-dsml-artifact-guard/update`) mounted via `lib/updater.js`:
|
|
129
|
-
* **SemVer Inspection**: Queries the registry and compares versions with full pre-release support.
|
|
130
|
-
* **Loopback & Same-Origin Protection**: Write mutations (`POST`) are strictly restricted to local loopback connections with valid origin headers.
|
|
131
|
-
* **Clean Invocation**: Executes package updates safely without risky CLI bypass flags.
|
|
132
|
-
|
|
133
|
-
### 7. Full Dark & Light Theme Compliance
|
|
134
|
-
All client UI styles are strictly tokenized via DeepSeek Harness `--dsw-alias-...` CSS custom properties and `color-mix()` functions with zero hardcoded hex or rgba color literals. High contrast and accessibility are guaranteed in both Dark and Light themes, guarded by automated regression tests (`test/theme.test.js`).
|
|
51
|
+
1. **Strict Synchronous Hook Contract**: Implements the Cordis `llm/stream` hook synchronously, returning an `AsyncIterable` directly to preserve runtime integrity and avoid fatal `TypeError: stream is not async iterable` errors.
|
|
52
|
+
2. **Chunk Boundary Buffer**: Uses a 96-byte sliding window to reliably intercept closing tags fragmented across network packet boundaries.
|
|
53
|
+
3. **Incomplete Token Recovery at Finish**: Detects and strips truncated protocol closing prefixes (`</|DSML|...`) when connections terminate abruptly.
|
|
54
|
+
4. **Reasoning Artifact Protection (`cleanThinkArtifacts`)**: Strips orphan `</think>` tags, removes trailing reasoning markers, and heals unclosed `<think>` blocks at stream finish.
|
|
55
|
+
5. **Fail-Open Tag Balancing**: Tracks open and closed tags to guarantee that legitimate technical discussions containing DSML or think examples are never altered.
|
|
56
|
+
6. **Live Telemetry & Metrics Dashboard**: Real-time in-memory counters (guarded sessions, stripped tags, last incident time, and recent events log) available directly in the native Web UI card.
|
|
135
57
|
|
|
136
58
|
---
|
|
137
59
|
|
|
@@ -149,14 +71,15 @@ Restart your DeepSeek Harness instance.
|
|
|
149
71
|
|
|
150
72
|
## ⚙️ Configuration (`settings.yaml`)
|
|
151
73
|
|
|
152
|
-
Configure
|
|
74
|
+
Configure matching rules in `settings.yaml` or through the Web UI Settings Card:
|
|
153
75
|
|
|
154
76
|
```yaml
|
|
155
77
|
# settings.yaml
|
|
156
78
|
dsh-dsml-artifact-guard:
|
|
157
79
|
mode: sanitize
|
|
158
|
-
modelPattern: "deepseek"
|
|
159
|
-
providers: []
|
|
80
|
+
modelPattern: "deepseek"
|
|
81
|
+
providers: []
|
|
82
|
+
cleanThinkArtifacts: false
|
|
160
83
|
```
|
|
161
84
|
|
|
162
85
|
### Configuration Parameters
|
|
@@ -166,6 +89,7 @@ dsh-dsml-artifact-guard:
|
|
|
166
89
|
| `mode` | `string` | `"sanitize"` | Operation mode: `"sanitize"` (strip tags), `"audit"` (log only), or `"disabled"` |
|
|
167
90
|
| `modelPattern` | `string` | `"deepseek"` | Case-insensitive RegExp matched against model IDs (e.g. `deepseek`, `deepseek-v4.*`, `deepseek/.*`) |
|
|
168
91
|
| `providers` | `string[]` | `[]` | Optional list of provider IDs. When empty, guards all providers |
|
|
92
|
+
| `cleanThinkArtifacts` | `boolean` | `false` | Strips orphan `</think>` tags, removes trailing reasoning markers, and heals unclosed reasoning blocks |
|
|
169
93
|
| `providerId` | `string` | `undefined` | *(Deprecated)* Legacy exact provider identifier; maintained for backward compatibility |
|
|
170
94
|
| `modelId` | `string` | `undefined` | *(Deprecated)* Legacy exact model identifier; maintained for backward compatibility |
|
|
171
95
|
|
|
@@ -173,6 +97,8 @@ dsh-dsml-artifact-guard:
|
|
|
173
97
|
|
|
174
98
|
| Method | Endpoint | Access | Description |
|
|
175
99
|
|:---|:---|:---|:---|
|
|
100
|
+
| `GET` | `/api/dsh-dsml-artifact-guard/stats` | Web UI / Localhost | Retrieves live in-memory telemetry and recent incident history |
|
|
101
|
+
| `POST` | `/api/dsh-dsml-artifact-guard/stats` | Loopback & Same-Origin | Resets telemetry counters and clears the recent incident log |
|
|
176
102
|
| `GET` | `/api/dsh-dsml-artifact-guard/update` | Web UI / Localhost | Retrieves current version, latest registry version, and update status |
|
|
177
103
|
| `POST` | `/api/dsh-dsml-artifact-guard/update` | Loopback & Same-Origin | Triggers in-place package update via DSH CLI |
|
|
178
104
|
|
|
@@ -180,7 +106,7 @@ dsh-dsml-artifact-guard:
|
|
|
180
106
|
|
|
181
107
|
## 🧪 Testing
|
|
182
108
|
|
|
183
|
-
Run the automated test suite
|
|
109
|
+
Run the automated test suite:
|
|
184
110
|
|
|
185
111
|
```bash
|
|
186
112
|
npm test
|
|
@@ -192,7 +118,3 @@ npm run check
|
|
|
192
118
|
## 📄 License
|
|
193
119
|
|
|
194
120
|
MIT © [GooDAnDReaDY](https://github.com/GooDAnDReaDY)
|
|
195
|
-
|
|
196
|
-
---
|
|
197
|
-
|
|
198
|
-
For a complete release history and version migration notes, see [CHANGELOG.md](CHANGELOG.md).
|
package/README.ru.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
<div align="center">
|
|
4
4
|
|
|
5
|
-
<h3>Предохранитель и потоковый очиститель от артефактов закрывающих тегов
|
|
5
|
+
<h3>Предохранитель и потоковый очиститель от артефактов закрывающих тегов DSML и reasoning-разметки в DeepSeek Harness</h3>
|
|
6
6
|
|
|
7
7
|
<p align="center">
|
|
8
8
|
<a href="https://www.npmjs.com/package/@goodandready/dsh-dsml-artifact-guard"><img src="https://img.shields.io/npm/v/@goodandready/dsh-dsml-artifact-guard.svg?style=for-the-badge&color=6366f1&labelColor=1e1b4b" alt="npm version"></a>
|
|
@@ -44,79 +44,16 @@
|
|
|
44
44
|
</|DSML|parameter> </|DSML|invoke> </|DSML|tool_calls>
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
Кроме того, reasoning-модели (например, DeepSeek-R1 / V3) или обрывы сетевых сессий могут оставлять сиротливые теги `</think>`, концевые маркеры (`<|end of sentence|>`) или незакрытые блоки размышлений, ломающие вёрстку Markdown.
|
|
48
48
|
|
|
49
|
-
**`@goodandready/dsh-dsml-artifact-guard`** — легковесный плагин времени выполнения
|
|
49
|
+
**`@goodandready/dsh-dsml-artifact-guard`** — легковесный плагин времени выполнения для DeepSeek Harness, перехватывающий и удаляющий эти паразитные терминальные артефакты в реальном времени до того, как текст попадёт в интерфейс:
|
|
50
50
|
|
|
51
|
-
1. **Строго синхронный контракт хука**: в среде Cordis обработчик события `llm/stream`
|
|
52
|
-
2. **Буферизация фрагментированного хвоста**:
|
|
53
|
-
3.
|
|
54
|
-
4.
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
## 💡 Почему этого нет в ядре DSH?
|
|
59
|
-
|
|
60
|
-
По состоянию на DeepSeek Harness **0.1.7-rc.2**, ядро системы (`dsh-llm-pi-ai`, `dsh-llm-deepseek*` и др.) вообще не выполняет очистку завершающих тегов DSML — в ядровом коде нет ни единого упоминания `|DSML|`. Когда вышестоящие провайдеры (например, `commandcode`, `deepseek-official` или внешние шлюзы) отдают в потоке закрывающие теги протокола, DSH пропускает их прямо в интерфейс чата.
|
|
61
|
-
|
|
62
|
-
Плагин `dsh-dsml-artifact-guard` обеспечивает универсальную защиту для всех моделей DeepSeek независимо от конкретного шлюза или маршрутизатора.
|
|
63
|
-
|
|
64
|
-
---
|
|
65
|
-
|
|
66
|
-
## 🏗️ Архитектура работы
|
|
67
|
-
|
|
68
|
-
```mermaid
|
|
69
|
-
graph TD
|
|
70
|
-
subgraph DSH ["Среда DeepSeek Harness"]
|
|
71
|
-
Turn["Ход выполнения агента<br/>(Запрос к потоку модели)"]
|
|
72
|
-
ChatUI["Отображение в чате<br/>(Чистый текст без паразитных тегов)"]
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
subgraph Guard ["@goodandready/dsh-dsml-artifact-guard"]
|
|
76
|
-
Hook["Синхронный хук llm/stream<br/>(Возвращает AsyncIterable синхронно)"]
|
|
77
|
-
ScopeCheck{"Совпадает скоуп?<br/>(providerId и modelId)"}
|
|
78
|
-
PassThrough["Сквозной пропуск потока<br/>(Нулевой оверхед для других моделей)"]
|
|
79
|
-
Buffer["Буфер скользящего хвоста<br/>(Сохраняет последние 96 байт)"]
|
|
80
|
-
Detector{"Терминальный артефакт?<br/>(Поиск хвоста DSML при finish)"}
|
|
81
|
-
Sanitize["Режим Sanitize<br/>(Вырезание закрывающих тегов)"]
|
|
82
|
-
Audit["Режим Audit<br/>(Логирование через ctx.logger)"]
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
Turn -->|Хук llm/stream| Hook
|
|
86
|
-
Hook --> ScopeCheck
|
|
87
|
-
ScopeCheck -->|Нет| PassThrough
|
|
88
|
-
ScopeCheck -->|Да| Buffer
|
|
89
|
-
PassThrough --> ChatUI
|
|
90
|
-
Buffer --> Detector
|
|
91
|
-
Detector -->|Нет артефакта| ChatUI
|
|
92
|
-
Detector -->|Артефакт найден: sanitize| Sanitize --> ChatUI
|
|
93
|
-
Detector -->|Артефакт найден: audit| Audit --> ChatUI
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
---
|
|
97
|
-
|
|
98
|
-
## ✨ Подробный разбор возможностей
|
|
99
|
-
|
|
100
|
-
### 1. Защита синхронного контракта Cordis
|
|
101
|
-
В архитектуре Cordis вызов `ctx.on('llm/stream', (o, next) => ...)` ожидает немедленный возврат асинхронного генератора. Если функция хука объявлена как `async`, JavaScript оборачивает возвращаемое значение в `Promise`. В результате потребители стрима падают с фатальной ошибкой `TypeError: stream is not async iterable`. `dsh-dsml-artifact-guard` оборачивает поток синхронно, сохраняя целостность рантайма.
|
|
102
|
-
|
|
103
|
-
### 2. Захват разорванных сетевых чанков
|
|
104
|
-
В реальном сетевом потоке завершающая последовательность тегов может приходить отдельными фрагментами:
|
|
105
|
-
* Чанк 1: `Задача выполнена. </|DSML|pa`
|
|
106
|
-
* Чанк 2: `rameter> </|DSML|invoke> `
|
|
107
|
-
* Чанк 3: `</|DSML|tool_calls>`
|
|
108
|
-
|
|
109
|
-
Буфер скользящего хвоста удерживает последние 96 байт до получения следующего текстового блока или сигнала завершения `finish`, точно сопоставляя полный шаблон и удаляя его как единое целое.
|
|
110
|
-
|
|
111
|
-
### 3. Гарантия сохранности данных (Fail-Open)
|
|
112
|
-
* Если в ответе содержится обычный текст с упоминанием тегов (например, руководство по написанию `<|DSML|tool_calls>`), текст **никогда** не удаляется.
|
|
113
|
-
* Нетекстовые чанки (`tool-call-delta`, `usage`, `finish`) пробрасываются немедленно без задержек.
|
|
114
|
-
* При любых непредвиденных ошибках или нестандартных форматах чанков поток не прерывается, а беспрепятственно передаётся дальше.
|
|
115
|
-
|
|
116
|
-
### 4. Режимы работы
|
|
117
|
-
* **`sanitize`** *(по умолчанию)*: вырезает паразитные закрывающие теги и фиксирует событие в журнале с указанием числа удалённых артефактов.
|
|
118
|
-
* **`audit`**: только логирует обнаружение артефактов через `ctx.logger.info(...)`, не модифицируя текст в чате.
|
|
119
|
-
* **`disabled`**: полностью отключает обработку.
|
|
51
|
+
1. **Строго синхронный контракт хука**: в среде Cordis обработчик события `llm/stream` возвращает `AsyncIterable` синхронно без Promise-обёрток.
|
|
52
|
+
2. **Буферизация фрагментированного хвоста**: скользящее окно размером 96 байт захватывает закрывающие теги, даже если они разрезаны между сетевыми чанками.
|
|
53
|
+
3. **Очистка неполных префиксов тегов при обрыве связи**: при получении сигнала `finish` срезает оборванные терминальные остатки (`</|DSML|...`).
|
|
54
|
+
4. **Защита от reasoning-артефактов (`cleanThinkArtifacts`)**: очищает сиротливые `</think>`, терминальные спецтокены шлюзов и закрывает аварийно оборванные `<think>`.
|
|
55
|
+
5. **100% Fail-Open архитектура**: плагин отслеживает баланс тегов и никогда не удаляет полезный пользовательский текст или обсуждения разметки.
|
|
56
|
+
6. **Панель телеметрии и статистики в UI**: отображение числа защищённых сессий, срезанных тегов, времени последней активности и журнала недавних перехватов с кнопкой сброса.
|
|
120
57
|
|
|
121
58
|
---
|
|
122
59
|
|
|
@@ -134,14 +71,15 @@ dsh plugin --profile web add @goodandready/dsh-dsml-artifact-guard
|
|
|
134
71
|
|
|
135
72
|
## ⚙️ Конфигурация (`settings.yaml`)
|
|
136
73
|
|
|
137
|
-
Настройка
|
|
74
|
+
Настройка параметров в `settings.yaml` или через веб-панель управления:
|
|
138
75
|
|
|
139
76
|
```yaml
|
|
140
77
|
# settings.yaml
|
|
141
78
|
dsh-dsml-artifact-guard:
|
|
142
79
|
mode: sanitize
|
|
143
|
-
|
|
144
|
-
|
|
80
|
+
modelPattern: "deepseek"
|
|
81
|
+
providers: []
|
|
82
|
+
cleanThinkArtifacts: false
|
|
145
83
|
```
|
|
146
84
|
|
|
147
85
|
### Таблица параметров конфигурации
|
|
@@ -149,8 +87,20 @@ dsh-dsml-artifact-guard:
|
|
|
149
87
|
| Параметр | Тип | По умолчанию | Описание |
|
|
150
88
|
|:---|:---|:---|:---|
|
|
151
89
|
| `mode` | `string` | `"sanitize"` | Режим работы: `"sanitize"` (удалять теги), `"audit"` (только логировать) или `"disabled"` |
|
|
152
|
-
| `
|
|
153
|
-
| `
|
|
90
|
+
| `modelPattern` | `string` | `"deepseek"` | Case-insensitive регулярное выражение для фильтрации моделей (например, `deepseek`, `deepseek-v4.*`) |
|
|
91
|
+
| `providers` | `string[]` | `[]` | Список разрешённых ID провайдеров. Если пуст — фильтруются все провайдеры |
|
|
92
|
+
| `cleanThinkArtifacts` | `boolean` | `false` | Очистка сиротливых `</think>`, концевых маркеров reasoning и починка незакрытых блоков |
|
|
93
|
+
| `providerId` | `string` | `undefined` | *(Устарело)* Идентификатор целевого провайдера; сохранено для обратной совместимости |
|
|
94
|
+
| `modelId` | `string` | `undefined` | *(Устарело)* Идентификатор целевой модели; сохранено для обратной совместимости |
|
|
95
|
+
|
|
96
|
+
### HTTP-эндпоинты управления
|
|
97
|
+
|
|
98
|
+
| Метод | Эндпоинт | Доступ | Назначение |
|
|
99
|
+
|:---|:---|:---|:---|
|
|
100
|
+
| `GET` | `/api/dsh-dsml-artifact-guard/stats` | Web UI / Localhost | Возвращает live-телеметрию и последние перехваченные инциденты |
|
|
101
|
+
| `POST` | `/api/dsh-dsml-artifact-guard/stats` | Loopback & Same-Origin | Сбрасывает счётчики телеметрии и очищает журнал инцидентов |
|
|
102
|
+
| `GET` | `/api/dsh-dsml-artifact-guard/update` | Web UI / Localhost | Получение статуса версии и проверки обновлений |
|
|
103
|
+
| `POST` | `/api/dsh-dsml-artifact-guard/update` | Loopback & Same-Origin | Запуск автоматического обновления пакета через DSH CLI |
|
|
154
104
|
|
|
155
105
|
---
|
|
156
106
|
|
|
@@ -168,7 +118,3 @@ npm run check
|
|
|
168
118
|
## 📄 Лицензия
|
|
169
119
|
|
|
170
120
|
MIT © [GooDAnDReaDY](https://github.com/GooDAnDReaDY)
|
|
171
|
-
|
|
172
|
-
---
|
|
173
|
-
|
|
174
|
-
Полная история версий и изменений доступна в файле [CHANGELOG.md](CHANGELOG.md).
|