@huaweidevtools/aishell-dsh-llm 0.0.3 → 0.0.5

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/README.md CHANGED
@@ -6,7 +6,7 @@ Besides the live route, the plugin declares `aishell` in the configurable-provid
6
6
 
7
7
  ## The Models-page row
8
8
 
9
- The row itself is read-only: the profile has no fields the host editor knows how to write, and credentials are managed at Settings → AI Shell (by `aishell-credentials`). The browser half therefore does not extend the row with a card — it shadows the row's header at runtime (`src/client/provider-row-shadow.ts`, the same approach `aishell-brand` uses for its digest-protected host residues): a status dot after the row's name (green when AK/SK are stored, warn when they are not, with the readiness copy as its hover title) and the header's Edit button hidden, because there is nothing to edit. A MutationObserver keeps the shadow applied across the page's re-renders; disabling the plugin restores the official row exactly.
9
+ The row itself is read-only: the profile has no fields the host editor knows how to write, and credentials are entered through the form the `aishell-credentials` chips open (the account chip beside the chat input, or the chip on a New Session page). The browser half therefore does not extend the row with a card — it shadows the row's header at runtime (`src/client/provider-row-shadow.ts`, the same approach `aishell-brand` uses for its digest-protected host residues): a status dot after the row's name (green when AK/SK are stored, warn when they are not, with the readiness copy as its hover title) and the header's Edit button hidden, because there is nothing to edit. A MutationObserver keeps the shadow applied across the page's re-renders; the shadow is re-installed on a locale switch so the hover copy follows the active language; disabling the plugin restores the official row exactly.
10
10
 
11
11
  ## How it works
12
12
 
@@ -80,7 +80,7 @@ The three image fields share `dsh-llm-pi-ai`'s defaults: the gateway publishes n
80
80
 
81
81
  ## Storing credentials
82
82
 
83
- **Web UI (recommended):** Install `aishell-credentials` (or the `aishell-base` bundle) — the Settings page gets an "AI Shell" section with AK/SK/SecurityToken input fields. Values are transferred to the credential store.
83
+ **Web UI (recommended):** Install `aishell-credentials` (or the `aishell-base` bundle) — clicking the credentials button beside the chat input (or the one on a New Session page) opens a form with AK/SK/SecurityToken fields. Values are verified against Huawei Cloud IAM and transferred to the credential store; the button flips to the account name when they are stored.
84
84
 
85
85
  **CLI fallback:**
86
86
 
package/lib/client.js CHANGED
@@ -46,13 +46,6 @@ const ROW_DOT_CSS = [
46
46
  " display: none !important;",
47
47
  "}"
48
48
  ].join("\n");
49
- /** Title copy for the dot, by readiness. The warn state keeps the
50
- * actionable half — where to save AK/SK — because that is the one thing a
51
- * fresh user cannot guess; the ready state needs nothing beyond itself. */
52
- const DOT_TITLE = {
53
- ok: "已就绪",
54
- warn: "未就绪 — 凭据未配置(在 设置 → AI Shell 中保存 AK/SK)"
55
- };
56
49
  /** Every Edit button an aishell row renders (there is ordinarily one; a
57
50
  * re-render that leaves a second copy gets both, so none stays visible). */
58
51
  function findEditButtons(row) {
@@ -93,15 +86,15 @@ function isProviderRow(node) {
93
86
  * `target` is the owning document, passed in because the stub DOM the specs
94
87
  * run on keeps no `ownerDocument` link.
95
88
  */
96
- function shadowRow(row, ready, target) {
89
+ function shadowRow(row, ready, titles, target) {
97
90
  const identity = row.querySelector("[class*=\"rowIdentity\"]");
98
91
  if (identity === null) return;
99
92
  const state = ready ? "ok" : "warn";
100
93
  const existing = identity.querySelector(`[${ROW_DOT_MARKER}]`);
101
94
  const dot = existing ?? target.createElement("span");
102
95
  dot.setAttribute(ROW_DOT_MARKER, state);
103
- dot.setAttribute("title", DOT_TITLE[state]);
104
- dot.setAttribute("aria-label", DOT_TITLE[state]);
96
+ dot.setAttribute("title", titles[state]);
97
+ dot.setAttribute("aria-label", titles[state]);
105
98
  if (existing === null) {
106
99
  dot.setAttribute("role", "img");
107
100
  identity.appendChild(dot);
@@ -122,21 +115,23 @@ function unshadowRow(row) {
122
115
  *
123
116
  * `ready` is the credential fact as the browser half derives it from the
124
117
  * settings namespace `aishell-credentials` owns (see `client/index.ts`);
125
- * the install does not read the store itself, so a later credential save is
126
- * a reinstall with the new fact, not a re-derivation buried in here. Sweeps
127
- * the page once, then observes the body so re-rendered rows are covered too.
128
- * Returns the disposer that stops the observer and restores every row.
118
+ * `titles` is the dot's hover copy in the active locale (the installer
119
+ * translates; this module holds only the DOM work). Neither is read from any
120
+ * store here, so a later credential save or locale switch is a reinstall with
121
+ * the new values, not a re-derivation buried in here. Sweeps the page once,
122
+ * then observes the body so re-rendered rows are covered too. Returns the
123
+ * disposer that stops the observer and restores every row.
129
124
  */
130
- function installProviderRowShadow(target, ready) {
125
+ function installProviderRowShadow(target, ready, titles) {
131
126
  if (typeof target.querySelector !== "function" || typeof MutationObserver !== "function") return () => {};
132
127
  /** Run the shadow over every provider row at or below `root`. */
133
128
  const sweep = (root) => {
134
- if (isElement(root) && isProviderRow(root)) shadowRow(root, ready, target);
135
- for (const row of root.querySelectorAll("[class*=\"rowCard\"], [class*=\"setupCard\"]")) if (isProviderRow(row)) shadowRow(row, ready, target);
129
+ if (isElement(root) && isProviderRow(root)) shadowRow(root, ready, titles, target);
130
+ for (const row of root.querySelectorAll("[class*=\"rowCard\"], [class*=\"setupCard\"]")) if (isProviderRow(row)) shadowRow(row, ready, titles, target);
136
131
  };
137
132
  const sweepIfRow = (node) => {
138
133
  if (isProviderRow(node)) {
139
- shadowRow(node, ready, target);
134
+ shadowRow(node, ready, titles, target);
140
135
  return;
141
136
  }
142
137
  for (let parent = node.parentElement; parent !== null; parent = parent.parentElement) sweep(parent);
@@ -160,20 +155,54 @@ function installProviderRowShadow(target, ready) {
160
155
  };
161
156
  }
162
157
 
158
+ //#endregion
159
+ //#region src/client/locales.ts
160
+ /**
161
+ * aishell-llm locale dictionaries — the Models-page provider row's copy.
162
+ *
163
+ * The row shadow is a DOM patch, not a React render, so its strings do not
164
+ * ride the framework's locale seat: the install reads them through `t` at
165
+ * install time and repaints on a locale switch (the client half re-installs
166
+ * on `locale/change`). zh is the key-set source of truth; en mirrors it.
167
+ *
168
+ * @module @huaweidevtools/aishell-dsh-llm/client/locales
169
+ */
170
+ /** Dictionary namespace owned by this plugin. */
171
+ const NS = "aishell-llm";
172
+ /** Simplified Chinese dictionary (the key-set source of truth). */
173
+ const zh = {
174
+ "provider.ready": "已就绪",
175
+ "provider.warn": "未就绪 — 凭据未配置(点击对话输入框上方的凭据按钮填写 AK/SK)"
176
+ };
177
+ /** English dictionary. */
178
+ const en = {
179
+ "provider.ready": "Ready",
180
+ "provider.warn": "Not ready — credentials missing (click the credentials button above the chat input to enter AK/SK)"
181
+ };
182
+
163
183
  //#endregion
164
184
  //#region src/client/index.ts
165
185
  /** The settings namespace aishell-credentials owns (the shadow reads its status). */
166
186
  const AISHELL_CREDENTIALS_NS = "aishell-client-credentials";
167
187
  /** Required services. */
168
- const inject = ["configForms"];
188
+ const inject = ["configForms", "locale"];
169
189
  function apply(ctx) {
170
190
  if (typeof document === "undefined") return;
191
+ ctx.effect(() => ctx.locale.register(NS, {
192
+ zh,
193
+ en
194
+ }), "aishell-llm: dictionaries");
195
+ const t = ctx.locale.bind(NS);
171
196
  const form = ctx.configForms.get(AISHELL_CREDENTIALS_NS);
172
197
  let readiness = form.getSnapshot().value?.credentialsStored === true;
173
198
  let disposeShadow;
199
+ const titles = () => ({
200
+ ok: t("provider.ready"),
201
+ warn: t("provider.warn")
202
+ });
174
203
  const sync = () => {
175
204
  disposeShadow?.();
176
- disposeShadow = installProviderRowShadow(document, readiness);
205
+ disposeShadow = installProviderRowShadow(document, readiness, titles());
177
206
  };
178
207
  const derive = () => {
179
208
  const next = form.getSnapshot().value?.credentialsStored === true;
@@ -190,6 +219,9 @@ function apply(ctx) {
190
219
  };
191
220
  }), "aishell-llm: models page provider row shadow");
192
221
  ctx.effect(() => form.subscribe(derive), "aishell-llm: credential presence for the models row");
222
+ ctx.effect(() => ctx.on("locale/change", () => {
223
+ sync();
224
+ }), "aishell-llm: shadow locale repaint");
193
225
  }
194
226
 
195
227
  //#endregion
@@ -2,11 +2,12 @@
2
2
  * aishell LLM browser half — shadows the Models page's provider row.
3
3
  *
4
4
  * The page's row for the aishell family is read-only: its profile has no
5
- * fields the host editor knows how to write, and its credentials live in
6
- * `aishell-credentials`' own settings section. What the row should tell the
7
- * user is the one fact the old card extension distilled — ready or not — so
8
- * the browser half paints it as a status dot beside the row's name and hides
9
- * the header's Edit button (see `client/provider-row-shadow.ts`).
5
+ * fields the host editor knows how to write, and its credentials are entered
6
+ * through the credential form the `aishell-credentials` chips open. What the
7
+ * row should tell the user is the one fact the old card extension distilled —
8
+ * ready or not — so the browser half paints it as a status dot beside the
9
+ * row's name and hides the header's Edit button (see
10
+ * `client/provider-row-shadow.ts`).
10
11
  *
11
12
  * The readiness fact is read from the `aishell-client-credentials` settings
12
13
  * namespace (`aishell-credentials` owns it; the shadow never names accounts
@@ -15,10 +16,15 @@
15
16
  * installed standalone) shows no trace of the dot either — the fact is
16
17
  * unknown, not false.
17
18
  *
19
+ * The dot's hover copy rides this package's own locale namespace. The shadow
20
+ * is a DOM patch that does not re-render on a locale switch, so the install
21
+ * is redone on `locale/change` — the repaint is attribute writes over rows
22
+ * the sweep re-finds, not a page mutation.
23
+ *
18
24
  * @module @huaweidevtools/aishell-dsh-llm/client
19
25
  */
20
26
  import type { Context as ClientContext } from '@deepseek-ai/cordis';
21
- export type { ProviderRowShadowDisposer, } from './provider-row-shadow.ts';
27
+ export type { ProviderRowShadowDisposer, ProviderRowTitles, } from './provider-row-shadow.ts';
22
28
  export { installProviderRowShadow, ROW_DOT_MARKER, ROW_EDIT_HIDDEN, } from './provider-row-shadow.ts';
23
29
  /** Required services. */
24
30
  export declare const inject: string[];
@@ -0,0 +1,30 @@
1
+ /**
2
+ * aishell-llm locale dictionaries — the Models-page provider row's copy.
3
+ *
4
+ * The row shadow is a DOM patch, not a React render, so its strings do not
5
+ * ride the framework's locale seat: the install reads them through `t` at
6
+ * install time and repaints on a locale switch (the client half re-installs
7
+ * on `locale/change`). zh is the key-set source of truth; en mirrors it.
8
+ *
9
+ * @module @huaweidevtools/aishell-dsh-llm/client/locales
10
+ */
11
+ /** Dictionary namespace owned by this plugin. */
12
+ export declare const NS: "aishell-llm";
13
+ /** Simplified Chinese dictionary (the key-set source of truth). */
14
+ export declare const zh: {
15
+ readonly 'provider.ready': "已就绪";
16
+ readonly 'provider.warn': "未就绪 — 凭据未配置(点击对话输入框上方的凭据按钮填写 AK/SK)";
17
+ };
18
+ /** English dictionary. */
19
+ export declare const en: {
20
+ readonly 'provider.ready': "Ready";
21
+ readonly 'provider.warn': "Not ready — credentials missing (click the credentials button above the chat input to enter AK/SK)";
22
+ };
23
+ /** All keys (derived from the zh dictionary, the source of truth). */
24
+ export type AishellLlmLocaleKey = keyof typeof zh;
25
+ declare module '@deepseek-ai/dsh-client-ui-slots' {
26
+ interface LocaleNamespaceMap {
27
+ 'aishell-llm': AishellLlmLocaleKey;
28
+ }
29
+ }
30
+ //# sourceMappingURL=locales.d.ts.map
@@ -24,8 +24,8 @@
24
24
  *
25
25
  * 1. a status dot after the name — the host credential dot's own 8px
26
26
  * geometry and success/warn colors, green when AK/SK are stored, warn
27
- * when they are not, with the readiness copy as its title (the row
28
- * keeps saying what the old card said, just in one word of hover);
27
+ * when they are not, with the readiness copy (installer-supplied, so it
28
+ * follows the active locale) as its title;
29
29
  * 2. the row's Edit button is hidden — the row is read-only, and the only
30
30
  * control the header keeps is whatever the host itself decides (Remove,
31
31
  * for user-added rows; this family's row is not removable). The hide is
@@ -53,15 +53,28 @@ export declare const ROW_DOT_MARKER = "data-aishell-provider-dot";
53
53
  export declare const ROW_EDIT_HIDDEN = "data-aishell-edit-hidden";
54
54
  /** The dot's own CSS: the host credential dot's geometry and palette. */
55
55
  export declare const ROW_DOT_CSS: string;
56
+ /** Title copy for the dot, by readiness — supplied by the installer so it
57
+ * follows the active locale (this module is a DOM patch with no locale seat
58
+ * of its own). The warn state keeps the actionable half — where to enter
59
+ * AK/SK — because that is the one thing a fresh user cannot guess; the ready
60
+ * state needs nothing beyond itself. */
61
+ export interface ProviderRowTitles {
62
+ /** Hover copy when AK/SK are stored. */
63
+ readonly ok: string;
64
+ /** Hover copy when they are not. */
65
+ readonly warn: string;
66
+ }
56
67
  /**
57
68
  * Install the provider-row shadow on a document.
58
69
  *
59
70
  * `ready` is the credential fact as the browser half derives it from the
60
71
  * settings namespace `aishell-credentials` owns (see `client/index.ts`);
61
- * the install does not read the store itself, so a later credential save is
62
- * a reinstall with the new fact, not a re-derivation buried in here. Sweeps
63
- * the page once, then observes the body so re-rendered rows are covered too.
64
- * Returns the disposer that stops the observer and restores every row.
72
+ * `titles` is the dot's hover copy in the active locale (the installer
73
+ * translates; this module holds only the DOM work). Neither is read from any
74
+ * store here, so a later credential save or locale switch is a reinstall with
75
+ * the new values, not a re-derivation buried in here. Sweeps the page once,
76
+ * then observes the body so re-rendered rows are covered too. Returns the
77
+ * disposer that stops the observer and restores every row.
65
78
  */
66
- export declare function installProviderRowShadow(target: Document, ready: boolean): ProviderRowShadowDisposer;
79
+ export declare function installProviderRowShadow(target: Document, ready: boolean, titles: ProviderRowTitles): ProviderRowShadowDisposer;
67
80
  //# sourceMappingURL=provider-row-shadow.d.ts.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@huaweidevtools/aishell-dsh-llm",
3
3
  "description": "aishell LLM gateway adapter for DSH — OpenAI-compatible, Huawei Cloud AK/SK auth via credential store",
4
- "version": "0.0.3",
4
+ "version": "0.0.5",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -33,29 +33,32 @@
33
33
  "license": "Apache-2.0",
34
34
  "dependencies": {
35
35
  "eventsource-parser": "^3.0.0",
36
- "@huaweidevtools/aishell-dsh-credentials-store": "0.0.3"
36
+ "@huaweidevtools/aishell-dsh-credentials-store": "0.0.5"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "@deepseek-ai/cordis": "^4.0.4",
40
- "@deepseek-ai/dsh-attachment": ">=0.2.0-0 <0.3.0-0",
41
- "@deepseek-ai/dsh-brand": ">=0.2.0-0 <0.3.0-0",
42
- "@deepseek-ai/dsh-fs": ">=0.2.0-0 <0.3.0-0",
43
- "@deepseek-ai/dsh-llm": ">=0.2.0-0 <0.3.0-0"
40
+ "@deepseek-ai/dsh-attachment": "0.2.0-rc.1 || 0.2.1-rc.1 || 0.2.1-rc.2 || 0.2.1",
41
+ "@deepseek-ai/dsh-brand": "0.2.0-rc.1 || 0.2.1-rc.1 || 0.2.1-rc.2 || 0.2.1",
42
+ "@deepseek-ai/dsh-fs": "0.2.0-rc.1 || 0.2.1-rc.1 || 0.2.1-rc.2 || 0.2.1",
43
+ "@deepseek-ai/dsh-llm": "0.2.0-rc.1 || 0.2.1-rc.1 || 0.2.1-rc.2 || 0.2.1"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@deepseek-ai/cordis": "^4.0.4",
47
47
  "@deepseek-ai/cordis-plugin-loader": "^1.0.5",
48
48
  "@deepseek-ai/dsh-attachment": "0.2.0-rc.1",
49
- "@deepseek-ai/dsh-brand": ">=0.2.0-0 <0.3.0-0",
49
+ "@deepseek-ai/dsh-brand": "0.2.0-rc.1 || 0.2.1-rc.1 || 0.2.1-rc.2 || 0.2.1",
50
+ "@deepseek-ai/dsh-client-locale": "0.2.0-rc.1 || 0.2.1-rc.1 || 0.2.1-rc.2 || 0.2.1",
50
51
  "@deepseek-ai/dsh-client-ui-settings": "0.2.0-rc.1",
52
+ "@deepseek-ai/dsh-client-ui-slots": "0.2.0-rc.1 || 0.2.1-rc.1 || 0.2.1-rc.2 || 0.2.1",
51
53
  "@deepseek-ai/dsh-fs": "0.2.0-rc.1",
52
- "@deepseek-ai/dsh-llm": ">=0.2.0-0 <0.3.0-0",
54
+ "@deepseek-ai/dsh-llm": "0.2.0-rc.1 || 0.2.1-rc.1 || 0.2.1-rc.2 || 0.2.1",
53
55
  "@deepseek-ai/schemastery": "3.18.4"
54
56
  },
55
57
  "dsh": {
56
58
  "client": {
57
59
  "inject": [
58
- "@deepseek-ai/dsh-client-ui-settings"
60
+ "@deepseek-ai/dsh-client-ui-settings",
61
+ "@deepseek-ai/dsh-client-locale"
59
62
  ],
60
63
  "platform": "web"
61
64
  },