@goodandready/dsh-dsml-artifact-guard 0.2.13 → 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 CHANGED
@@ -7,6 +7,15 @@ 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
+
10
19
  ## [0.2.13] - 2026-10-21
11
20
 
12
21
  ### Fixed
@@ -37,121 +46,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
37
46
  ## [0.2.9] - 2026-10-07
38
47
 
39
48
  ### Fixed
40
- - **Settings Card Locale Snapshot Extraction**: safely extract active locale string from `LocaleSnapshot` object (`snap?.active`) returned by `ctx.locale.getLocale()` / `getSnapshot()`, eliminating fatal `TypeError: rawLang.startsWith is not a function` during settings card mount (#50, #57).
41
- - **Russian Language Registration & Ownership**: removed embedded `ru` dictionary from the plugin bundle to prevent `(namespace, 'ru')` duplicate registration collisions in core; delegate Russian translations to `dsh-russian-lang` via `props.t` and `ctx.locale.bind(NS)` (#58).
42
- - **Volatile Per-Field Settings Schema**: marked configuration fields volatile individually, enabling DSH to discover and generate settings form controls (#52).
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.
43
52
 
44
53
  ## [0.2.8] - 2026-09-26
45
54
 
46
55
  ### Added
47
- - **Universal DeepSeek Model Matching**: replaced strict single `providerId`/`modelId` pair with case-insensitive `modelPattern` RegExp (default: `deepseek`), automatically protecting all DeepSeek models regardless of provider gateway or vendor prefix (#48).
48
- - **Target Providers Filter**: added optional `providers` array filter (empty = all providers) (#48).
49
- - **Russian Localization**: added native `ru` translations in the Web UI settings card alongside English and Chinese (#48).
50
-
51
- ### Changed
52
- - **De-identification**: removed proprietary `opencode-go` default in public package configuration.
53
- - **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.
54
- - **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).
55
60
 
56
61
  ## [0.2.7] - 2026-09-25
57
62
 
58
63
  ### Fixed
59
- - **Volatile Config Unwrapping**: introduced `unwrapConfig` helper to gracefully handle pre-resolved volatile schema references passed by Cordis to `apply` and `ctx.on('config')`, avoiding TypeError on functions inside volatile schemas (#47).
60
-
61
- ## [0.2.6] - 2026-09-25
62
-
63
- ### Fixed
64
- - **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).
65
- - **Client Locale Lifecycle**: wrapped client locale registration in `ctx.effect` to ensure clean namespace disposal on HMR and avoid collision on module reload (#44).
66
-
67
- ## [0.2.5] - 2026-09-24
68
-
69
- ### Fixed
70
- - **Preflight & Locale Contract**: eliminated nonexistent `locale.get()` call in `lib/client.js`, using injected `props.t` with canonical `ctx.locale.bind(NS)` fallback (#36).
71
- - **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).
72
- - **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).
73
- - **Dead Code Elimination**: connected `checkRequestMethod` helper to updater POST handler (#39).
74
-
75
- ## [0.2.4] - 2026-09-22
76
-
77
- ### Fixed
78
- - The settings card no longer waits for the removed `settingsScope` service. It uses `configForms` on current DeepSeek Harness (#41).
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).
79
66
 
80
- ## [0.2.3] - 2026-09-19
67
+ ## [0.2.6] - 2026-09-24
81
68
 
82
69
  ### Fixed
83
- - **Settings reachable again on the plugin's own page**: the card registered into
84
- `settings.plugin.item` / `plugins.row.config`, and the current DSH core
85
- (0.1.6-alpha.2) only renders a plugin's configuration page for entries registered
86
- in the plugin list seat `plugins.item` — that is how `dsh-agentrouter` and
87
- `dsh-agent-orchestrator` show their settings. The view-aware `PluginItem` is now
88
- registered there as well (`id: 'dsh-dsml-artifact-guard'`, order 95, static label),
89
- with the row seat and the legacy card kept as fallbacks.
90
- - The render path was hardened on the way: `PluginCard` is wrapped in its own error
91
- boundary so a throw inside this card cannot take the whole client batch down.
92
-
93
- ## [0.2.2] - 2026-09-18
94
-
95
- ### Fixed
96
- - **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)).
97
- - **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.
98
-
99
- ---
100
-
101
- ## [0.2.1] - 2026-09-18
102
-
103
- ### Fixed
104
- - **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)).
105
- - **Theme Regression Test Guard (`test/theme.test.js`)**: Added automated regression test asserting zero hardcoded hex and rgba color literals in client surfaces.
106
- - **Repository Hygiene**: Fixed `.gitignore` whitespace rule for `AGENTS.md` and untracked `package-lock.json` in alignment with zero-dependency architecture.
107
-
108
- ---
109
-
110
- ## [0.2.0] - 2026-09-17
111
-
112
- ### Added
113
- - **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)).
114
- - **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)).
115
- - **Core Primitive Chevron**: Requested `IconChevronDownOutline14` with SVG fallback.
116
-
117
- ### Fixed
118
- - **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)).
119
- - **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)).
120
-
121
- ---
122
-
123
- ## [0.1.5] - 2026-09-17
124
-
125
- ### Documentation
126
- - 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)).
127
-
128
- ---
129
-
130
- ## [0.1.4] - 2026-09-12
131
-
132
- ### Changed
133
- - Schema `mode` default set to `sanitize` for out-of-the-box protection ([#11](https://github.com/GooDAnDReaDY/dsh-dsml-artifact-guard/issues/11)).
134
- - 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)).
135
- - Updated design contract documentation and verified package hygiene ([#11](https://github.com/GooDAnDReaDY/dsh-dsml-artifact-guard/issues/11)).
136
-
137
- ---
138
-
139
- ## [0.1.3] - 2026-09-06
140
-
141
- ### Changed
142
- - Wrapped `llm/stream` handler in `ctx.effect` for clean lifecycle unmount ([#8](https://github.com/GooDAnDReaDY/dsh-dsml-artifact-guard/issues/8)).
143
- - 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)).
144
-
145
- ---
146
-
147
- ## [0.1.2] - 2026-09-02
148
-
149
- ### Fixed
150
- - Packaging and runtime compatibility adjustments for DSH profile loader.
151
-
152
- ---
153
-
154
- ## [0.1.1] - 2026-08-30
155
-
156
- ### Added
157
- - 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>Fail-Open Stream Sanitizer for Leaked Protocol DSML Closing Tags in DeepSeek Harness</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 like this plugin, please star it on GitHub</strong> — it shows me that the plugin is useful to you and motivates me to keep developing it.
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>If you find a bug or would like to request a feature</strong>, open a GitHub issue in any language — I will review your proposal and implement useful suggestions in a future plugin version.
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
- ## ⚡ Overview & The Problem
38
+ ## ⚡ Problem & Purpose
39
39
 
40
- When interacting with certain upstream model providers or API gateways, raw DSML (DeepSeek Markup Language) tool-invocation protocol tags can leak into the assistant's visible text stream. Users frequently see trailing protocol clutter like:
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
- Done. All tests have passed.
43
+ Response completed successfully.
44
44
  </|DSML|parameter> </|DSML|invoke> </|DSML|tool_calls>
45
45
  ```
46
46
 
47
- These leaked closing tags visually pollute the chat bubble, cause Markdown rendering glitches, and can confuse downstream agents or clipboard exports.
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 lightweight, host-only runtime stream interceptor for DeepSeek Harness that cleans up these terminal artifacts in real time before they reach the user interface:
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 Stream Contract Preservation**: Cordis requires stream interceptors to return an `AsyncIterable` synchronously. Making interceptors `async` returns a `Promise` that crashes the harness turn with `stream is not async iterable`. This guard adheres strictly to the synchronous hook contract.
52
- 2. **Split Chunk Buffer Pipeline**: Protocol tags often arrive split across multiple TCP or WebSocket text deltas. The guard maintains a small sliding buffer (`KEEP = 96` bytes) to reliably match and strip multi-chunk tails.
53
- 3. **100% Fail-Open Safety**: Never drops legitimate user or assistant text. Legitimate discussions about DSML syntax or internal tool calls are preserved intact.
54
- 4. **Targeted Provider & Model Scoping**: Restricts processing specifically to the provider and model configurations that exhibit tag leakage, passing other model traffic through with zero overhead.
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 model matching and provider targets in `settings.yaml` or through the Web UI:
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" # Case-insensitive RegExp matching all DeepSeek models
159
- providers: [] # Empty = guard all providers; or e.g. ["commandcode", "deepseek-official"]
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 covering split chunks, audit vs sanitize modes, scope matching, and synchronous hook contracts:
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>Предохранитель и потоковый очиститель от артефактов закрывающих тегов протокола DSML в DeepSeek Harness</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
- Такие теги загрязняют чат, ломают рендеринг Markdown и сбивают парсинг при копировании или передаче ответов другим агентам.
47
+ Кроме того, reasoning-модели (например, DeepSeek-R1 / V3) или обрывы сетевых сессий могут оставлять сиротливые теги `</think>`, концевые маркеры (`<|end of sentence|>`) или незакрытые блоки размышлений, ломающие вёрстку Markdown.
48
48
 
49
- **`@goodandready/dsh-dsml-artifact-guard`** — легковесный плагин времени выполнения (host-only) для DeepSeek Harness, перехватывающий и удаляющий эти паразитные терминальные артефакты в реальном времени до того, как текст попадёт в интерфейс:
49
+ **`@goodandready/dsh-dsml-artifact-guard`** — легковесный плагин времени выполнения для DeepSeek Harness, перехватывающий и удаляющий эти паразитные терминальные артефакты в реальном времени до того, как текст попадёт в интерфейс:
50
50
 
51
- 1. **Строго синхронный контракт хука**: в среде Cordis обработчик события `llm/stream` обязан синхронно возвращать итератор `AsyncIterable`. Сделать обработчик асинхронным (`async`) означает вернуть `Promise`, что неизбежно приводит к падению среды выполнения с ошибкой `stream is not async iterable`. Плагин строго соблюдает синхронный контракт.
52
- 2. **Буферизация фрагментированного хвоста**: сетевые чанки часто разрезают закрывающие теги на части. Плагин использует скользящее окно размером 96 байт (`KEEP = 96`), гарантируя надёжный захват и вырезание артефакта, даже если он разделен между пакетами.
53
- 3. **100% Fail-Open архитектура**: плагин никогда не удаляет полезный пользовательский текст или легитимные обсуждения синтаксиса DSML.
54
- 4. **Адресный скоупинг (Provider & Model)**: фильтрация применяется только к целевым провайдерам и моделям, у которых наблюдается утечка протокольных тегов. Трафик остальных моделей проходит без задержек и оверхеда.
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
- Настройка провайдера и модели в `settings.yaml` или через веб-панель управления:
74
+ Настройка параметров в `settings.yaml` или через веб-панель управления:
138
75
 
139
76
  ```yaml
140
77
  # settings.yaml
141
78
  dsh-dsml-artifact-guard:
142
79
  mode: sanitize
143
- providerId: "your-provider-id"
144
- modelId: "your-model-id"
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
- | `providerId` | `string` | `"opencode-go"` | Идентификатор целевого провайдера, отдающего паразитные теги |
153
- | `modelId` | `string` | `"deepseek-v4-flash"` | Идентификатор целевой модели с артефактами |
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).