@goodandready/dsh-key-rotation 0.7.30 → 0.7.31
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/LICENSE +21 -21
- package/README.md +245 -172
- package/README.ru.md +245 -0
- package/README.zh.md +206 -0
- package/cordis.patch.yml +6 -6
- package/lib/agent-budget.js +68 -68
- package/lib/bucket.js +129 -52
- package/lib/canary.js +63 -56
- package/lib/client-helpers.js +21 -21
- package/lib/client.js +1086 -1063
- package/lib/heal.js +35 -35
- package/lib/histogram.js +66 -66
- package/lib/incident.js +76 -76
- package/lib/pool.js +264 -237
- package/lib/quota.js +39 -39
- package/lib/region.js +50 -50
- package/lib/sandbox.js +117 -117
- package/lib/shadow.js +81 -81
- package/lib/usage-report.js +79 -49
- package/lib/webhook.js +193 -133
- package/package.json +58 -58
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 GooDAnDReaDY
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,172 +1,245 @@
|
|
|
1
|
-
# dsh-key-rotation
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
>
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
1
|
+
# 📦 @goodandready/dsh-key-rotation
|
|
2
|
+
|
|
3
|
+
<div align="center">
|
|
4
|
+
|
|
5
|
+
<h3>Enterprise-Grade Transparent API Key Rotation, Rate-Limit Pre-emption & Failover Cascade for DeepSeek Harness</h3>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<a href="https://www.npmjs.com/package/@goodandready/dsh-key-rotation"><img src="https://img.shields.io/npm/v/@goodandready/dsh-key-rotation.svg?style=for-the-badge&color=6366f1&labelColor=1e1b4b" alt="npm version"></a>
|
|
9
|
+
<a href="LICENSE"><img src="https://img.shields.io/github/license/GooDAnDReaDY/dsh-key-rotation.svg?style=for-the-badge&color=10b981&labelColor=064e3b" alt="license"></a>
|
|
10
|
+
<a href="https://github.com/topics/dsh-plugin"><img src="https://img.shields.io/badge/DSH-Plugin-8b5cf6.svg?style=for-the-badge&labelColor=2e1065" alt="DSH Plugin"></a>
|
|
11
|
+
<a href="https://nodejs.org"><img src="https://img.shields.io/badge/Node-20%2B-f59e0b.svg?style=for-the-badge&labelColor=451a03" alt="Node version"></a>
|
|
12
|
+
</p>
|
|
13
|
+
|
|
14
|
+
<!-- Showcase Link -->
|
|
15
|
+
<p align="center">
|
|
16
|
+
<a href="https://goodandready.app/"><img src="https://img.shields.io/badge/🌐_DSH_Hub-goodandready.app-ff4500.svg?style=for-the-badge&labelColor=1a1a2e" alt="GoodAndReady Showcase"></a>
|
|
17
|
+
</p>
|
|
18
|
+
|
|
19
|
+
<p align="center">
|
|
20
|
+
<a href="README.md"><b>🇬🇧 English</b></a> •
|
|
21
|
+
<a href="README.ru.md"><b>🇷🇺 Русский</b></a> •
|
|
22
|
+
<a href="README.zh.md"><b>🇨🇳 中文说明</b></a>
|
|
23
|
+
</p>
|
|
24
|
+
|
|
25
|
+
</div>
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## ⚡ Overview & The Problem
|
|
30
|
+
|
|
31
|
+
### 🚀 What's New in v0.7.31
|
|
32
|
+
- **⚡ O(1) TokenBucket Accumulator**: Upgraded rate limiting math to O(1) time and zero-allocation memory with adaptive header synchronization.
|
|
33
|
+
- **🛡️ Soft vs Hard Backoff**: Differentiates transient infrastructure drops (502/503/timeouts: 10s flat cooldown) from hard quota errors (progressive doubling).
|
|
34
|
+
- **⏳ Penalty Decay**: Stable keys that operate cleanly automatically decay their failure penalty multiplier every hour.
|
|
35
|
+
- **🎲 Cooldown Jitter**: Adds ±12.5% random dispersion to recovery timers, eliminating thundering herd stampedes.
|
|
36
|
+
- **🎯 Addressable Canary Probing**: Support for probing target pool models with lightweight single-token verification pings.
|
|
37
|
+
- **📊 TTFT Percentiles (p50 / p95 / p99)**: Sub-second high-resolution latency percentile tracking across all key pools.
|
|
38
|
+
- **🔔 Webhook Alert Digest**: Aggregates multiple rapid switch/cooldown events into consolidated incident digests for Telegram, Discord, and Slack.
|
|
39
|
+
- **🧹 30-Day Usage Compaction**: Automatic bounded memory management with 30-day rolling window data pruning.
|
|
40
|
+
- **✨ Optimistic UI & Filter Pills**: Instant zero-latency UI updates on reset, plus `All`, `Ready`, `In Cooldown`, and `With Errors` quick filter chips.
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
High-throughput autonomous agent workflows, parallel subagent swarms, and multi-turn tool loops inevitably hit upstream API rate limits (HTTP 429, RPM/TPM exhaustion, daily quotas, or sudden provider outages). In standard DeepSeek Harness deployments, a single exhausted API key breaks the entire agent execution chain, requiring manual intervention and destroying the session's replay state.
|
|
44
|
+
|
|
45
|
+
**`dsh-key-rotation`** provides a seamless, enterprise-ready **transparent API key pooling, pre-emptive rate-limiting, and cross-provider failover engine** built natively on the Cordis microkernel architecture.
|
|
46
|
+
|
|
47
|
+
Unlike naive routing proxies that alter provider identifiers, `dsh-key-rotation` hooks into `ctx.credentials.resolve` and intercepts `llm/stream` at runtime:
|
|
48
|
+
* **The provider identity never changes**: Agent replay states, multi-call turns, and tool schemas remain 100% consistent.
|
|
49
|
+
* **Pre-emptive Token Bucket**: Throttled keys are skipped *before* issuing network calls, eliminating retry latency.
|
|
50
|
+
* **Least-Connections Concurrency Control**: Balances in-flight streams across keys to prevent burst saturation.
|
|
51
|
+
* **Autonomous Self-Healing & Cascades**: Proactively tests quarantined keys via canary probes and smoothly escalates to fallback providers if an entire pool is exhausted.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## 🏗️ Architecture & Request Lifecycle
|
|
56
|
+
|
|
57
|
+
```mermaid
|
|
58
|
+
graph LR
|
|
59
|
+
subgraph ClientLayer ["Client & Agent Turn"]
|
|
60
|
+
UserMsg["User / Subagent Message"] --> Adapter["pi-ai Model Adapter"]
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
subgraph RotationEngine ["dsh-key-rotation Core Engine"]
|
|
64
|
+
Adapter --> StreamHook["llm/stream Interceptor"]
|
|
65
|
+
StreamHook --> BucketCheck{"Token Bucket\nRPM / TPM Check"}
|
|
66
|
+
BucketCheck -->|Under Limit| ConcurrencyCheck{"Concurrency Tracker\nLeast-Connections"}
|
|
67
|
+
BucketCheck -->|Exceeded| NextKey1["Pick Next Healthy Key"]
|
|
68
|
+
ConcurrencyCheck -->|Slot Available| KeyResolver["ctx.credentials.resolve"]
|
|
69
|
+
ConcurrencyCheck -->|Saturated| NextKey1
|
|
70
|
+
|
|
71
|
+
KeyResolver --> ActiveKey["Active Key (In Use)"]
|
|
72
|
+
|
|
73
|
+
ActiveKey -.->|HTTP 429 / Quota / Error| Failover["Instant Failover Handler"]
|
|
74
|
+
Failover --> BackoffCalc["Exponential Backoff & Quarantine"]
|
|
75
|
+
Failover --> NextKey2["Retry Next Key (Zero Token Loss)"]
|
|
76
|
+
Failover -.->|All Pool Keys Exhausted| CascadeEngine["Cross-Provider Cascade"]
|
|
77
|
+
|
|
78
|
+
BackoffCalc --> QuotaWindow["Calendar Reset / Midnight Window"]
|
|
79
|
+
BackoffCalc --> CanaryProbe["Active Canary Prober (Sandbox Ping)"]
|
|
80
|
+
CanaryProbe -->|Verified Healthy| PoolReady["Restored to Ready Pool"]
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
subgraph UpstreamLayer ["Model Provider Endpoints"]
|
|
84
|
+
ActiveKey --> UpstreamAPI["Primary Provider API"]
|
|
85
|
+
CascadeEngine --> FallbackAPI["Backup Provider API"]
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
style ClientLayer fill:#1e1e2e,stroke:#89b4fa,stroke-width:2px,color:#cdd6f4
|
|
89
|
+
style RotationEngine fill:#181825,stroke:#cba6f7,stroke-width:2px,color:#cdd6f4
|
|
90
|
+
style UpstreamLayer fill:#11111b,stroke:#a6e3a1,stroke-width:2px,color:#cdd6f4
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## ✨ Full Feature Breakdown
|
|
96
|
+
|
|
97
|
+
### 🔄 1. Transparent Rotation & Failover
|
|
98
|
+
* **Unchanged Provider Identity**: Rotates only the underlying resolved API credential ref, never the provider ID. Prevents `INVALID_REPLAY_STATE` crashes in `pi-ai` multi-turn sessions.
|
|
99
|
+
* **Zero-Token-Loss Stream Retries**: If an API key encounters an error before the first content chunk is emitted, the request is transparently re-dispatched to the next healthy key in the pool.
|
|
100
|
+
* **Comprehensive Switch Codes**: Automatically fails over on `QUOTA`, `RATE_LIMIT`, `SERVER`, `TIMEOUT`, `TRANSPORT`, `EMPTY_RESPONSE`, `UNKNOWN_MODEL`, `AUTH`, and `INVALID` error codes.
|
|
101
|
+
* **Intelligent Message Pattern Matching**: Fallback regex classifier (`SWITCHABLE_MESSAGE_PATTERN`) identifies text-based quota/rate-limit errors thrown as generic exceptions by upstream SDKs.
|
|
102
|
+
* **Non-Streaming Safety Net**: Synchronous calls (e.g., embeddings, batch evaluations) are protected via the `agent/request-error` lifecycle hook.
|
|
103
|
+
|
|
104
|
+
### ⏱️ 2. Rate-Limit Pre-emption & Concurrency Control
|
|
105
|
+
* **Token Bucket / Leaky Bucket (`lib/bucket.js`)**: Sliding-window tracking of Requests Per Minute (`rpmLimit`) and Tokens Per Minute (`tpmLimit`). Quarantines saturated keys *before* dispatching network requests, preventing 429 roundtrips.
|
|
106
|
+
* **Least-Connections Balancer (`lib/concurrency.js`)**: Tracks active in-flight streams per key (`inFlight`). Distributes concurrent requests evenly across available credentials and enforces `maxConcurrency` limits.
|
|
107
|
+
* **Stale Lock Auto-Release**: Deadlocks from disconnected clients or aborted network sockets are automatically purged after 5 minutes.
|
|
108
|
+
|
|
109
|
+
### 🛡️ 3. Autonomous Healing & Cascade Escalation
|
|
110
|
+
* **Cross-Provider Failover Cascade (`lib/cascade.js`)**: If all keys for a selected provider are in cooldown, requests automatically cascade to an alternative fallback provider pool (e.g., primary provider → fallback proxy / secondary provider).
|
|
111
|
+
* **Active Canary Prober (`lib/canary.js`)**: Before releasing a key from quarantine, a lightweight background probe (`/models` probe or single-token check via `SandboxRunner`) validates upstream availability without exposing real user traffic to risk.
|
|
112
|
+
* **Calendar & Rolling Quota Reset Windows (`lib/quota-window.js`)**: Supports scheduled quota reset alignments (`midnight_utc`, `midnight_pst`, and `rolling_24h`) so daily free/tier quotas unfreeze exactly when upstream resets them.
|
|
113
|
+
* **Adaptive Exponential Backoff (`lib/pool.js`)**: Successive failures on a key double its quarantine duration (base → ×2 → ×4 → cap ×8). Successful requests gradually restore healthy status.
|
|
114
|
+
|
|
115
|
+
### 🎯 4. Model-Aware & Geolocation Routing
|
|
116
|
+
* **Model Sub-Pools (`lib/pool.js`)**: Configure dedicated key pools for specific model tiers (e.g. reasoning/heavy models vs fast/cheap utility models).
|
|
117
|
+
* **Tag-Based Routing**: Assign operational tags (`production`, `background`, `eval`) to match key usage with workload priorities.
|
|
118
|
+
* **Region Mapping (`lib/region.js`)**: Route queries through geographically optimal credentials and endpoints.
|
|
119
|
+
|
|
120
|
+
### 📊 5. Observability, Telemetry & Webhooks
|
|
121
|
+
* **Interactive Multi-Platform Webhooks (`lib/webhook.js`)**: Dispatches rich notifications with HMAC-signed action buttons for **Telegram** (Inline Keyboards), **Discord** (Action Rows), and **Slack** (Block Kit). Administrators can click buttons to reset cooldowns or pause providers directly from their mobile chat.
|
|
122
|
+
* **Usage & Cost Reporting (`lib/usage-report.js`)**: Per-key daily request counters and estimated cost breakdown with one-click CSV/JSON export (`GET /dsh-key-rotation/usage-report`).
|
|
123
|
+
* **Latency SLO & Histogram (`lib/histogram.js`)**: Tracks Time-To-First-Token (TTFT) and stream durations with health score degradation scoring (`0..100`).
|
|
124
|
+
* **Automated Incident Reporting (`lib/incident.js`)**: Lazily creates structured GitHub Issues on sustained upstream outages.
|
|
125
|
+
* **Shadow Traffic Routing (`lib/shadow.js`)**: Fork a configurable percentage of live requests to evaluate secondary providers in shadow mode.
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## 🖥️ Rich Web GUI & Dashboard
|
|
130
|
+
|
|
131
|
+
Access full visual management under **Settings → Key Rotation** or via the Header quick-widget.
|
|
132
|
+
|
|
133
|
+
| Interface Feature | Description |
|
|
134
|
+
|---|---|
|
|
135
|
+
| **Header Status Widget** | Compact live badge in DSH header: 🟢 `All Healthy` \| 🟡 `Cooldown Active` \| 🔴 `Pool Exhausted` with quick popover actions. |
|
|
136
|
+
| **1-Click Health Matrix** | "Health Matrix" dashboard running parallel sandbox probes across all providers, keys, and models with TTFT latency and status badges. |
|
|
137
|
+
| **Instant Key Provisioning** | Add keys with auto-generated names (`<PROVIDER>_API_KEY`, `_2`, `_3`) and automatic key-tail disambiguation. |
|
|
138
|
+
| **Live Status Badges** | Visual states: `In Use`, `Ready`, `Cooling Down` (with live countdown timer), and `Not Found`. |
|
|
139
|
+
| **Drag & Priority Ordering** | Reorder keys with <kbd>↑</kbd> and <kbd>↓</kbd> buttons to fine-tune selection precedence. |
|
|
140
|
+
| **Switch Code Toggles** | Interactive checkboxes for switchable error conditions. |
|
|
141
|
+
| **Secret Leak Detector** | Real-time input sanitizer (`lib/keycheck.js`) catching accidental pastes of private keys, SSH keys, or misplaced tokens. |
|
|
142
|
+
| **Batch `.env` Import** | Parse standard `.env` key-value pairs directly into corresponding provider pools. |
|
|
143
|
+
| **5-Second Undo Bar** | Non-destructive undo bar for accidental key or pool removals. |
|
|
144
|
+
| **Usage Analytics Chart** | Interactive breakdown of lifetime requests and daily trends per key. |
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## 🔒 Security & Safe Storage
|
|
149
|
+
|
|
150
|
+
* **Zero Plaintext Secrets in Plugin Config**: Configuration files store only environment variable reference names (e.g. `MY_PROVIDER_API_KEY`).
|
|
151
|
+
* **Secure Vault Storage**: Actual secret values reside securely in `$DSH_HOME/.credentials.yaml` managed by the DSH `Credentials` service.
|
|
152
|
+
* **5-Character Masking (`keyTail`)**: Full secret values are never sent to the client browser; only the trailing 5 characters are exposed for visual identification.
|
|
153
|
+
* **Loopback & Same-Origin Fencing**: Administrative endpoints (`GET /status`, `PUT /key`, `POST /reset`, `POST /test-matrix`) strictly enforce loopback origin checks (`isTrustedBridgeRequest`).
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## 📦 Installation
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
# Install via DSH Plugin Manager (Web Profile):
|
|
161
|
+
dsh plugin --profile web add @goodandready/dsh-key-rotation
|
|
162
|
+
|
|
163
|
+
# Or directly from GitHub:
|
|
164
|
+
dsh plugin --profile web add github:GooDAnDReaDY/dsh-key-rotation
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
> [!IMPORTANT]
|
|
168
|
+
> Restart DeepSeek Harness web service after installation and refresh your browser tab:
|
|
169
|
+
> ```bash
|
|
170
|
+
> systemctl --user restart dsh-web
|
|
171
|
+
> ```
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## ⚙️ Configuration Reference (`settings.yaml`)
|
|
176
|
+
|
|
177
|
+
```yaml
|
|
178
|
+
dsh-key-rotation:
|
|
179
|
+
switchCodes:
|
|
180
|
+
- QUOTA
|
|
181
|
+
- RATE_LIMIT
|
|
182
|
+
- SERVER
|
|
183
|
+
- TIMEOUT
|
|
184
|
+
- TRANSPORT
|
|
185
|
+
- EMPTY_RESPONSE
|
|
186
|
+
- UNKNOWN_MODEL
|
|
187
|
+
- AUTH
|
|
188
|
+
cooldownMs: 60000
|
|
189
|
+
canaryProbing: true
|
|
190
|
+
concurrencyLimit: 5
|
|
191
|
+
quotaResetWindow:
|
|
192
|
+
type: midnight_utc
|
|
193
|
+
hour: 0
|
|
194
|
+
cascade:
|
|
195
|
+
- provider: backup-provider-id
|
|
196
|
+
model: your-backup-model-id
|
|
197
|
+
webhookUrl: "https://api.telegram.org/bot<TOKEN>/sendMessage?chat_id=<CHAT_ID>"
|
|
198
|
+
providers:
|
|
199
|
+
- provider: your-primary-provider
|
|
200
|
+
rpmLimit: 60
|
|
201
|
+
tpmLimit: 100000
|
|
202
|
+
keys:
|
|
203
|
+
- PRIMARY_API_KEY
|
|
204
|
+
- PRIMARY_API_KEY_2
|
|
205
|
+
- PRIMARY_API_KEY_BACKUP
|
|
206
|
+
- provider: secondary-provider
|
|
207
|
+
keys:
|
|
208
|
+
- SECONDARY_API_KEY
|
|
209
|
+
- SECONDARY_API_KEY_2
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Parameter Reference
|
|
213
|
+
|
|
214
|
+
| Parameter | Type | Default | Description |
|
|
215
|
+
|---|---|---|---|
|
|
216
|
+
| `switchCodes` | `string[]` | `[QUOTA, RATE_LIMIT, ...]` | List of error codes that immediately trigger failover. |
|
|
217
|
+
| `cooldownMs` | `number` | `60000` (1 min) | Base penalty duration (in ms) for quarantined keys. |
|
|
218
|
+
| `canaryProbing` | `boolean` | `true` | Runs background ping probe before restoring quarantined keys. |
|
|
219
|
+
| `concurrencyLimit` | `number` | `0` (disabled) | Max concurrent in-flight streams per key (0 = unlimited). |
|
|
220
|
+
| `quotaResetWindow` | `object` | `null` | Calendar reset alignment (`midnight_utc`, `midnight_pst`, `rolling_24h`). |
|
|
221
|
+
| `cascade` | `array` | `[]` | Fallback provider chain when primary pool is completely exhausted. |
|
|
222
|
+
| `webhookUrl` | `string` | `""` | Target URL for interactive Telegram, Discord, Slack, or generic alerts. |
|
|
223
|
+
| `providers` | `array` | `[]` | List of `{ provider, keys, rpmLimit, tpmLimit, modelPools }` definitions. |
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## 🔌 HTTP Bridge API Reference
|
|
228
|
+
|
|
229
|
+
All management routes require loopback authentication (`127.0.0.1` / `::1`) with same-origin validation:
|
|
230
|
+
|
|
231
|
+
| Route | Method | Description |
|
|
232
|
+
|---|---|---|
|
|
233
|
+
| `/dsh-key-rotation/status` | `GET` | Returns real-time health snapshots, active keys, and cooldown states. |
|
|
234
|
+
| `/dsh-key-rotation/config` | `GET` / `PUT` | Read and update active key rotation settings and provider pools. |
|
|
235
|
+
| `/dsh-key-rotation/key` | `PUT` / `DELETE` | Add, update, or remove credentials in host storage and pool. |
|
|
236
|
+
| `/dsh-key-rotation/reset` | `POST` | Instantly resets all cooldowns and restores all keys to `ready`. |
|
|
237
|
+
| `/dsh-key-rotation/test-matrix` | `POST` | Triggers parallel health check across all configured keys and models. |
|
|
238
|
+
| `/dsh-key-rotation/usage-report` | `GET` | Returns aggregated usage metrics in JSON or CSV format (`?format=csv`). |
|
|
239
|
+
| `/dsh-key-rotation/webhook-callback`| `POST` | Receives and executes interactive actions from Telegram/Slack callbacks. |
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## 📄 License
|
|
244
|
+
|
|
245
|
+
MIT © [GooDAnDReaDY](https://github.com/GooDAnDReaDY)
|