@leaves615/dsh-llm-ctl 0.1.0
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 -0
- package/README.md +174 -0
- package/cordis.patch.yml +7 -0
- package/lib/client-plugin.d.ts +82 -0
- package/lib/client-plugin.js +685 -0
- package/lib/client.js +1712 -0
- package/lib/concurrency.d.ts +28 -0
- package/lib/concurrency.js +36 -0
- package/lib/config.d.ts +203 -0
- package/lib/config.js +67 -0
- package/lib/controller.d.ts +42 -0
- package/lib/controller.js +51 -0
- package/lib/delay.d.ts +68 -0
- package/lib/delay.js +134 -0
- package/lib/discover-ui.d.ts +94 -0
- package/lib/discover-ui.js +91 -0
- package/lib/discover.d.ts +79 -0
- package/lib/discover.js +141 -0
- package/lib/events.d.ts +45 -0
- package/lib/events.js +37 -0
- package/lib/index.d.ts +38 -0
- package/lib/index.js +378 -0
- package/lib/menu-filter.d.ts +134 -0
- package/lib/menu-filter.js +428 -0
- package/lib/menu-visibility.d.ts +26 -0
- package/lib/menu-visibility.js +77 -0
- package/lib/queue-dock.d.ts +85 -0
- package/lib/queue-dock.js +291 -0
- package/lib/queue.d.ts +128 -0
- package/lib/queue.js +313 -0
- package/lib/reactive.d.ts +57 -0
- package/lib/reactive.js +75 -0
- package/lib/reasoning-efforts.d.ts +120 -0
- package/lib/reasoning-efforts.js +143 -0
- package/lib/routes.d.ts +126 -0
- package/lib/routes.js +267 -0
- package/lib/settings-ui.d.ts +183 -0
- package/lib/settings-ui.js +367 -0
- package/lib/visibility-settings.d.ts +193 -0
- package/lib/visibility-settings.js +225 -0
- package/lib/visibility.d.ts +152 -0
- package/lib/visibility.js +235 -0
- package/package.json +92 -0
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Model visibility: two-level switches plus wildcard presets.
|
|
3
|
+
*
|
|
4
|
+
* Priority, highest first: an explicit `models['provider:model']` entry, an
|
|
5
|
+
* explicit `providers[provider]` entry, a matching `hiddenPatterns` entry,
|
|
6
|
+
* visible by default. A provider switched off hides every one of its models,
|
|
7
|
+
* even one carrying an explicit `true`.
|
|
8
|
+
*
|
|
9
|
+
* @module dsh-llm-ctl/visibility
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Canonical form of a wildcard pattern: surrounding whitespace trimmed and
|
|
13
|
+
* lower-cased. Matching is case-insensitive, so this is the form compared.
|
|
14
|
+
*
|
|
15
|
+
* @param pattern Raw pattern, as written in configuration.
|
|
16
|
+
* @returns The trimmed, lower-cased pattern.
|
|
17
|
+
*/
|
|
18
|
+
export function normalizePattern(pattern) {
|
|
19
|
+
return pattern.trim().toLowerCase();
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Greedy wildcard match where `*` consumes any run of characters, `:`
|
|
23
|
+
* included. Every other character, including `?` and `[]`, is literal.
|
|
24
|
+
*
|
|
25
|
+
* @param pattern Lower-cased pattern containing at most `*` metacharacters.
|
|
26
|
+
* @param value Lower-cased candidate string.
|
|
27
|
+
* @returns True when the whole value is consumed by the pattern.
|
|
28
|
+
*/
|
|
29
|
+
function globMatch(pattern, value) {
|
|
30
|
+
let p = 0;
|
|
31
|
+
let v = 0;
|
|
32
|
+
let star = -1;
|
|
33
|
+
let resume = 0;
|
|
34
|
+
while (v < value.length) {
|
|
35
|
+
if (p < pattern.length && pattern[p] === '*') {
|
|
36
|
+
star = p;
|
|
37
|
+
resume = v;
|
|
38
|
+
p += 1;
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
if (p < pattern.length && pattern[p] === value[v]) {
|
|
42
|
+
p += 1;
|
|
43
|
+
v += 1;
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
if (star >= 0) {
|
|
47
|
+
p = star + 1;
|
|
48
|
+
resume += 1;
|
|
49
|
+
v = resume;
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
while (p < pattern.length && pattern[p] === '*')
|
|
55
|
+
p += 1;
|
|
56
|
+
return p === pattern.length;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Test one wildcard pattern against a provider/model pair.
|
|
60
|
+
*
|
|
61
|
+
* `*` is the only metacharacter and matches any run of characters, `:`
|
|
62
|
+
* included. A pattern may be written `provider:model` or, omitting the
|
|
63
|
+
* provider segment, as a model-only pattern that applies to every provider.
|
|
64
|
+
* When `model` is omitted only a pattern covering a whole provider
|
|
65
|
+
* (`p:*`, `p:`) can match.
|
|
66
|
+
*
|
|
67
|
+
* @param pattern Pattern to test, with or without a provider segment.
|
|
68
|
+
* @param provider Provider id to test.
|
|
69
|
+
* @param model Model id to test; omit to ask about the provider as a whole.
|
|
70
|
+
* @returns True when the pattern matches the pair.
|
|
71
|
+
*/
|
|
72
|
+
export function matchesPattern(pattern, provider, model) {
|
|
73
|
+
const normalized = normalizePattern(pattern);
|
|
74
|
+
const separator = normalized.indexOf(':');
|
|
75
|
+
const providerGlob = separator < 0 ? '*' : normalized.slice(0, separator);
|
|
76
|
+
const modelGlob = separator < 0 ? normalized : normalized.slice(separator + 1);
|
|
77
|
+
if (!globMatch(providerGlob, provider.trim().toLowerCase()))
|
|
78
|
+
return false;
|
|
79
|
+
return globMatch(modelGlob, model === undefined ? '' : model.trim().toLowerCase());
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* True when any configured preset pattern matches the pair.
|
|
83
|
+
*
|
|
84
|
+
* @param config Composition config carrying the presets; may be undefined.
|
|
85
|
+
* @param provider Provider id to test.
|
|
86
|
+
* @param model Model id to test, or undefined for the provider as a whole.
|
|
87
|
+
* @returns True when at least one pattern hits.
|
|
88
|
+
*/
|
|
89
|
+
function matchesAnyPattern(config, provider, model) {
|
|
90
|
+
const patterns = config?.hiddenPatterns;
|
|
91
|
+
if (patterns === undefined)
|
|
92
|
+
return false;
|
|
93
|
+
return patterns.some((pattern) => matchesPattern(pattern, provider, model));
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Whether a provider is switched on.
|
|
97
|
+
*
|
|
98
|
+
* An explicit `providers[provider]` entry wins; otherwise a preset pattern
|
|
99
|
+
* covering the provider's whole model set (`p:*`, `p:`) hides it; otherwise
|
|
100
|
+
* it is visible.
|
|
101
|
+
*
|
|
102
|
+
* @param provider Provider id.
|
|
103
|
+
* @param settings Two-level switches.
|
|
104
|
+
* @param config Composition config with preset patterns; may be omitted.
|
|
105
|
+
* @returns True when the provider is visible.
|
|
106
|
+
*/
|
|
107
|
+
export function isProviderVisible(provider, settings, config) {
|
|
108
|
+
const explicit = settings.providers[provider];
|
|
109
|
+
if (explicit !== undefined)
|
|
110
|
+
return explicit;
|
|
111
|
+
return !matchesAnyPattern(config, provider, undefined);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Whether one model is switched on, resolving the full priority chain.
|
|
115
|
+
*
|
|
116
|
+
* A provider explicitly set to `false` hides all of its models. Otherwise an
|
|
117
|
+
* explicit `models` entry wins, then an explicit `providers` entry, then a
|
|
118
|
+
* matching preset pattern, then the visible default.
|
|
119
|
+
*
|
|
120
|
+
* @param provider Provider id.
|
|
121
|
+
* @param model Model id.
|
|
122
|
+
* @param settings Two-level switches.
|
|
123
|
+
* @param config Composition config with preset patterns; may be omitted.
|
|
124
|
+
* @returns True when the model is visible.
|
|
125
|
+
*/
|
|
126
|
+
export function isModelVisible(provider, model, settings, config) {
|
|
127
|
+
if (settings.providers[provider] === false)
|
|
128
|
+
return false;
|
|
129
|
+
const explicitModel = settings.models[modelKey(provider, model)];
|
|
130
|
+
if (explicitModel !== undefined)
|
|
131
|
+
return explicitModel;
|
|
132
|
+
const explicitProvider = settings.providers[provider];
|
|
133
|
+
if (explicitProvider !== undefined)
|
|
134
|
+
return explicitProvider;
|
|
135
|
+
return !matchesAnyPattern(config, provider, model);
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Key under which one model's switch is stored.
|
|
139
|
+
*
|
|
140
|
+
* @param provider Provider id.
|
|
141
|
+
* @param model Model id.
|
|
142
|
+
* @returns The `provider:model` key used by {@link VisibilitySettings.models}.
|
|
143
|
+
*/
|
|
144
|
+
export function modelKey(provider, model) {
|
|
145
|
+
return `${provider}:${model}`;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Return a new settings object with one provider switch written.
|
|
149
|
+
*
|
|
150
|
+
* The input is never mutated, and a repeated write of the same value still
|
|
151
|
+
* returns a fresh object so callers can diff by identity.
|
|
152
|
+
*
|
|
153
|
+
* @param settings Two-level switches; left untouched.
|
|
154
|
+
* @param provider Provider id.
|
|
155
|
+
* @param visible Whether the provider is visible.
|
|
156
|
+
* @returns A new settings object.
|
|
157
|
+
*/
|
|
158
|
+
export function setProviderVisible(settings, provider, visible) {
|
|
159
|
+
return { providers: { ...settings.providers, [provider]: visible }, models: { ...settings.models } };
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Return a new settings object with one model switch written.
|
|
163
|
+
*
|
|
164
|
+
* The input is never mutated, and a repeated write of the same value still
|
|
165
|
+
* returns a fresh object so callers can diff by identity.
|
|
166
|
+
*
|
|
167
|
+
* @param settings Two-level switches; left untouched.
|
|
168
|
+
* @param provider Provider id.
|
|
169
|
+
* @param model Model id.
|
|
170
|
+
* @param visible Whether the model is visible.
|
|
171
|
+
* @returns A new settings object.
|
|
172
|
+
*/
|
|
173
|
+
export function setModelVisible(settings, provider, model, visible) {
|
|
174
|
+
return { providers: { ...settings.providers }, models: { ...settings.models, [modelKey(provider, model)]: visible } };
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Return an empty settings object, i.e. every provider and model visible.
|
|
178
|
+
*
|
|
179
|
+
* @param settings Two-level switches; left untouched.
|
|
180
|
+
* @returns A new settings object with both tables empty.
|
|
181
|
+
*/
|
|
182
|
+
export function setAllVisible(settings) {
|
|
183
|
+
return { providers: {}, models: {} };
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Split a catalog into visible and hidden rows, preserving input order.
|
|
187
|
+
*
|
|
188
|
+
* Rows are neither copied nor modified; both arrays hold the original objects.
|
|
189
|
+
*
|
|
190
|
+
* @param entries Catalog rows to partition.
|
|
191
|
+
* @param settings Two-level switches.
|
|
192
|
+
* @param config Composition config with preset patterns; may be omitted.
|
|
193
|
+
* @returns The visible rows and the hidden rows, each in input order.
|
|
194
|
+
*/
|
|
195
|
+
export function filterCatalog(entries, settings, config) {
|
|
196
|
+
const visible = [];
|
|
197
|
+
const hidden = [];
|
|
198
|
+
for (const entry of entries) {
|
|
199
|
+
if (isModelVisible(entry.provider, entry.model, settings, config))
|
|
200
|
+
visible.push(entry);
|
|
201
|
+
else
|
|
202
|
+
hidden.push(entry);
|
|
203
|
+
}
|
|
204
|
+
return { visible, hidden };
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* How many catalog rows the current switches hide.
|
|
208
|
+
*
|
|
209
|
+
* @param entries Catalog rows to inspect.
|
|
210
|
+
* @param settings Two-level switches.
|
|
211
|
+
* @param config Composition config with preset patterns; may be omitted.
|
|
212
|
+
* @returns The hidden row count, equal to `filterCatalog(...).hidden.length`.
|
|
213
|
+
*/
|
|
214
|
+
export function hiddenCount(entries, settings, config) {
|
|
215
|
+
return filterCatalog(entries, settings, config).hidden.length;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Choose the fallback model when the current selection is hidden.
|
|
219
|
+
*
|
|
220
|
+
* @param current The selection to validate; it need not appear in `entries`.
|
|
221
|
+
* @param entries Candidate catalog rows, scanned in order.
|
|
222
|
+
* @param settings Two-level switches.
|
|
223
|
+
* @param config Composition config with preset patterns; may be omitted.
|
|
224
|
+
* @returns Undefined when `current` is visible, else the first visible entry,
|
|
225
|
+
* else undefined when nothing is visible.
|
|
226
|
+
*/
|
|
227
|
+
export function pickFallback(current, entries, settings, config) {
|
|
228
|
+
if (isModelVisible(current.provider, current.model, settings, config))
|
|
229
|
+
return undefined;
|
|
230
|
+
for (const entry of entries) {
|
|
231
|
+
if (isModelVisible(entry.provider, entry.model, settings, config))
|
|
232
|
+
return entry;
|
|
233
|
+
}
|
|
234
|
+
return undefined;
|
|
235
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@leaves615/dsh-llm-ctl",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "DSH plugin — rate-limit queuing, provider cooldown, and standalone request recovery on the llm/stream and agent/request-error seams",
|
|
5
|
+
"author": "leaves chen <leaves615@gmail.com>",
|
|
6
|
+
"homepage": "https://github.com/leaves615/dsh-llm-ctl#readme",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/leaves615/dsh-llm-ctl.git"
|
|
10
|
+
},
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/leaves615/dsh-llm-ctl/issues"
|
|
13
|
+
},
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=22"
|
|
16
|
+
},
|
|
17
|
+
"type": "module",
|
|
18
|
+
"main": "lib/index.js",
|
|
19
|
+
"types": "lib/index.d.ts",
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"types": "./lib/index.d.ts",
|
|
23
|
+
"default": "./lib/index.js"
|
|
24
|
+
},
|
|
25
|
+
"./client": {
|
|
26
|
+
"types": "./lib/client-plugin.d.ts",
|
|
27
|
+
"default": "./lib/client.js"
|
|
28
|
+
},
|
|
29
|
+
"./package.json": "./package.json"
|
|
30
|
+
},
|
|
31
|
+
"dsh": {
|
|
32
|
+
"bundle": {
|
|
33
|
+
"patch": "./cordis.patch.yml"
|
|
34
|
+
},
|
|
35
|
+
"client": {
|
|
36
|
+
"platform": "web",
|
|
37
|
+
"inject": [
|
|
38
|
+
"@deepseek-ai/dsh-api-remotes",
|
|
39
|
+
"@deepseek-ai/dsh-client-ui-conversation",
|
|
40
|
+
"@deepseek-ai/dsh-client-ui-settings-models",
|
|
41
|
+
"@deepseek-ai/dsh-client-ui-settings-plugins"
|
|
42
|
+
]
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"scripts": {
|
|
46
|
+
"build": "tsc -p tsconfig.build.json && node scripts/build-client.mjs",
|
|
47
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
48
|
+
"test": "node --test \"test/*.test.ts\"",
|
|
49
|
+
"verify": "npm run typecheck && npm run build && npm test && ./scripts/smoke-boot.sh",
|
|
50
|
+
"clean": "rm -rf lib"
|
|
51
|
+
},
|
|
52
|
+
"keywords": [
|
|
53
|
+
"dsh",
|
|
54
|
+
"plugin",
|
|
55
|
+
"rate-limit",
|
|
56
|
+
"queue",
|
|
57
|
+
"llm",
|
|
58
|
+
"deepseek",
|
|
59
|
+
"harness"
|
|
60
|
+
],
|
|
61
|
+
"license": "MIT",
|
|
62
|
+
"publishConfig": {
|
|
63
|
+
"access": "public"
|
|
64
|
+
},
|
|
65
|
+
"files": [
|
|
66
|
+
"lib",
|
|
67
|
+
"cordis.patch.yml",
|
|
68
|
+
"README.md",
|
|
69
|
+
"LICENSE"
|
|
70
|
+
],
|
|
71
|
+
"peerDependencies": {
|
|
72
|
+
"@deepseek-ai/cordis": "^4.0.2",
|
|
73
|
+
"@deepseek-ai/dsh-typert-protocol": "^0.1.2-rc.1",
|
|
74
|
+
"@deepseek-ai/schemastery": "^3.18.2"
|
|
75
|
+
},
|
|
76
|
+
"devDependencies": {
|
|
77
|
+
"@deepseek-ai/cordis": "^4.0.2",
|
|
78
|
+
"@deepseek-ai/dsh-agent": "0.1.2-rc.1",
|
|
79
|
+
"@deepseek-ai/dsh-llm": "0.1.2-rc.1",
|
|
80
|
+
"@deepseek-ai/dsh-typert-protocol": "0.1.2-rc.1",
|
|
81
|
+
"@deepseek-ai/schemastery": "^3.18.2",
|
|
82
|
+
"@types/jsdom": "^30.0.0",
|
|
83
|
+
"@types/node": "^22.20.0",
|
|
84
|
+
"@types/react": "^18.3.31",
|
|
85
|
+
"@types/react-dom": "^18.3.0",
|
|
86
|
+
"esbuild": "^0.28.2",
|
|
87
|
+
"jsdom": "^29.1.1",
|
|
88
|
+
"react": "^18.3.1",
|
|
89
|
+
"react-dom": "^18.3.1",
|
|
90
|
+
"typescript": "^5.9.3"
|
|
91
|
+
}
|
|
92
|
+
}
|