dsh-plugin-model-proxy 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 +157 -0
- package/cordis.patch.yml +15 -0
- package/lib/client/ModelProxyCard.d.ts +14 -0
- package/lib/client/ModelProxyCard.d.ts.map +1 -0
- package/lib/client/catalog.d.ts +140 -0
- package/lib/client/catalog.d.ts.map +1 -0
- package/lib/client/controller.d.ts +107 -0
- package/lib/client/controller.d.ts.map +1 -0
- package/lib/client/index.d.ts +8 -0
- package/lib/client/index.d.ts.map +1 -0
- package/lib/client/locales.d.ts +106 -0
- package/lib/client/locales.d.ts.map +1 -0
- package/lib/client.js +1129 -0
- package/lib/client.js.map +7 -0
- package/lib/host/config.d.ts +47 -0
- package/lib/host/config.d.ts.map +1 -0
- package/lib/host/config.js +153 -0
- package/lib/host/config.js.map +1 -0
- package/lib/host/credentials.d.ts +24 -0
- package/lib/host/credentials.d.ts.map +1 -0
- package/lib/host/credentials.js +45 -0
- package/lib/host/credentials.js.map +1 -0
- package/lib/host/dispatcher.d.ts +30 -0
- package/lib/host/dispatcher.d.ts.map +1 -0
- package/lib/host/dispatcher.js +167 -0
- package/lib/host/dispatcher.js.map +1 -0
- package/lib/host/fetch-wrap.d.ts +45 -0
- package/lib/host/fetch-wrap.d.ts.map +1 -0
- package/lib/host/fetch-wrap.js +100 -0
- package/lib/host/fetch-wrap.js.map +1 -0
- package/lib/host/index.d.ts +18 -0
- package/lib/host/index.d.ts.map +1 -0
- package/lib/host/index.js +262 -0
- package/lib/host/index.js.map +1 -0
- package/lib/host/probe.d.ts +30 -0
- package/lib/host/probe.d.ts.map +1 -0
- package/lib/host/probe.js +43 -0
- package/lib/host/probe.js.map +1 -0
- package/lib/invariant.d.ts +5 -0
- package/lib/invariant.d.ts.map +1 -0
- package/lib/invariant.js +7 -0
- package/lib/invariant.js.map +1 -0
- package/package.json +95 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 dsh-plugin-model-proxy contributors
|
|
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
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# dsh-plugin-model-proxy
|
|
2
|
+
|
|
3
|
+
Community DSH plugin: route **specific provider/model pairs** through specific proxies (`http://`, `https://`, `socks5://`, `socks5h://`) — with a **Settings UI**.
|
|
4
|
+
|
|
5
|
+
## Why
|
|
6
|
+
|
|
7
|
+
Some model endpoints are only reachable through a proxy while their siblings
|
|
8
|
+
connect fine — for instance `opencode/muse-spark-1.2-contributor` may answer
|
|
9
|
+
`403 RegionError` to direct connections that other models from the same
|
|
10
|
+
provider never see. The coarse fixes don't help: process-wide proxy
|
|
11
|
+
environment variables drag every request through the tunnel, and swapping a
|
|
12
|
+
whole provider's `baseURL` hides the real upstream. This plugin routes
|
|
13
|
+
**specific provider/model pairs** at the transport layer instead — everything
|
|
14
|
+
else stays direct, and the configured endpoint is never rewritten.
|
|
15
|
+
|
|
16
|
+
## Features
|
|
17
|
+
|
|
18
|
+
- **Per-rule routing**: `{provider, model, proxyUrl, enabled}` — specificity: exact model > prefix `muse-*` > `*`.
|
|
19
|
+
- **Purpose filter**: optional per-rule `purpose` (e.g. `compaction`) so chat goes through the proxy while background calls stay direct.
|
|
20
|
+
- **credentialRef**: keep proxy passwords in the DSH credentials service instead of settings.yaml; rules reference them by name (`user:password` entries). Soft dependency — installs without it keep working.
|
|
21
|
+
- **Auto probe**: newly configured proxies are connectivity-tested once (CONNECT/socks handshake, no model quota); results go to the host log.
|
|
22
|
+
- **Protocols**: `http://`, `https://` (CONNECT via `undici.ProxyAgent`), `socks5://` / `socks5h://` (via optional `socks`, tunnelled by undici `Agent` + custom connect).
|
|
23
|
+
- **Zero baseURL mutation** — keep the real upstream.
|
|
24
|
+
- **Live**: change rules → next `llm/stream` uses them; in-flight streams unaffected.
|
|
25
|
+
- **UI**: `Settings → Plugins → Model Proxy` card (also works via `~/.dsh/settings.yaml`).
|
|
26
|
+
- **Provider picker**: dropdown groups user-configured providers first (derived from `llm.providers` × settings mirror, same semantics as the built-in Models page); bare directory routes follow, and "Custom…" accepts anything — hand-written yaml rules, wildcards, gateways the catalog doesn't know. Provider and model fields are dropdowns fed by the live host catalog (`llm.providers` / `llm.models`, refreshed on `llm/adapters-updated`); a "Custom…" entry keeps free text for wildcards (`muse-*`, `*`) or not-yet-installed providers.
|
|
27
|
+
- **Batch & grouped management**: adding rules checks multiple models for one provider at once — one rule each, sharing proxy/purpose/credential; the list groups cards by provider with group-level apply-proxy, enable/disable-all, and delete (cross-provider grouping never affects match order).
|
|
28
|
+
|
|
29
|
+
## Install
|
|
30
|
+
|
|
31
|
+
### Recommended: profile-managed (bundle)
|
|
32
|
+
|
|
33
|
+
The package declares a `dsh.bundle` layer, so the DSH CLI links the dependency
|
|
34
|
+
**and** appends the activation row in one step:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
dsh plugin --profile <name> add dsh-plugin-model-proxy
|
|
38
|
+
# optional SOCKS support:
|
|
39
|
+
dsh plugin --profile <name> add socks
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Verify the composed layer without booting, then run:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
dsh --profile <name> --dump-config # shows a "# == dsh-plugin-model-proxy" layer
|
|
46
|
+
dsh --profile <name>
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Uninstall removes both the dependency and the layer:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
dsh plugin --profile <name> remove dsh-plugin-model-proxy
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Installing from GitHub (`dsh plugin --profile <name> add github:<user>/dsh-plugin-model-proxy#<sha>`)
|
|
56
|
+
fetches sources; pnpm ≥10 asks you to allowlist the `prepare` build — copy the
|
|
57
|
+
package key it prints into the profile's `pnpm-workspace.yaml` under
|
|
58
|
+
`allowBuilds:`, then re-run the `add`. Pin a commit so later pushes cannot
|
|
59
|
+
change what runs on your machine.
|
|
60
|
+
|
|
61
|
+
### Manual: hand-written patch
|
|
62
|
+
|
|
63
|
+
If you manage compositions by hand, install the dependency into the **profile
|
|
64
|
+
directory** first (`dsh plugin --profile <name> add ./` from a checkout works;
|
|
65
|
+
module resolution anchors at the profile). Then insert exactly ONE loader row:
|
|
66
|
+
|
|
67
|
+
```yaml
|
|
68
|
+
# ~/.dsh/cordis.patch.yml (or a --patch overlay)
|
|
69
|
+
- insert:
|
|
70
|
+
- id: model-proxy/host
|
|
71
|
+
name: dsh-plugin-model-proxy
|
|
72
|
+
config: {}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Patch-file rules that trip people up:
|
|
76
|
+
|
|
77
|
+
- The file must parse as a **top-level YAML array** of patch entries. Comments
|
|
78
|
+
are fine; a file of only comments (no `- …` rows and no `[]`) fails to parse
|
|
79
|
+
and breaks every boot/dump that reads it.
|
|
80
|
+
- The loader-entry specifier field is **`name:`** (the package name), not `module:`.
|
|
81
|
+
- New rows must be nested under **`insert:`** — a bare `- id:` row means "patch an existing entry".
|
|
82
|
+
- Only the **host** half is a loader entry. The browser half is discovered automatically
|
|
83
|
+
from the package's `dsh.client` declaration and served at
|
|
84
|
+
`/plugins/dsh-plugin-model-proxy/client.js`. Do NOT add a `model-proxy/client`
|
|
85
|
+
row — it would run browser code inside the Node process.
|
|
86
|
+
- **Never mix this path with the profile-managed install above.** Once the
|
|
87
|
+
dependency declares `dsh.bundle.patch`, `dsh plugin add` injects the host row
|
|
88
|
+
automatically; keeping a hand-written copy in `~/.dsh/cordis.patch.yml`
|
|
89
|
+
inserts the same loader id twice and the composition collides at boot.
|
|
90
|
+
|
|
91
|
+
Uninstall = remove the inserted rows + `pnpm remove dsh-plugin-model-proxy`
|
|
92
|
+
from the profile.
|
|
93
|
+
|
|
94
|
+
## Configure
|
|
95
|
+
|
|
96
|
+
### Via UI
|
|
97
|
+
|
|
98
|
+
`Settings → Plugins → Model Proxy`
|
|
99
|
+
|
|
100
|
+
### Via file
|
|
101
|
+
|
|
102
|
+
`~/.dsh/settings.yaml`:
|
|
103
|
+
|
|
104
|
+
```yaml
|
|
105
|
+
model-proxy:
|
|
106
|
+
enabled: true
|
|
107
|
+
debug: false
|
|
108
|
+
defaultProxy: "" # fallback when no rule matches
|
|
109
|
+
rules:
|
|
110
|
+
- provider: opencode
|
|
111
|
+
model: muse-spark-1.2-contributor
|
|
112
|
+
proxyUrl: socks5://127.0.0.1:1080
|
|
113
|
+
enabled: true
|
|
114
|
+
- provider: opencode
|
|
115
|
+
model: "*"
|
|
116
|
+
proxyUrl: "" # direct for the rest of this provider
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
`proxyUrl: ""` means **direct (exempt)**. `socks5h://` resolves DNS at the proxy.
|
|
120
|
+
|
|
121
|
+
## How it works (non-invasive)
|
|
122
|
+
|
|
123
|
+
1. Host registers `model-proxy` settings namespace (`installSettingsSection`, live).
|
|
124
|
+
2. Wraps `globalThis.fetch` reversibly.
|
|
125
|
+
3. Listens on `llm/stream` waterfall, resolves `proxyUrl` for `(provider, model)` via `AsyncLocalStorage`, then injects a `dispatcher` into the adapter's `fetch` — for proxied requests it routes through `undici.fetch` (Node's native global fetch ignores custom dispatchers), with `undici.ProxyAgent` for `http(s)` and an undici `Agent` + socks `connect` (with TLS) for `socks5/h`.
|
|
126
|
+
4. Browser registers `settings.plugin.item` with key `model-proxy` — automatically paired by the Plugins tab (`served ∩ registered`).
|
|
127
|
+
|
|
128
|
+
No Adapter fork, no `baseURL` rewrite. See `DESIGN.md` for full design and invasiveness analysis.
|
|
129
|
+
|
|
130
|
+
## Invasiveness
|
|
131
|
+
|
|
132
|
+
| Check | Result |
|
|
133
|
+
|---|---|
|
|
134
|
+
| Modifies `packages/*` | No |
|
|
135
|
+
| Requires fork of `dsh-llm` | No |
|
|
136
|
+
| Global side effect reversible | Yes (`ctx.effect` dispose restores `fetch`) |
|
|
137
|
+
| Client bundle purity gate | Passes (only type-only slot import) |
|
|
138
|
+
|
|
139
|
+
## Building
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
pnpm install
|
|
143
|
+
pnpm run build
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Testing
|
|
147
|
+
|
|
148
|
+
Fully offline (local origin + CONNECT-capable toy proxy; no real network or proxy needed):
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
pnpm test # builds host + client, then runs node --test tests/
|
|
152
|
+
pnpm run typecheck
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## License
|
|
156
|
+
|
|
157
|
+
MIT
|
package/cordis.patch.yml
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# dsh-plugin-model-proxy — bundle layer
|
|
2
|
+
#
|
|
3
|
+
# Declared by package.json#dsh.bundle.patch and applied automatically by
|
|
4
|
+
# `dsh plugin --profile <name> add dsh-plugin-model-proxy`. Manual installs can
|
|
5
|
+
# copy these rows into ~/.dsh/cordis.patch.yml or a --patch overlay.
|
|
6
|
+
#
|
|
7
|
+
# Only the HOST row is a loader entry (the specifier field is `name:`). The
|
|
8
|
+
# browser half is discovered automatically from package.json#dsh.client and
|
|
9
|
+
# served at /plugins/dsh-plugin-model-proxy/client.js — never add a second
|
|
10
|
+
# `model-proxy/client` loader row, it would run browser code in the host.
|
|
11
|
+
|
|
12
|
+
- insert:
|
|
13
|
+
- id: model-proxy/host
|
|
14
|
+
name: dsh-plugin-model-proxy
|
|
15
|
+
config: {}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ProviderCatalogStore } from './catalog.js';
|
|
2
|
+
import type { ModelProxyController } from './controller.js';
|
|
3
|
+
import { en } from './locales.js';
|
|
4
|
+
type Props = {
|
|
5
|
+
controller: ModelProxyController;
|
|
6
|
+
/** Live provider/model catalog; absent or empty falls back to free text. */
|
|
7
|
+
catalog?: ProviderCatalogStore;
|
|
8
|
+
t?: (k: keyof typeof en) => string;
|
|
9
|
+
};
|
|
10
|
+
/** Mirrors host assertServiceable for defaultProxy so bad values never reach the wire. */
|
|
11
|
+
export declare function validateDefaultProxy(defaultProxy: string): string | undefined;
|
|
12
|
+
export declare function ModelProxyCard({ controller, catalog, t: tProp }: Props): import("react").JSX.Element;
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=ModelProxyCard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ModelProxyCard.d.ts","sourceRoot":"","sources":["../../src/client/ModelProxyCard.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAA;AACnD,OAAO,KAAK,EAAE,oBAAoB,EAA+B,MAAM,iBAAiB,CAAA;AAExF,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAA;AAEjC,KAAK,KAAK,GAAG;IACX,UAAU,EAAE,oBAAoB,CAAA;IAChC,4EAA4E;IAC5E,OAAO,CAAC,EAAE,oBAAoB,CAAA;IAC9B,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,OAAO,EAAE,KAAK,MAAM,CAAA;CACnC,CAAA;AAoKD,0FAA0F;AAC1F,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAG7E;AAqFD,wBAAgB,cAAc,CAAC,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,KAAK,+BAmetE"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider/model catalog feeding the settings card dropdowns.
|
|
3
|
+
*
|
|
4
|
+
* Data sources mirror the built-in Models page and the model-selection
|
|
5
|
+
* surface:
|
|
6
|
+
* - `llm.providers` — configurable provider directory merged with live routes
|
|
7
|
+
* (`{ providers: [{ provider, displayName, settingsNs, settingsPath,
|
|
8
|
+
* active, declared? }] }`)
|
|
9
|
+
* - `llm.models` — advisory per-provider model catalog
|
|
10
|
+
* (`{ groups: [{ id, name, models: [{ id, name?, … }] }], failures }`)
|
|
11
|
+
* - `settings.describe` — optional enrichment: cross-references each row's
|
|
12
|
+
* settings address to derive `configured`, so the card can group
|
|
13
|
+
* user-configured providers ahead of the bare directory (same semantics as
|
|
14
|
+
* the built-in Models page).
|
|
15
|
+
*
|
|
16
|
+
* Refresh triggers mirror ui-model-selection's convergence sources:
|
|
17
|
+
* `llm/adapters-updated` (registry topology commits) and
|
|
18
|
+
* `settings/document-updated` (configuration-owned catalogs).
|
|
19
|
+
*
|
|
20
|
+
* Everything here is advisory. The card always keeps a free-text escape
|
|
21
|
+
* hatch, because proxy rules legitimately target things no catalog lists:
|
|
22
|
+
* wildcard patterns (`vendor-*`, `*`) and providers whose adapter is not
|
|
23
|
+
* installed (yet).
|
|
24
|
+
*/
|
|
25
|
+
/** One selectable provider row (shape of `llm.providers.providers`). */
|
|
26
|
+
export type CatalogProvider = {
|
|
27
|
+
provider: string;
|
|
28
|
+
displayName: string;
|
|
29
|
+
active: boolean;
|
|
30
|
+
/** Settings namespace whose section configures this provider (absent = no settings address). */
|
|
31
|
+
settingsNs?: string;
|
|
32
|
+
/** Path from that section's root to this provider's profile object. */
|
|
33
|
+
settingsPath?: string[];
|
|
34
|
+
/** Adapter knows this route only because configuration declared it. */
|
|
35
|
+
declared?: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Mirrors ui-settings-models' derivation: the provider's settings namespace
|
|
38
|
+
* exists AND its profile object is present in the merged value. Undefined
|
|
39
|
+
* when unknown (no settings address, or settings.describe unavailable).
|
|
40
|
+
*/
|
|
41
|
+
configured?: boolean;
|
|
42
|
+
};
|
|
43
|
+
/** One selectable model row (subset of an `llm.models` group entry). */
|
|
44
|
+
export type CatalogModel = {
|
|
45
|
+
id: string;
|
|
46
|
+
name?: string;
|
|
47
|
+
};
|
|
48
|
+
export type CatalogSnapshot = {
|
|
49
|
+
status: 'idle' | 'loading' | 'ready' | 'unavailable';
|
|
50
|
+
providers: CatalogProvider[];
|
|
51
|
+
/** Provider id → catalog models; absent/empty means no known models. */
|
|
52
|
+
modelsByProvider: Record<string, CatalogModel[]>;
|
|
53
|
+
};
|
|
54
|
+
/** Structural wire face so tests can pass fakes without a transport. */
|
|
55
|
+
export type CatalogApiFace = {
|
|
56
|
+
llm: {
|
|
57
|
+
providers(payload: object): Promise<unknown>;
|
|
58
|
+
models(payload: object): Promise<unknown>;
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* Optional settings mirror used to derive each provider's `configured`
|
|
62
|
+
* flag. Absent or failing keeps configured undefined — grouping degrades
|
|
63
|
+
* to the flat directory list.
|
|
64
|
+
*/
|
|
65
|
+
settings?: {
|
|
66
|
+
describe(payload: object): Promise<unknown>;
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
/** Structural face of `ctx.remote` — `$on` returns its own disposer. */
|
|
70
|
+
export type CatalogRemoteFace = {
|
|
71
|
+
$on(event: string, listener: (...args: never[]) => void): () => void;
|
|
72
|
+
};
|
|
73
|
+
type Listener = () => void;
|
|
74
|
+
/**
|
|
75
|
+
* Unwrap one RPC envelope (`{ result: { ok, value | error } }`), throwing on
|
|
76
|
+
* a business rejection with its wire message.
|
|
77
|
+
*/
|
|
78
|
+
export declare function unwrapRpc(response: unknown): unknown;
|
|
79
|
+
/**
|
|
80
|
+
* Extract selectable provider rows from an unwrapped `llm.providers` value.
|
|
81
|
+
* Malformed rows are skipped, never fatal — the dropdown degrades to whatever
|
|
82
|
+
* is parseable.
|
|
83
|
+
*/
|
|
84
|
+
export declare function pickProviders(value: unknown): CatalogProvider[];
|
|
85
|
+
/** Deep-get along a path; undefined as soon as any hop is missing. */
|
|
86
|
+
export declare function getPath(value: unknown, path: readonly string[]): unknown;
|
|
87
|
+
/**
|
|
88
|
+
* Attach `configured` to provider rows, mirroring ui-settings-models'
|
|
89
|
+
* derivation: the settings namespace exists in the mirror AND either the
|
|
90
|
+
* provider configures via the whole section (`settingsPath` empty) or its
|
|
91
|
+
* profile object is present in the merged value. Rows without a settings
|
|
92
|
+
* address keep `configured` undefined (unknown, not false).
|
|
93
|
+
*/
|
|
94
|
+
export declare function attachConfigured(providers: CatalogProvider[], namespaces: ReadonlyArray<{
|
|
95
|
+
ns?: unknown;
|
|
96
|
+
value?: unknown;
|
|
97
|
+
}>): CatalogProvider[];
|
|
98
|
+
/**
|
|
99
|
+
* Group an unwrapped `llm.models` value into provider id → model rows.
|
|
100
|
+
* Failures entries are ignored (the dropdown simply offers nothing for a
|
|
101
|
+
* provider whose catalog failed host-side).
|
|
102
|
+
*/
|
|
103
|
+
export declare function pickModelsByProvider(value: unknown): Record<string, CatalogModel[]>;
|
|
104
|
+
/**
|
|
105
|
+
* uSES-compatible store over the two catalog RPCs. Loads once on bind(),
|
|
106
|
+
* reloads on forwarded topology/settings events, and keeps the last good
|
|
107
|
+
* rows across a failed background refresh so an outage never blanks open
|
|
108
|
+
* dropdowns.
|
|
109
|
+
*/
|
|
110
|
+
export declare class ProviderCatalogStore {
|
|
111
|
+
private readonly api;
|
|
112
|
+
private readonly remote?;
|
|
113
|
+
private readonly listeners;
|
|
114
|
+
private snapshot;
|
|
115
|
+
private generation;
|
|
116
|
+
private unsubs;
|
|
117
|
+
private bound;
|
|
118
|
+
constructor(api: CatalogApiFace, remote?: CatalogRemoteFace | undefined);
|
|
119
|
+
/** Idempotent: start loading and subscribe to refresh events. */
|
|
120
|
+
bind(): void;
|
|
121
|
+
/** Stop listening; in-flight loads become no-ops via the generation guard. */
|
|
122
|
+
dispose(): void;
|
|
123
|
+
subscribe(listener: Listener): () => void;
|
|
124
|
+
getSnapshot(): CatalogSnapshot;
|
|
125
|
+
/**
|
|
126
|
+
* Fetch both catalogs. Each call settles independently (`allSettled`
|
|
127
|
+
* semantics via mapped thunks): a provider-catalog failure fails the whole
|
|
128
|
+
* load, while a model-catalog failure degrades to an empty model map —
|
|
129
|
+
* models are an enrichment, providers drive the primary dropdown.
|
|
130
|
+
*/
|
|
131
|
+
load(): Promise<void>;
|
|
132
|
+
/**
|
|
133
|
+
* Keep last good rows across a failed refresh; the card falls back to
|
|
134
|
+
* free-text inputs only when the snapshot holds no providers at all.
|
|
135
|
+
*/
|
|
136
|
+
private markUnavailable;
|
|
137
|
+
private set;
|
|
138
|
+
}
|
|
139
|
+
export {};
|
|
140
|
+
//# sourceMappingURL=catalog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../src/client/catalog.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client controller for model-proxy settings card.
|
|
3
|
+
* Binds to `model-proxy` namespace via ctx.settingsScope and exposes
|
|
4
|
+
* a small observable store for the card.
|
|
5
|
+
*/
|
|
6
|
+
import type { SettingsScope } from '@deepseek-ai/dsh-client-runtime/client';
|
|
7
|
+
export type ProxyRule = {
|
|
8
|
+
/** Card key; may be absent on hand-written yaml rules until edited here. */
|
|
9
|
+
id?: string;
|
|
10
|
+
provider: string;
|
|
11
|
+
model: string;
|
|
12
|
+
proxyUrl: string;
|
|
13
|
+
enabled: boolean;
|
|
14
|
+
/** Only apply to calls with this GenerateOptions.purpose; empty = all. */
|
|
15
|
+
purpose?: string;
|
|
16
|
+
/** Credentials-service entry ("user:password") overriding proxyUrl userinfo. */
|
|
17
|
+
credentialRef?: string;
|
|
18
|
+
};
|
|
19
|
+
export type ModelProxyConfig = {
|
|
20
|
+
enabled: boolean;
|
|
21
|
+
rules: ProxyRule[];
|
|
22
|
+
defaultProxy: string;
|
|
23
|
+
debug: boolean;
|
|
24
|
+
};
|
|
25
|
+
export type ModelProxySnapshot = {
|
|
26
|
+
status: 'loading' | 'ready' | 'unavailable';
|
|
27
|
+
value?: ModelProxyConfig;
|
|
28
|
+
revision?: number;
|
|
29
|
+
writable: boolean;
|
|
30
|
+
error?: string;
|
|
31
|
+
};
|
|
32
|
+
type Listener = () => void;
|
|
33
|
+
/**
|
|
34
|
+
* Strip unknown keys from drafted rules before persisting. The wire layer
|
|
35
|
+
* tolerates extra keys and passes them through materialization, so without
|
|
36
|
+
* this a legacy field (e.g. the removed `note`) read from the stored document
|
|
37
|
+
* would ride every save forever. Writing only known fields converges stored
|
|
38
|
+
* documents to the schema shape.
|
|
39
|
+
*
|
|
40
|
+
* Dropping is loud, not silent: every stripped key is named on the console,
|
|
41
|
+
* so a hand-written key vanishing on save is never a mystery.
|
|
42
|
+
*/
|
|
43
|
+
export declare function sanitizeRules(rules: ProxyRule[]): ProxyRule[];
|
|
44
|
+
/** Stable-enough client-side id for rule cards (React keys / list diffs). */
|
|
45
|
+
export declare function makeRuleId(): string;
|
|
46
|
+
/** One "batch add" spec: shared fields + the model patterns to fan out over. */
|
|
47
|
+
export type CreatorSpec = {
|
|
48
|
+
provider: string;
|
|
49
|
+
/** Model ids / wildcard patterns; one rule each. Duplicates collapse. */
|
|
50
|
+
models: string[];
|
|
51
|
+
proxyUrl: string;
|
|
52
|
+
purpose?: string;
|
|
53
|
+
credentialRef?: string;
|
|
54
|
+
enabled?: boolean;
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Fan one creator spec out into N prefilled rules sharing provider and
|
|
58
|
+
* connection fields. Returns [] when provider or models are effectively
|
|
59
|
+
* empty — callers gate the button on the same predicate for inline counts.
|
|
60
|
+
*/
|
|
61
|
+
export declare function buildCreatorRules(spec: CreatorSpec): ProxyRule[];
|
|
62
|
+
/**
|
|
63
|
+
* Group rules by provider for the card's grouped view: group order is first
|
|
64
|
+
* appearance, intra-group order preserved. Matching semantics only care about
|
|
65
|
+
* order WITHIN a provider (same-pass first-wins), so regrouping across
|
|
66
|
+
* providers is display-safe by construction.
|
|
67
|
+
*/
|
|
68
|
+
export declare function groupByProvider(rules: ProxyRule[]): Array<{
|
|
69
|
+
provider: string;
|
|
70
|
+
rules: ProxyRule[];
|
|
71
|
+
}>;
|
|
72
|
+
/**
|
|
73
|
+
* Fill missing rule ids so every card has a stable React key. Host-side code
|
|
74
|
+
* never relies on `id` (the schema leaves it optional), so this is purely a
|
|
75
|
+
* UI concern and does not dirty the saved document.
|
|
76
|
+
*/
|
|
77
|
+
export declare function ensureRuleIds(cfg: ModelProxyConfig): ModelProxyConfig;
|
|
78
|
+
export declare class ModelProxyController {
|
|
79
|
+
private readonly scope;
|
|
80
|
+
private listeners;
|
|
81
|
+
private snapshot;
|
|
82
|
+
private unsub?;
|
|
83
|
+
constructor(scope: SettingsScope<ModelProxyConfig>);
|
|
84
|
+
bind(): void;
|
|
85
|
+
dispose(): void;
|
|
86
|
+
subscribe(l: Listener): () => void;
|
|
87
|
+
getSnapshot(): ModelProxySnapshot;
|
|
88
|
+
private pull;
|
|
89
|
+
private emit;
|
|
90
|
+
/**
|
|
91
|
+
* Persist the config as four fenced field writes.
|
|
92
|
+
*
|
|
93
|
+
* The scope contract exposes per-field writes only, so full atomicity would
|
|
94
|
+
* require collapsing the namespace to a single field (a breaking settings
|
|
95
|
+
* shape change). Until then we order the writes so the field most likely to
|
|
96
|
+
* be REJECTED by host validation (`rules`) goes FIRST: if it fails, nothing
|
|
97
|
+
* else has been committed and the failure aborts cleanly instead of leaving
|
|
98
|
+
* mixed old/new state. The remaining fields are booleans plus a URL that the
|
|
99
|
+
* card pre-validates with the same checks the host applies, making their
|
|
100
|
+
* rejection practically unreachable.
|
|
101
|
+
*/
|
|
102
|
+
save(next: ModelProxyConfig): Promise<void>;
|
|
103
|
+
setEnabled(v: boolean): Promise<void>;
|
|
104
|
+
setDebug(v: boolean): Promise<void>;
|
|
105
|
+
}
|
|
106
|
+
export {};
|
|
107
|
+
//# sourceMappingURL=controller.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../src/client/controller.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAA;AAE3E,MAAM,MAAM,SAAS,GAAG;IACtB,4EAA4E;IAC5E,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,OAAO,CAAA;IAChB,0EAA0E;IAC1E,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,gFAAgF;IAChF,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,SAAS,EAAE,CAAA;IAClB,YAAY,EAAE,MAAM,CAAA;IACpB,KAAK,EAAE,OAAO,CAAA;CACf,CAAA;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,MAAM,EAAE,SAAS,GAAG,OAAO,GAAG,aAAa,CAAA;IAC3C,KAAK,CAAC,EAAE,gBAAgB,CAAA;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,OAAO,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AAED,KAAK,QAAQ,GAAG,MAAM,IAAI,CAAA;AAK1B;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,SAAS,EAAE,CAa7D;AAED,6EAA6E;AAC7E,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED,gFAAgF;AAChF,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,EAAE,MAAM,CAAA;IAChB,yEAAyE;IACzE,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB,CAAA;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,WAAW,GAAG,SAAS,EAAE,CAgBhE;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,KAAK,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,SAAS,EAAE,CAAA;CAAE,CAAC,CAanG;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,gBAAgB,GAAG,gBAAgB,CAErE;AAED,qBAAa,oBAAoB;IAKnB,OAAO,CAAC,QAAQ,CAAC,KAAK;IAJlC,OAAO,CAAC,SAAS,CAAsB;IACvC,OAAO,CAAC,QAAQ,CAA6D;IAC7E,OAAO,CAAC,KAAK,CAAC,CAAY;gBAEG,KAAK,EAAE,aAAa,CAAC,gBAAgB,CAAC;IAEnE,IAAI,IAAI,IAAI;IAKZ,OAAO,IAAI,IAAI;IAKf,SAAS,CAAC,CAAC,EAAE,QAAQ,GAAG,MAAM,IAAI;IAKlC,WAAW,IAAI,kBAAkB;IAIjC,OAAO,CAAC,IAAI;IAiBZ,OAAO,CAAC,IAAI;IAIZ;;;;;;;;;;;OAWG;IACG,IAAI,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAO3C,UAAU,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAIrC,QAAQ,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;CAG1C"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser half: registers `settings.plugin.item` card for `model-proxy`.
|
|
3
|
+
* Non-invasive: only depends on the declared slot via type-only import.
|
|
4
|
+
*/
|
|
5
|
+
import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';
|
|
6
|
+
export declare const inject: string[];
|
|
7
|
+
export declare function apply(ctx: ClientContext): void;
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAA;AAO3E,eAAO,MAAM,MAAM,UAA+D,CAAA;AAElF,wBAAgB,KAAK,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CA8C9C"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
export declare const en: {
|
|
2
|
+
readonly title: "Model Proxy";
|
|
3
|
+
readonly desc: "Route specific provider/model pairs through HTTP/HTTPS/SOCKS5 proxies. Specificity: exact model > prefix \"vendor-*\" > \"*\". Optional purpose filter targets compaction/session-title calls.";
|
|
4
|
+
readonly enabled: "Enable proxy routing";
|
|
5
|
+
readonly debug: "Debug logging (host log)";
|
|
6
|
+
readonly rules: "Rules (first match wins — exact before prefix before \"*\")";
|
|
7
|
+
readonly addRule: "Add rule";
|
|
8
|
+
readonly provider: "Provider";
|
|
9
|
+
readonly providerPlaceholder: "e.g. openai";
|
|
10
|
+
readonly model: "Model";
|
|
11
|
+
readonly modelPlaceholder: "e.g. gpt-4o-mini, vendor-* or *";
|
|
12
|
+
readonly purpose: "Purpose filter";
|
|
13
|
+
readonly purposePlaceholder: "empty = all purposes (e.g. compaction, session-title)";
|
|
14
|
+
readonly credRef: "Credential ref";
|
|
15
|
+
readonly credRefPlaceholder: "credentials entry holding user:password (optional)";
|
|
16
|
+
readonly proxyUrl: "Proxy URL";
|
|
17
|
+
readonly proxyPlaceholder: "socks5://127.0.0.1:1080 or http://127.0.0.1:7890 (empty=direct)";
|
|
18
|
+
readonly enabledShort: "On";
|
|
19
|
+
readonly delete: "Delete";
|
|
20
|
+
readonly defaultProxy: "Fallback proxy (when no rule matches)";
|
|
21
|
+
readonly defaultPlaceholder: "optional, e.g. http://127.0.0.1:7890";
|
|
22
|
+
readonly saving: "Saving…";
|
|
23
|
+
readonly save: "Save";
|
|
24
|
+
readonly saved: "Saved";
|
|
25
|
+
readonly unavailable: "Model proxy settings unavailable.";
|
|
26
|
+
readonly empty: "No rules yet — add one above. Tip: use model \"*\" for all models of a provider.";
|
|
27
|
+
readonly invalid: "Please fix highlighted fields.";
|
|
28
|
+
readonly duplicate: "Duplicate provider+model";
|
|
29
|
+
readonly reading: "Loading…";
|
|
30
|
+
readonly readOnly: "Read-only (settings provider not writable).";
|
|
31
|
+
readonly choose: "Select…";
|
|
32
|
+
readonly customOption: "Custom…";
|
|
33
|
+
readonly backToList: "Pick from the installed catalog";
|
|
34
|
+
readonly dormant: "not configured";
|
|
35
|
+
readonly groupConfigured: "Configured providers";
|
|
36
|
+
readonly groupDirectory: "Other directory routes";
|
|
37
|
+
readonly wildcardAll: "any model";
|
|
38
|
+
readonly catalogUnavailable: "Provider catalog unavailable — type values manually.";
|
|
39
|
+
readonly creatorTitle: "New rules";
|
|
40
|
+
readonly creatorModels: "Models";
|
|
41
|
+
readonly creatorPatternHint: "Or a pattern (vendor-* or *)";
|
|
42
|
+
readonly createN: "Create {n} rule(s)";
|
|
43
|
+
readonly cancel: "Cancel";
|
|
44
|
+
readonly alreadyRuled: "rule exists";
|
|
45
|
+
readonly noneCatalogued: "No catalog models — use * or a custom pattern.";
|
|
46
|
+
readonly groupApplyProxy: "proxy for all…";
|
|
47
|
+
readonly groupApply: "Apply";
|
|
48
|
+
readonly groupEnableAll: "Enable all";
|
|
49
|
+
readonly groupDisableAll: "Disable all";
|
|
50
|
+
readonly groupDelete: "Delete group";
|
|
51
|
+
readonly groupConfirmDelete: "Sure?";
|
|
52
|
+
};
|
|
53
|
+
export declare const zh: {
|
|
54
|
+
readonly title: "模型代理";
|
|
55
|
+
readonly desc: "按 provider/model 粒度走代理(HTTP/HTTPS/SOCKS5)。优先级:精确 model > 前缀 \"vendor-*\" > \"*\"。可选用途过滤可单独控制 compaction/session-title 等调用。";
|
|
56
|
+
readonly enabled: "启用代理路由";
|
|
57
|
+
readonly debug: "调试日志(Host 日志)";
|
|
58
|
+
readonly rules: "规则(首条命中即用 — 精确 > 前缀 > \"*\")";
|
|
59
|
+
readonly addRule: "添加规则";
|
|
60
|
+
readonly provider: "Provider";
|
|
61
|
+
readonly providerPlaceholder: "例如 openai";
|
|
62
|
+
readonly model: "Model";
|
|
63
|
+
readonly modelPlaceholder: "例如 gpt-4o-mini、vendor-* 或 *";
|
|
64
|
+
readonly purpose: "用途过滤";
|
|
65
|
+
readonly purposePlaceholder: "留空=所有用途(如 compaction、session-title)";
|
|
66
|
+
readonly credRef: "凭据引用";
|
|
67
|
+
readonly credRefPlaceholder: "credentials 服务条目(user:password),可选";
|
|
68
|
+
readonly proxyUrl: "代理地址";
|
|
69
|
+
readonly proxyPlaceholder: "socks5://127.0.0.1:1080 或 http://127.0.0.1:7890(空=直连)";
|
|
70
|
+
readonly enabledShort: "启用";
|
|
71
|
+
readonly delete: "删除";
|
|
72
|
+
readonly defaultProxy: "兜底代理(无规则命中时)";
|
|
73
|
+
readonly defaultPlaceholder: "可选,例如 http://127.0.0.1:7890";
|
|
74
|
+
readonly saving: "保存中…";
|
|
75
|
+
readonly save: "保存";
|
|
76
|
+
readonly saved: "已保存";
|
|
77
|
+
readonly unavailable: "模型代理设置不可用。";
|
|
78
|
+
readonly empty: "暂无规则 — 点击上方添加。提示:model 用 \"*\" 表示该 provider 的所有模型。";
|
|
79
|
+
readonly invalid: "请修正标红字段。";
|
|
80
|
+
readonly duplicate: "provider+model 重复";
|
|
81
|
+
readonly reading: "加载中…";
|
|
82
|
+
readonly readOnly: "只读(settings provider 不可写)。";
|
|
83
|
+
readonly choose: "请选择…";
|
|
84
|
+
readonly customOption: "自定义…";
|
|
85
|
+
readonly backToList: "从已安装目录选择";
|
|
86
|
+
readonly dormant: "未配置";
|
|
87
|
+
readonly groupConfigured: "已配置的 Provider";
|
|
88
|
+
readonly groupDirectory: "目录中的其他路由";
|
|
89
|
+
readonly wildcardAll: "所有模型";
|
|
90
|
+
readonly catalogUnavailable: "提供方目录不可用 — 请手动输入。";
|
|
91
|
+
readonly creatorTitle: "新建规则";
|
|
92
|
+
readonly creatorModels: "勾选模型";
|
|
93
|
+
readonly creatorPatternHint: "或自定义模式(vendor-*、*)";
|
|
94
|
+
readonly createN: "创建 {n} 条规则";
|
|
95
|
+
readonly cancel: "取消";
|
|
96
|
+
readonly alreadyRuled: "已有规则";
|
|
97
|
+
readonly noneCatalogued: "该 provider 无目录模型——可用 * 或自定义模式。";
|
|
98
|
+
readonly groupApplyProxy: "整组代理地址…";
|
|
99
|
+
readonly groupApply: "应用";
|
|
100
|
+
readonly groupEnableAll: "全部启用";
|
|
101
|
+
readonly groupDisableAll: "全部停用";
|
|
102
|
+
readonly groupDelete: "删除本组";
|
|
103
|
+
readonly groupConfirmDelete: "确认?";
|
|
104
|
+
};
|
|
105
|
+
export type LocaleKey = keyof typeof en;
|
|
106
|
+
//# sourceMappingURL=locales.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"locales.d.ts","sourceRoot":"","sources":["../../src/client/locales.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmDL,CAAA;AAEV,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmDL,CAAA;AAEV,MAAM,MAAM,SAAS,GAAG,MAAM,OAAO,EAAE,CAAA"}
|