dsh-think-translate 1.2.1 → 1.2.3
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.de.md +1 -1
- package/README.es.md +1 -1
- package/README.fr.md +1 -1
- package/README.ja.md +1 -1
- package/README.ko.md +1 -1
- package/README.md +1 -1
- package/README.ru.md +1 -1
- package/README.zh-CN.md +1 -1
- package/lib/client.js +88 -70
- package/lib/index.js +40 -1
- package/package.json +1 -1
package/README.de.md
CHANGED
|
@@ -33,7 +33,7 @@ Modelle der DeepSeek-Familie denken oft auf Chinesisch — oder in der Sprache,
|
|
|
33
33
|
- **🎚️ Einstellbarer Übersetzungszeitpunkt** — alles vorübersetzen / alte Ketten lazy laden (Standard) / nur beim Aufklappen
|
|
34
34
|
- **🔗 Dynamische Anbieter-Kette** — die Listenreihenfolge ist die Ausführungsreihenfolge: ziehen zum Sortieren, jede Zeile einzeln ein-/ausschalten. Integriert google gtx / bing / lokales Ollama plus beliebige eigene Endpunkte
|
|
35
35
|
- **🔌 Eigene Anbieter (OpenAI & Anthropic)** — im Panel jeden OpenAI-kompatiblen Endpunkt (`/v1/chat/completions`) oder die **Anthropic Messages API** (Claude) hinzufügen: Typ, Vorlage, Basis-URL, API-Schlüssel, Modell
|
|
36
|
-
- **🪄 DSH-konfigurierte Anbieter übernehmen** — liest schreibgeschützte DSH-Zeilen aus `settings.yaml` (`llm-pi-ai.providers`); eine Schaltfläche liest neu ein und fügt alle der Kette hinzu. Der Schlüssel wird pro Anfrage aus `.credentials.yaml` aufgelöst und nie in der Plugin-Konfiguration gespeichert
|
|
36
|
+
- **🪄 DSH-konfigurierte Anbieter übernehmen** — liest schreibgeschützte DSH-Zeilen aus `settings.yaml` (`llm-pi-ai.providers`); eine Schaltfläche liest neu ein und fügt alle der Kette hinzu. Der Schlüssel wird pro Anfrage aus `.credentials.yaml` aufgelöst und nie in der Plugin-Konfiguration gespeichert. Auch die eigene Standardroute des Harness zählt: zeigt `agent-default-model` auf `deepseek-official`, erscheint die offizielle DeepSeek-API als weitere DSH-Zeile
|
|
37
37
|
- **⏱️ Robust** — 3 Wiederholungen mit Backoff + direkter Browser-Fallback, Test-Schaltfläche pro Zeile, Fehlschläge werden nie zwischengespeichert
|
|
38
38
|
|
|
39
39
|
## 📦 Installation
|
package/README.es.md
CHANGED
|
@@ -33,7 +33,7 @@ Los modelos de la familia DeepSeek suelen razonar en chino — o en el idioma en
|
|
|
33
33
|
- **🎚️ Momento de traducción ajustable** — pre-traducir todo / carga diferida de cadenas antiguas (por defecto) / solo al expandir
|
|
34
34
|
- **🔗 Cadena de proveedores dinámica** — el orden de la lista es el orden de uso: arrastra para reordenar y activa o desactiva cada fila. Integrados google gtx / bing / Ollama local más cualquier endpoint personalizado
|
|
35
35
|
- **🔌 Proveedores personalizados (OpenAI y Anthropic)** — añade desde el panel cualquier endpoint compatible con OpenAI (`/v1/chat/completions`) o la **Anthropic Messages API** (Claude): tipo, preajuste, URL base, clave de API y modelo
|
|
36
|
-
- **🪄 Hereda los proveedores configurados en DSH** — detecta filas DSH de solo lectura desde `settings.yaml` (`llm-pi-ai.providers`) y un botón reescanea y las añade todas a la cadena; la clave se resuelve en cada petición desde `.credentials.yaml` y nunca se guarda en la config del plugin
|
|
36
|
+
- **🪄 Hereda los proveedores configurados en DSH** — detecta filas DSH de solo lectura desde `settings.yaml` (`llm-pi-ai.providers`) y un botón reescanea y las añade todas a la cadena; la clave se resuelve en cada petición desde `.credentials.yaml` y nunca se guarda en la config del plugin. La ruta por defecto del propio harness también cuenta: si `agent-default-model` apunta a `deepseek-official`, la API oficial de DeepSeek aparece como una fila DSH más
|
|
37
37
|
- **⏱️ Resistente** — 3 reintentos con backoff + respaldo directo del navegador, botón de prueba por fila, los fallos nunca se almacenan en caché
|
|
38
38
|
|
|
39
39
|
## 📦 Instalación
|
package/README.fr.md
CHANGED
|
@@ -33,7 +33,7 @@ Les modèles de la famille DeepSeek raisonnent souvent en chinois — ou dans la
|
|
|
33
33
|
- **🎚️ Moment de traduction réglable** — tout pré-traduire / chargement différé des anciennes chaînes (défaut) / uniquement à l'ouverture
|
|
34
34
|
- **🔗 Chaîne de fournisseurs dynamique** — l'ordre de la liste est l'ordre d'exécution : glissez pour réordonner, activez ou désactivez chaque ligne. Intégrés google gtx / bing / Ollama local, plus tout endpoint personnalisé
|
|
35
35
|
- **🔌 Fournisseurs personnalisés (OpenAI et Anthropic)** — ajoutez depuis le panneau tout endpoint compatible OpenAI (`/v1/chat/completions`) ou l'**Anthropic Messages API** (Claude) : type, préréglage, URL de base, clé API et modèle
|
|
36
|
-
- **🪄 Hérite des fournisseurs configurés dans DSH** — détecte les lignes DSH en lecture seule depuis `settings.yaml` (`llm-pi-ai.providers`), et un bouton relance l'analyse et les ajoute toutes à la chaîne ; la clé est résolue à chaque requête depuis `.credentials.yaml` et n'est jamais écrite dans la config du plugin
|
|
36
|
+
- **🪄 Hérite des fournisseurs configurés dans DSH** — détecte les lignes DSH en lecture seule depuis `settings.yaml` (`llm-pi-ai.providers`), et un bouton relance l'analyse et les ajoute toutes à la chaîne ; la clé est résolue à chaque requête depuis `.credentials.yaml` et n'est jamais écrite dans la config du plugin. La route par défaut du harness compte aussi : si `agent-default-model` désigne `deepseek-official`, l'API officielle DeepSeek apparaît comme une ligne DSH de plus
|
|
37
37
|
- **⏱️ Résilient** — 3 tentatives avec backoff + secours direct du navigateur, bouton de test par ligne, les échecs ne sont jamais mis en cache
|
|
38
38
|
|
|
39
39
|
## 📦 Installation
|
package/README.ja.md
CHANGED
|
@@ -33,7 +33,7 @@ DeepSeek 系モデルは中国語で考えることが多く、あるいはた
|
|
|
33
33
|
- **🎚️ 翻訳タイミングを調整可能** — すべて事前翻訳 / 履歴を遅延ロード(既定)/ 展開時のみ翻訳
|
|
34
34
|
- **🔗 動的プロバイダーチェーン** — 一覧の順序がそのまま実行順。ドラッグで並べ替え、行ごとにオン/オフ。組み込みの google gtx / bing / ローカル Ollama に加えて任意のカスタム端点
|
|
35
35
|
- **🔌 カスタムプロバイダー(OpenAI / Anthropic)** — 設定パネルから任意の OpenAI 互換端点(`/v1/chat/completions`)や **Anthropic Messages API**(Claude)を追加:種類・プリセット・ベース URL・API キー・モデル
|
|
36
|
-
- **🪄 DSH 設定のプロバイダーを引き継ぐ** — `settings.yaml`(`llm-pi-ai.providers`)から読み取り専用の DSH 行を自動検出し、ボタン1つで再スキャンしてまとめてチェーンに追加。キーは `.credentials.yaml`
|
|
36
|
+
- **🪄 DSH 設定のプロバイダーを引き継ぐ** — `settings.yaml`(`llm-pi-ai.providers`)から読み取り専用の DSH 行を自動検出し、ボタン1つで再スキャンしてまとめてチェーンに追加。キーは `.credentials.yaml` からリクエスト時に解決され、プラグインの設定には保存されません。harness 自身の既定ルートも対象です:`agent-default-model` が `deepseek-official` を指していれば、DeepSeek の公式 API も DSH 行として提供されます
|
|
37
37
|
- **⏱️ 失敗に強い** — host は3回バックオフ再試行 + ブラウザ直接フォールバック、行ごとのテストボタン、失敗結果はキャッシュしない
|
|
38
38
|
|
|
39
39
|
## 📦 インストール
|
package/README.ko.md
CHANGED
|
@@ -33,7 +33,7 @@ DeepSeek 계열 모델은 중국어로, 또는 우연히 생각에 쓰는 언어
|
|
|
33
33
|
- **🎚️ 번역 시점 조절** — 모두 사전 번역 / 이전 체인 지연 로딩(기본)/ 펼친 체인만 번역
|
|
34
34
|
- **🔗 동적 제공자 체인** — 목록 순서가 곧 실행 순서. 끌어서 정렬하고 행마다 켜고 끄기. 내장 google gtx / bing / 로컬 Ollama에 더해 임의의 사용자 지정 엔드포인트
|
|
35
35
|
- **🔌 사용자 지정 제공자(OpenAI / Anthropic)** — 설정 패널에서 OpenAI 호환 엔드포인트(`/v1/chat/completions`)나 **Anthropic Messages API**(Claude)를 추가: 유형, 프리셋, 베이스 URL, API 키, 모델
|
|
36
|
-
- **🪄 DSH 설정의 제공자 상속** — `settings.yaml`(`llm-pi-ai.providers`)에서 읽기 전용 DSH 행을 자동 발견하고, 버튼 한 번으로 다시 검사해 모두 체인에 추가. 키는 요청 시 `.credentials.yaml`에서 해석되며 플러그인 설정에 저장되지
|
|
36
|
+
- **🪄 DSH 설정의 제공자 상속** — `settings.yaml`(`llm-pi-ai.providers`)에서 읽기 전용 DSH 행을 자동 발견하고, 버튼 한 번으로 다시 검사해 모두 체인에 추가. 키는 요청 시 `.credentials.yaml`에서 해석되며 플러그인 설정에 저장되지 않음. harness 자체의 기본 경로도 포함됩니다: `agent-default-model`이 `deepseek-official`을 가리키면 DeepSeek 공식 API도 DSH 행으로 제공됩니다
|
|
37
37
|
- **⏱️ 실패에 강함** — host 3회 백오프 재시도 + 브라우저 직접 폴백, 행별 테스트 버튼, 실패 결과는 캐시하지 않음
|
|
38
38
|
|
|
39
39
|
## 📦 설치
|
package/README.md
CHANGED
|
@@ -24,7 +24,7 @@ DeepSeek-class models often reason in Chinese — or in whatever language they h
|
|
|
24
24
|
- **🌍 8 languages, one consistent UI** — 中文 / English / 日本語 / 한국어 / Español / Français / Deutsch / Русский; the settings panel, thinking rows and task cards all follow your choice, and it persists across reloads
|
|
25
25
|
- **🔗 Dynamic provider chain** — order providers by drag-and-drop and enable/disable each one. Built-ins (google gtx, bing, local Ollama) plus any number of custom providers; the chain already ends with the free providers, so a second fallback pass is a config-file option, not a UI one
|
|
26
26
|
- **🔌 Custom providers (OpenAI & Anthropic)** — add arbitrary OpenAI-compatible endpoints (any `/v1/chat/completions` gateway) or native **Anthropic Messages API** endpoints (Claude) from the settings panel: name, type, base URL, API key, model
|
|
27
|
-
- **🪄 DSH provider discovery** — providers already configured in DSH's `settings.yaml` (`llm-pi-ai.providers`, e.g. linuxdo-hub, coding-hub) are auto-discovered and appear in the chain as read-only "DSH" entries, and **one button in settings rescans and adds them all at once**; keys are resolved from `.credentials.yaml` at runtime and never written to the plugin's config
|
|
27
|
+
- **🪄 DSH provider discovery** — providers already configured in DSH's `settings.yaml` (`llm-pi-ai.providers`, e.g. linuxdo-hub, coding-hub) are auto-discovered and appear in the chain as read-only "DSH" entries, and **one button in settings rescans and adds them all at once**; keys are resolved from `.credentials.yaml` at runtime and never written to the plugin's config. The harness's own default route counts too: when `agent-default-model` points at `deepseek-official`, DeepSeek's API is offered as one more DSH entry
|
|
28
28
|
- **🔒 Private & offline-first** — local Ollama (qwen2.5:7b / 14b or custom) is a first-class provider: free, unlimited, nothing leaves your machine. First local-model selection **auto-downloads** the model with a live progress bar and enables it when done
|
|
29
29
|
- **🧠 Zero context cost** — pure display layer: the model still sees the original text, and translated text never consumes the context window
|
|
30
30
|
- **☁️ Google / Bing fallback** — automatic switch when other providers are unavailable (google goes through a Node CONNECT tunnel using the system proxy, bypassing anti-bot blocks)
|
package/README.ru.md
CHANGED
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
- **🎚️ Настраиваемый момент перевода** — переводить всё / ленивая загрузка старых цепочек (по умолчанию) / только при раскрытии
|
|
34
34
|
- **🔗 Динамическая цепочка провайдеров** — порядок списка и есть порядок обращения: перетаскивайте для сортировки, включайте и выключайте каждую строку. Встроенные google gtx / bing / локальный Ollama плюс любые свои эндпоинты
|
|
35
35
|
- **🔌 Свои провайдеры (OpenAI и Anthropic)** — из панели можно добавить любой OpenAI-совместимый эндпоинт (`/v1/chat/completions`) или **Anthropic Messages API** (Claude): тип, шаблон, базовый URL, ключ API, модель
|
|
36
|
-
- **🪄 Наследование провайдеров из DSH** — читает из `settings.yaml` (`llm-pi-ai.providers`) строки DSH только для чтения; одна кнопка заново сканирует и добавляет их все в цепочку. Ключ разрешается на каждый запрос из `.credentials.yaml` и никогда не попадает в конфиг
|
|
36
|
+
- **🪄 Наследование провайдеров из DSH** — читает из `settings.yaml` (`llm-pi-ai.providers`) строки DSH только для чтения; одна кнопка заново сканирует и добавляет их все в цепочку. Ключ разрешается на каждый запрос из `.credentials.yaml` и никогда не попадает в конфиг плагина. Собственный маршрут харнесса тоже учитывается: если `agent-default-model` указывает на `deepseek-official`, официальный API DeepSeek появляется как ещё одна строка DSH
|
|
37
37
|
- **⏱️ Устойчивость** — 3 повтора с backoff + прямой запрос из браузера, кнопка проверки в каждой строке, ошибки не кэшируются
|
|
38
38
|
|
|
39
39
|
## 📦 Установка
|
package/README.zh-CN.md
CHANGED
|
@@ -33,7 +33,7 @@ DeepSeek 系模型经常用中文思考——或者用它们碰巧习惯的语
|
|
|
33
33
|
- **🎚️ 可调翻译时机** — 三档:全部预翻译 / 懒加载历史(默认)/ 仅展开时翻译
|
|
34
34
|
- **🔗 动态提供方链** — 列表顺序就是投递顺序:拖动排序、逐行开关;内置 google gtx / bing / 本地 Ollama,外加任意数量的自定义端点
|
|
35
35
|
- **🔌 自定义提供方(OpenAI 与 Anthropic)** — 设置面板里可添加任意 OpenAI 兼容端点(任何 `/v1/chat/completions` 网关)或原生 **Anthropic Messages API**(Claude):类型、预设、接口地址、API 密钥、模型
|
|
36
|
-
- **🪄 继承 DSH 已配置的提供方** — 自动发现 `settings.yaml`(`llm-pi-ai.providers`)里的只读 DSH 行,一个按钮重新扫描并全部加入链;密钥在请求时从 `.credentials.yaml`
|
|
36
|
+
- **🪄 继承 DSH 已配置的提供方** — 自动发现 `settings.yaml`(`llm-pi-ai.providers`)里的只读 DSH 行,一个按钮重新扫描并全部加入链;密钥在请求时从 `.credentials.yaml` 解析,绝不写入插件配置;harness 自己的默认路线也算:`agent-default-model` 指向 `deepseek-official` 时,DeepSeek 官方 API 也会作为一条 DSH 条目提供
|
|
37
37
|
- **⏱️ 失败韧性** — host 请求 3 次退避重试 + 浏览器直连兜底、每行独立的测试按钮、失败结果不缓存
|
|
38
38
|
|
|
39
39
|
## 📦 安装
|
package/lib/client.js
CHANGED
|
@@ -23,7 +23,7 @@ window.__ModuleLoader__.load({
|
|
|
23
23
|
// there yet (an older process still serving the port), and the contract test
|
|
24
24
|
// pins PLUGIN_VERSION to package.json so the two can never drift.
|
|
25
25
|
var PLUGIN_NAME = "dsh-think-translate";
|
|
26
|
-
var PLUGIN_VERSION = "1.2.
|
|
26
|
+
var PLUGIN_VERSION = "1.2.3";
|
|
27
27
|
var PLUGIN_REPO = "https://github.com/UncleK/dsh-think-translate";
|
|
28
28
|
// The official MarkdownText contract changed in 0.1.2-alpha: it now takes a
|
|
29
29
|
// nested `labels` object and dereferences it without defaults inside its code
|
|
@@ -142,7 +142,7 @@ window.__ModuleLoader__.load({
|
|
|
142
142
|
".xl-provider-row:active{opacity:.55}",
|
|
143
143
|
".xl-provider-type{font-size:11px;opacity:.6;flex:0 0 auto}",
|
|
144
144
|
".xl-provider-name{font-size:12px;font-weight:500;flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}",
|
|
145
|
-
".xl-badge{font-size:
|
|
145
|
+
".xl-badge{font-size:10px;line-height:16px;padding:0 6px;border-radius:999px;border:1px solid var(--dsw-alias-border-l2,rgba(127,127,127,.45));background:transparent;color:inherit;opacity:.7;font-weight:500;white-space:nowrap}",
|
|
146
146
|
".xl-add-form{display:flex;flex-direction:column;gap:6px;padding:8px;background:var(--dsw-alias-bg-layer-2,rgba(127,127,127,.08));border-radius:8px;margin:4px 0}",
|
|
147
147
|
".xl-form-row{display:flex;align-items:center;gap:8px}",
|
|
148
148
|
".xl-form-label{flex:0 0 62px;font-size:11.5px;opacity:.65}",
|
|
@@ -155,7 +155,6 @@ window.__ModuleLoader__.load({
|
|
|
155
155
|
".xl-menu-item:hover{background:var(--dsw-alias-bg-layer-2,rgba(127,127,127,.14))}",
|
|
156
156
|
".xl-menu-item-active{color:var(--dsw-alias-brand-primary,#4c9aff);font-weight:600}",
|
|
157
157
|
".xl-menu-note{font-size:11px;opacity:.55;padding:4px 8px 2px;margin-top:2px;border-top:1px solid var(--dsw-alias-border-l1,rgba(127,127,127,.2))}",
|
|
158
|
-
".xl-dsh-menu{margin:4px 0;padding:6px;border:1px solid var(--dsw-alias-border-l1,rgba(127,127,127,.35));border-radius:8px;background:var(--dsw-alias-bg-layer-2,rgba(127,127,127,.06))}",
|
|
159
158
|
".xl-caret:disabled{opacity:.35;cursor:default}",
|
|
160
159
|
".xl-unused{opacity:.85}",
|
|
161
160
|
".xl-kv-value{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}",
|
|
@@ -170,6 +169,7 @@ window.__ModuleLoader__.load({
|
|
|
170
169
|
".xl-model-item-active{border-color:var(--dsw-alias-brand-primary,#4c9aff);color:var(--dsw-alias-brand-primary,#4c9aff)}",
|
|
171
170
|
".xl-x-btn{border:0;background:none;color:inherit;opacity:.5;cursor:pointer;font-size:15px;line-height:1;padding:0 6px;border-radius:4px}",
|
|
172
171
|
".xl-x-btn:hover{opacity:1;background:var(--dsw-alias-bg-layer-2,rgba(127,127,127,.12))}",
|
|
172
|
+
".xl-add-btn{padding:1px 7px;font-size:14px;line-height:1.35;font-weight:600}",
|
|
173
173
|
".xl-provider-row .xl-sel{max-width:260px}",
|
|
174
174
|
".xl-model-row{display:flex;align-items:center;gap:6px;flex-wrap:wrap}",
|
|
175
175
|
".xl-model-row .xl-sel{max-width:220px}",
|
|
@@ -260,9 +260,12 @@ window.__ModuleLoader__.load({
|
|
|
260
260
|
providerBaseURL: "接口地址",
|
|
261
261
|
providerApiKey: "API 密钥",
|
|
262
262
|
footnotes: "脚注",
|
|
263
|
-
dshImport: "
|
|
264
|
-
dshImportAll: "
|
|
263
|
+
dshImport: "重新扫描 DSH 配置",
|
|
264
|
+
dshImportAll: "全部加入",
|
|
265
265
|
dshImportEmpty: "DSH 里没有发现已配置的 provider",
|
|
266
|
+
dshRescanning: "正在重新扫描 DSH 配置…",
|
|
267
|
+
dshRescanDone: "重新扫描完成",
|
|
268
|
+
providerDshList: "DSH 已配置提供方",
|
|
266
269
|
starCta: "给个星星鼓励一下",
|
|
267
270
|
providerPreset: "提供方",
|
|
268
271
|
currentInUse: "当前使用",
|
|
@@ -281,7 +284,7 @@ window.__ModuleLoader__.load({
|
|
|
281
284
|
providerOff: "关闭",
|
|
282
285
|
providerSaved: "已保存",
|
|
283
286
|
providerDeleted: "已删除",
|
|
284
|
-
providerDrag: "
|
|
287
|
+
providerDrag: "翻译优先级(拖动排序)",
|
|
285
288
|
providerCancel: "取消",
|
|
286
289
|
providerSave: "保存",
|
|
287
290
|
providerSaveError: "保存失败",
|
|
@@ -308,9 +311,12 @@ window.__ModuleLoader__.load({
|
|
|
308
311
|
providerBaseURL: "Base URL",
|
|
309
312
|
providerApiKey: "API key",
|
|
310
313
|
footnotes: "Footnotes",
|
|
311
|
-
dshImport: "
|
|
312
|
-
dshImportAll: "Add all
|
|
314
|
+
dshImport: "Rescan DSH config",
|
|
315
|
+
dshImportAll: "Add all",
|
|
313
316
|
dshImportEmpty: "No provider configured in DSH",
|
|
317
|
+
dshRescanning: "Rescanning the DSH config…",
|
|
318
|
+
dshRescanDone: "Rescan complete",
|
|
319
|
+
providerDshList: "Configured in DSH",
|
|
314
320
|
starCta: "Star it on GitHub",
|
|
315
321
|
providerPreset: "Provider",
|
|
316
322
|
currentInUse: "In use",
|
|
@@ -329,7 +335,7 @@ window.__ModuleLoader__.load({
|
|
|
329
335
|
providerOff: "off",
|
|
330
336
|
providerSaved: "Saved",
|
|
331
337
|
providerDeleted: "Deleted",
|
|
332
|
-
providerDrag: "
|
|
338
|
+
providerDrag: "Translation priority (drag to reorder)",
|
|
333
339
|
providerCancel: "Cancel",
|
|
334
340
|
providerSave: "Save",
|
|
335
341
|
providerSaveError: "Save failed",
|
|
@@ -356,9 +362,12 @@ window.__ModuleLoader__.load({
|
|
|
356
362
|
providerApiKey: "API キー",
|
|
357
363
|
copy: "コピー", copied: "コピー済み",
|
|
358
364
|
footnotes: "脚注",
|
|
359
|
-
dshImport: "DSH
|
|
360
|
-
dshImportAll: "
|
|
365
|
+
dshImport: "DSH 設定を再スキャン",
|
|
366
|
+
dshImportAll: "すべて追加",
|
|
361
367
|
dshImportEmpty: "DSH に設定済みプロバイダーがありません",
|
|
368
|
+
dshRescanning: "DSH 設定を再スキャン中…",
|
|
369
|
+
dshRescanDone: "再スキャン完了",
|
|
370
|
+
providerDshList: "DSH に設定済みの提供元",
|
|
362
371
|
starCta: "GitHub でスターを",
|
|
363
372
|
providerPreset: "提供元",
|
|
364
373
|
currentInUse: "使用中",
|
|
@@ -377,7 +386,7 @@ window.__ModuleLoader__.load({
|
|
|
377
386
|
providerOff: "オフ",
|
|
378
387
|
providerSaved: "保存しました",
|
|
379
388
|
providerDeleted: "削除しました",
|
|
380
|
-
providerDrag: "
|
|
389
|
+
providerDrag: "翻訳の優先順位(ドラッグで並べ替え)",
|
|
381
390
|
providerCancel: "キャンセル",
|
|
382
391
|
providerSave: "保存",
|
|
383
392
|
providerSaveError: "保存に失敗",
|
|
@@ -404,9 +413,12 @@ window.__ModuleLoader__.load({
|
|
|
404
413
|
providerApiKey: "API 키",
|
|
405
414
|
copy: "복사", copied: "복사됨",
|
|
406
415
|
footnotes: "각주",
|
|
407
|
-
dshImport: "DSH
|
|
408
|
-
dshImportAll: "모두
|
|
416
|
+
dshImport: "DSH 설정 다시 검사",
|
|
417
|
+
dshImportAll: "모두 추가",
|
|
409
418
|
dshImportEmpty: "DSH에 구성된 제공자가 없습니다",
|
|
419
|
+
dshRescanning: "DSH 설정을 다시 검사하는 중…",
|
|
420
|
+
dshRescanDone: "다시 검사 완료",
|
|
421
|
+
providerDshList: "DSH에 설정된 제공자",
|
|
410
422
|
starCta: "GitHub에서 별 주기",
|
|
411
423
|
providerPreset: "제공자",
|
|
412
424
|
currentInUse: "사용 중",
|
|
@@ -425,7 +437,7 @@ window.__ModuleLoader__.load({
|
|
|
425
437
|
providerOff: "끄기",
|
|
426
438
|
providerSaved: "저장됨",
|
|
427
439
|
providerDeleted: "삭제됨",
|
|
428
|
-
providerDrag: "끌어서
|
|
440
|
+
providerDrag: "번역 우선순위(끌어서 정렬)",
|
|
429
441
|
providerCancel: "취소",
|
|
430
442
|
providerSave: "저장",
|
|
431
443
|
providerSaveError: "저장 실패",
|
|
@@ -452,9 +464,12 @@ window.__ModuleLoader__.load({
|
|
|
452
464
|
providerApiKey: "Clave de API",
|
|
453
465
|
copy: "Copiar", copied: "Copiado",
|
|
454
466
|
footnotes: "Notas al pie",
|
|
455
|
-
dshImport: "
|
|
456
|
-
dshImportAll: "Añadir todo
|
|
467
|
+
dshImport: "Reescanear la config de DSH",
|
|
468
|
+
dshImportAll: "Añadir todo",
|
|
457
469
|
dshImportEmpty: "No hay proveedores configurados en DSH",
|
|
470
|
+
dshRescanning: "Reescaneando la config de DSH…",
|
|
471
|
+
dshRescanDone: "Reescaneo completado",
|
|
472
|
+
providerDshList: "Configurados en DSH",
|
|
458
473
|
starCta: "Danos una estrella",
|
|
459
474
|
providerPreset: "Proveedor",
|
|
460
475
|
currentInUse: "En uso",
|
|
@@ -473,7 +488,7 @@ window.__ModuleLoader__.load({
|
|
|
473
488
|
providerOff: "Desactivado",
|
|
474
489
|
providerSaved: "Guardado",
|
|
475
490
|
providerDeleted: "Eliminado",
|
|
476
|
-
providerDrag: "
|
|
491
|
+
providerDrag: "Prioridad de traducción (arrastra para reordenar)",
|
|
477
492
|
providerCancel: "Cancelar",
|
|
478
493
|
providerSave: "Guardar",
|
|
479
494
|
providerSaveError: "Error al guardar",
|
|
@@ -500,9 +515,12 @@ window.__ModuleLoader__.load({
|
|
|
500
515
|
providerApiKey: "Clé API",
|
|
501
516
|
copy: "Copier", copied: "Copié",
|
|
502
517
|
footnotes: "Notes de bas de page",
|
|
503
|
-
dshImport: "
|
|
504
|
-
dshImportAll: "Tout ajouter
|
|
518
|
+
dshImport: "Réanalyser la config DSH",
|
|
519
|
+
dshImportAll: "Tout ajouter",
|
|
505
520
|
dshImportEmpty: "Aucun fournisseur configuré dans DSH",
|
|
521
|
+
dshRescanning: "Réanalyse de la config DSH…",
|
|
522
|
+
dshRescanDone: "Réanalyse terminée",
|
|
523
|
+
providerDshList: "Configurés dans DSH",
|
|
506
524
|
starCta: "Mettre une étoile",
|
|
507
525
|
providerPreset: "Fournisseur",
|
|
508
526
|
currentInUse: "En cours d'utilisation",
|
|
@@ -521,7 +539,7 @@ window.__ModuleLoader__.load({
|
|
|
521
539
|
providerOff: "Désactivé",
|
|
522
540
|
providerSaved: "Enregistré",
|
|
523
541
|
providerDeleted: "Supprimé",
|
|
524
|
-
providerDrag: "
|
|
542
|
+
providerDrag: "Priorité de traduction (glisser pour réordonner)",
|
|
525
543
|
providerCancel: "Annuler",
|
|
526
544
|
providerSave: "Enregistrer",
|
|
527
545
|
providerSaveError: "Échec de l'enregistrement",
|
|
@@ -548,9 +566,12 @@ window.__ModuleLoader__.load({
|
|
|
548
566
|
providerApiKey: "API-Schlüssel",
|
|
549
567
|
copy: "Kopieren", copied: "Kopiert",
|
|
550
568
|
footnotes: "Fußnoten",
|
|
551
|
-
dshImport: "
|
|
552
|
-
dshImportAll: "Alle
|
|
569
|
+
dshImport: "DSH-Konfiguration neu einlesen",
|
|
570
|
+
dshImportAll: "Alle hinzufügen",
|
|
553
571
|
dshImportEmpty: "Kein konfigurierter Anbieter in DSH",
|
|
572
|
+
dshRescanning: "DSH-Konfiguration wird neu eingelesen…",
|
|
573
|
+
dshRescanDone: "Neu eingelesen",
|
|
574
|
+
providerDshList: "In DSH konfiguriert",
|
|
554
575
|
starCta: "Mit einem Stern danken",
|
|
555
576
|
providerPreset: "Anbieter",
|
|
556
577
|
currentInUse: "In Benutzung",
|
|
@@ -569,7 +590,7 @@ window.__ModuleLoader__.load({
|
|
|
569
590
|
providerOff: "Aus",
|
|
570
591
|
providerSaved: "Gespeichert",
|
|
571
592
|
providerDeleted: "Gelöscht",
|
|
572
|
-
providerDrag: "
|
|
593
|
+
providerDrag: "Übersetzungspriorität (zum Sortieren ziehen)",
|
|
573
594
|
providerCancel: "Abbrechen",
|
|
574
595
|
providerSave: "Speichern",
|
|
575
596
|
providerSaveError: "Speichern fehlgeschlagen",
|
|
@@ -596,9 +617,12 @@ window.__ModuleLoader__.load({
|
|
|
596
617
|
providerApiKey: "Ключ API",
|
|
597
618
|
copy: "Копировать", copied: "Скопировано",
|
|
598
619
|
footnotes: "Сноски",
|
|
599
|
-
dshImport: "
|
|
600
|
-
dshImportAll: "Добавить все
|
|
620
|
+
dshImport: "Пересканировать конфиг DSH",
|
|
621
|
+
dshImportAll: "Добавить все",
|
|
601
622
|
dshImportEmpty: "В DSH нет настроенных провайдеров",
|
|
623
|
+
dshRescanning: "Пересканирую конфиг DSH…",
|
|
624
|
+
dshRescanDone: "Сканирование завершено",
|
|
625
|
+
providerDshList: "Настроены в DSH",
|
|
602
626
|
starCta: "Поставить звезду",
|
|
603
627
|
providerPreset: "Провайдер",
|
|
604
628
|
currentInUse: "Используется",
|
|
@@ -617,7 +641,7 @@ window.__ModuleLoader__.load({
|
|
|
617
641
|
providerOff: "Выкл",
|
|
618
642
|
providerSaved: "Сохранено",
|
|
619
643
|
providerDeleted: "Удалено",
|
|
620
|
-
providerDrag: "
|
|
644
|
+
providerDrag: "Приоритет перевода (перетащите для порядка)",
|
|
621
645
|
providerCancel: "Отмена",
|
|
622
646
|
providerSave: "Сохранить",
|
|
623
647
|
providerSaveError: "Не удалось сохранить",
|
|
@@ -1974,34 +1998,30 @@ window.__ModuleLoader__.load({
|
|
|
1974
1998
|
// URL or a key per provider.
|
|
1975
1999
|
var dshAll = Object.keys(provs).filter(function (id) { return provs[id] && provs[id].source === "dsh"; });
|
|
1976
2000
|
var dshAvailable = dshAll.filter(function (id) { return chain.indexOf(id) < 0; });
|
|
1977
|
-
|
|
2001
|
+
// The host already merges the harness's providers into the config it serves,
|
|
2002
|
+
// so they show up in the "available providers" list without being asked for.
|
|
2003
|
+
// What the button adds is the RE-READ: editing ~/.dsh/settings.yaml (or
|
|
2004
|
+
// fixing the home the host looks at) otherwise needs a web restart.
|
|
2005
|
+
var rescanDsh = function () {
|
|
2006
|
+
setMsg(t.dshRescanning);
|
|
1978
2007
|
fetch("/_xlate/dsh-scan").then(function (r) { return r.json(); })
|
|
1979
2008
|
.then(function (c) {
|
|
1980
|
-
if (c
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
2009
|
+
if (!c || !c.providers) throw new Error("bad scan response");
|
|
2010
|
+
cfgRef.current = c;
|
|
2011
|
+
setCfg(c);
|
|
2012
|
+
var d = c.dshScan || {};
|
|
2013
|
+
var found = (d.providers || []).length;
|
|
2014
|
+
setMsg(found
|
|
2015
|
+
? t.dshRescanDone + " · " + found
|
|
2016
|
+
: t.dshImportEmpty + (d.home ? " · " + d.home + "/settings.yaml" : ""));
|
|
1984
2017
|
})
|
|
1985
2018
|
.catch(function (e) { setMsg(t.connFail + ": " + (e && e.message ? e.message : e)); });
|
|
1986
2019
|
};
|
|
1987
|
-
// Where the host looked for the harness settings, and what it found there:
|
|
1988
|
-
// an empty scan used to be a dead end, so the panel now names the file it
|
|
1989
|
-
// read (the usual cause is a home directory the plugin guessed wrong).
|
|
1990
|
-
var dshScanNote = function () {
|
|
1991
|
-
var d = cfg && cfg.dshScan;
|
|
1992
|
-
if (!d || !d.home) return null;
|
|
1993
|
-
var where = d.home + "/settings.yaml";
|
|
1994
|
-
var detail = d.settingsFound
|
|
1995
|
-
? (d.providers && d.providers.length ? d.providers.join(", ") : t.dshImportEmpty)
|
|
1996
|
-
: (t.dshImportEmpty + " · " + where);
|
|
1997
|
-
return createElement("div", { className: "xl-note", style: { marginTop: "4px" } }, detail);
|
|
1998
|
-
};
|
|
1999
2020
|
var addAllDsh = function () {
|
|
2000
2021
|
var next = chain.slice();
|
|
2001
2022
|
dshAvailable.forEach(function (id) { if (next.indexOf(id) < 0) next.push(id); });
|
|
2002
2023
|
applyLocal({ chain: next });
|
|
2003
2024
|
saveCfg({ chain: next });
|
|
2004
|
-
setDshMenu(false);
|
|
2005
2025
|
};
|
|
2006
2026
|
|
|
2007
2027
|
// Local-model menu: opened by the chip on the endpoint's own row and
|
|
@@ -2164,10 +2184,23 @@ window.__ModuleLoader__.load({
|
|
|
2164
2184
|
var unused = Object.keys(provs).filter(function (id) {
|
|
2165
2185
|
return chain.indexOf(id) < 0;
|
|
2166
2186
|
});
|
|
2187
|
+
var unusedDsh = unused.filter(function (id) { return provs[id] && provs[id].source === "dsh"; });
|
|
2167
2188
|
var unusedArea = null;
|
|
2168
2189
|
if (unused.length > 0) {
|
|
2190
|
+
// The heading names what the rows are — in practice the DSH entries the
|
|
2191
|
+
// host discovered; the generic wording stays for a custom provider that
|
|
2192
|
+
// was saved without a chain reference.
|
|
2193
|
+
var allDsh = unusedDsh.length === unused.length;
|
|
2169
2194
|
unusedArea = createElement("div", { className: "xl-unused", style: { marginTop: "8px" } },
|
|
2170
|
-
|
|
2195
|
+
// The heading row carries the bulk action: the rows are right here, so
|
|
2196
|
+
// this is the one place that lists them (the old separate "inherit"
|
|
2197
|
+
// menu listed the same providers a second time).
|
|
2198
|
+
createElement("div", { style: { display: "flex", alignItems: "center", gap: "6px" } },
|
|
2199
|
+
createElement("div", { className: "xl-note", style: { fontWeight: 600, flex: "1 1 auto" } },
|
|
2200
|
+
allDsh ? t.providerDshList : t.providerUnused),
|
|
2201
|
+
unusedDsh.length > 1 ? createElement("button", {
|
|
2202
|
+
className: "xl-btn", type: "button", onClick: addAllDsh
|
|
2203
|
+
}, t.dshImportAll) : null),
|
|
2171
2204
|
unused.map(function (id) {
|
|
2172
2205
|
var up = provs[id] || {};
|
|
2173
2206
|
var isDsh = up.source === "dsh";
|
|
@@ -2175,7 +2208,13 @@ window.__ModuleLoader__.load({
|
|
|
2175
2208
|
createElement("span", { className: "xl-provider-type" }, providerLabel(id, up, t)),
|
|
2176
2209
|
createElement("span", { className: "xl-provider-name" }, id),
|
|
2177
2210
|
isDsh ? createElement("span", { className: "xl-badge" }, t.providerDsh) : null,
|
|
2178
|
-
|
|
2211
|
+
// A bare "+" with the wording in the tooltip: one narrow control
|
|
2212
|
+
// at the end of the row, same as the ↑↓/测试 cluster above.
|
|
2213
|
+
createElement("button", {
|
|
2214
|
+
className: "xl-btn xl-add-btn", type: "button",
|
|
2215
|
+
title: t.providerAddToChain, "aria-label": t.providerAddToChain,
|
|
2216
|
+
onClick: function () { actions.addToChain(id); }
|
|
2217
|
+
}, "+"));
|
|
2179
2218
|
}));
|
|
2180
2219
|
}
|
|
2181
2220
|
|
|
@@ -2187,29 +2226,8 @@ window.__ModuleLoader__.load({
|
|
|
2187
2226
|
: createElement("button", { className: "xl-btn", type: "button", onClick: startAdd, style: { marginTop: "4px" } },
|
|
2188
2227
|
"+ " + t.providerAdd),
|
|
2189
2228
|
adding || editingId ? null
|
|
2190
|
-
: createElement("button", { className: "xl-btn", type: "button", onClick:
|
|
2191
|
-
"
|
|
2192
|
-
dshMenu ? createElement("div", { className: "xl-dsh-menu" },
|
|
2193
|
-
dshAvailable.length === 0
|
|
2194
|
-
? createElement("div", null,
|
|
2195
|
-
createElement("div", { className: "xl-note" }, t.dshImportEmpty),
|
|
2196
|
-
dshScanNote())
|
|
2197
|
-
: createElement("div", null,
|
|
2198
|
-
dshAvailable.length > 1 ? createElement("button", {
|
|
2199
|
-
className: "xl-btn", type: "button", style: { marginBottom: "4px" }, onClick: addAllDsh
|
|
2200
|
-
}, t.dshImportAll) : null,
|
|
2201
|
-
dshAvailable.map(function (id) {
|
|
2202
|
-
var dp = provs[id] || {};
|
|
2203
|
-
return createElement("div", { key: id, className: "xl-provider-row" },
|
|
2204
|
-
createElement("span", { className: "xl-badge" }, t.providerDsh),
|
|
2205
|
-
createElement("span", { className: "xl-provider-name" }, id),
|
|
2206
|
-
createElement("span", { className: "xl-provider-type" }, providerLabel(id, dp, t)),
|
|
2207
|
-
dp.model ? createElement("span", { className: "xl-provider-type" }, dp.model) : null,
|
|
2208
|
-
createElement("button", {
|
|
2209
|
-
className: "xl-btn", type: "button",
|
|
2210
|
-
onClick: function () { actions.addToChain(id); }
|
|
2211
|
-
}, "+ " + t.providerAddToChain));
|
|
2212
|
-
}))) : null,
|
|
2229
|
+
: createElement("button", { className: "xl-btn", type: "button", onClick: rescanDsh, style: { marginTop: "4px", marginLeft: "6px" } },
|
|
2230
|
+
"↻ " + t.dshImport),
|
|
2213
2231
|
unusedArea,
|
|
2214
2232
|
msg ? createElement("div", { className: "xl-note", style: { marginTop: "6px" } }, msg) : null);
|
|
2215
2233
|
}
|
package/lib/index.js
CHANGED
|
@@ -771,6 +771,38 @@ function extractDshProviders(txt) {
|
|
|
771
771
|
return providers
|
|
772
772
|
}
|
|
773
773
|
|
|
774
|
+
// The harness ALSO has one built-in provider route that never shows up in
|
|
775
|
+
// llm-pi-ai.providers: `deepseek-official`, registered by llm-deepseek and
|
|
776
|
+
// configured through `agent-default-model` (provider + model) plus a credential
|
|
777
|
+
// ref. Its transport is OpenAI-compatible — llm-deepseek itself posts to
|
|
778
|
+
// `${baseURL}/chat/completions` with PUBLIC_BASE_URL = https://api.deepseek.com
|
|
779
|
+
// and the DEEPSEEK_API_KEY credential — so this plugin can drive it with the
|
|
780
|
+
// same adapter, which is what lets "inherit from DSH" offer DeepSeek's own API
|
|
781
|
+
// and not just the custom endpoints someone declared by hand.
|
|
782
|
+
const BUILTIN_HARNESS_ROUTES = {
|
|
783
|
+
'deepseek-official': { type: 'openai', baseURL: 'https://api.deepseek.com', apiKeyEnv: 'DEEPSEEK_API_KEY' },
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
// Returns { id, entry } for the harness's default model route when the plugin
|
|
787
|
+
// knows how to speak to it, else null. `refs` is the credential map, used only to
|
|
788
|
+
// confirm the key exists somewhere.
|
|
789
|
+
function extractHarnessDefaultRoute(txt, refs) {
|
|
790
|
+
const block = txt.match(/^agent-default-model:[^\n]*\n((?:[ \t]+[^\n]*\n?)*)/m)
|
|
791
|
+
if (!block) return null
|
|
792
|
+
const provider = (block[1].match(/^[ \t]+provider:[ \t]*(\S+)/m) || [])[1]
|
|
793
|
+
const model = (block[1].match(/^[ \t]+model:[ \t]*(\S+)/m) || [])[1]
|
|
794
|
+
if (!provider || !model) return null
|
|
795
|
+
const route = BUILTIN_HARNESS_ROUTES[provider]
|
|
796
|
+
if (!route) return null
|
|
797
|
+
const entry = { type: route.type, baseURL: route.baseURL, model: model }
|
|
798
|
+
// The ref is the route's documented credential; carry it even when the user
|
|
799
|
+
// keeps the key in the environment instead of .credentials.yaml, because the
|
|
800
|
+
// host resolves apiKeyEnv from both.
|
|
801
|
+
if (route.apiKeyEnv) entry.apiKeyEnv = route.apiKeyEnv
|
|
802
|
+
void refs
|
|
803
|
+
return { id: provider, entry: entry }
|
|
804
|
+
}
|
|
805
|
+
|
|
774
806
|
// (2026-09-01) Parse .credentials.yaml refs. Returns { envName: value }.
|
|
775
807
|
function extractCredRefs(txt) {
|
|
776
808
|
const refs = {}
|
|
@@ -836,6 +868,13 @@ async function discoverDshProviders() {
|
|
|
836
868
|
out[name] = entry
|
|
837
869
|
diag.providers.push(name)
|
|
838
870
|
}
|
|
871
|
+
// The harness's built-in route (deepseek-official): never in llm-pi-ai.providers,
|
|
872
|
+
// configured by agent-default-model. An id declared by hand wins.
|
|
873
|
+
const def = extractHarnessDefaultRoute(settingsTxt, refs)
|
|
874
|
+
if (def && !out[def.id]) {
|
|
875
|
+
out[def.id] = Object.assign({ source: 'dsh', enabled: false }, def.entry)
|
|
876
|
+
diag.providers.push(def.id)
|
|
877
|
+
}
|
|
839
878
|
} catch (e) {
|
|
840
879
|
diag.error = e instanceof Error ? e.message : String(e)
|
|
841
880
|
}
|
|
@@ -1430,7 +1469,7 @@ export function apply(ctx) {
|
|
|
1430
1469
|
// plugin system (which only reads name, inject, apply) ignores.
|
|
1431
1470
|
export {
|
|
1432
1471
|
buildChainFromPriority, migrateConfig, normalizeConfigPatch,
|
|
1433
|
-
applyFullProviders, extractDshProviders, extractCredRefs,
|
|
1472
|
+
applyFullProviders, extractDshProviders, extractCredRefs, extractHarnessDefaultRoute,
|
|
1434
1473
|
runChainFor, translateViaChain, removeFromChain,
|
|
1435
1474
|
needsTranslate, hasProse, chunkText, fnv, deepMerge,
|
|
1436
1475
|
structuredCloneSafe, ADAPTERS,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-think-translate",
|
|
3
3
|
"description": "Display-layer translation for the DSH web app: thinking chain, task cards, and optional answer text, in 8 target languages (local Ollama / any OpenAI-compatible or Anthropic endpoint / Google / Bing, fail-open)",
|
|
4
|
-
"version": "1.2.
|
|
4
|
+
"version": "1.2.3",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
7
7
|
"exports": {
|