@dsh-plus/llm-pi 0.1.13 → 0.1.15
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/lib/client.js +48 -50
- package/lib/index.d.ts +3 -2
- package/lib/index.js +633 -222
- package/package.json +28 -24
- package/src/auth-inline.ts +177 -0
- package/src/catalog/official.ts +0 -2
- package/src/client/api.ts +4 -3
- package/src/client/card.tsx +5 -13
- package/src/client/client.ts +16 -18
- package/src/client/constants.ts +11 -16
- package/src/compat.ts +136 -62
- package/src/config-api.ts +3 -3
- package/src/config.ts +25 -4
- package/src/deepseek-routes.ts +25 -0
- package/src/ns.ts +1 -1
- package/src/profiles-deepseek.ts +12 -6
- package/src/profiles.ts +439 -171
- package/src/resolve-dsh.ts +170 -13
- package/src/service.ts +26 -0
package/lib/client.js
CHANGED
|
@@ -196,14 +196,15 @@ window.__ModuleLoader__.load({
|
|
|
196
196
|
//#endregion
|
|
197
197
|
//#region ../shared/src/client/scope.ts
|
|
198
198
|
/**
|
|
199
|
-
*
|
|
199
|
+
* remote.settings 直连实现的命名空间 scope(官方配置页 tab 同款模式)。
|
|
200
200
|
* 读:describe 取命名空间视图(脱敏 value/revision + 顶层 writable);
|
|
201
201
|
* 刷新:remote `settings/document-updated`(按命名空间过滤)与
|
|
202
202
|
* `connection/reset`;generation 防旧读覆盖新发布。任何页面 origin
|
|
203
203
|
* (loopback 或 tailnet 信任域名)下行为一致。
|
|
204
204
|
* effect 归属调用方 fiber(label 需含插件名以便诊断)。
|
|
205
205
|
*/
|
|
206
|
-
function
|
|
206
|
+
function createSettingsScope(c, ns, label) {
|
|
207
|
+
const remote = c.get("remote");
|
|
207
208
|
let state = {
|
|
208
209
|
status: "loading",
|
|
209
210
|
value: void 0,
|
|
@@ -218,36 +219,37 @@ window.__ModuleLoader__.load({
|
|
|
218
219
|
};
|
|
219
220
|
const load = async () => {
|
|
220
221
|
const gen = ++generation;
|
|
221
|
-
let
|
|
222
|
+
let view;
|
|
222
223
|
try {
|
|
223
|
-
response = await
|
|
224
|
+
const response = await remote.settings.describe();
|
|
225
|
+
if (!response.ok) return;
|
|
226
|
+
view = response.value;
|
|
224
227
|
} catch {
|
|
225
228
|
return;
|
|
226
229
|
}
|
|
227
|
-
if (gen !== generation
|
|
228
|
-
const
|
|
229
|
-
|
|
230
|
-
if (view === void 0) {
|
|
230
|
+
if (gen !== generation) return;
|
|
231
|
+
const namespace = view.namespaces.find((candidate) => candidate.ns === ns);
|
|
232
|
+
if (namespace === void 0) {
|
|
231
233
|
publish({
|
|
232
234
|
status: "unavailable",
|
|
233
235
|
value: void 0,
|
|
234
236
|
revision: void 0,
|
|
235
|
-
writable
|
|
237
|
+
writable: view.writable
|
|
236
238
|
});
|
|
237
239
|
return;
|
|
238
240
|
}
|
|
239
241
|
publish({
|
|
240
242
|
status: "ready",
|
|
241
|
-
value:
|
|
242
|
-
revision:
|
|
243
|
-
writable
|
|
243
|
+
value: namespace.value,
|
|
244
|
+
revision: namespace.revision,
|
|
245
|
+
writable: view.writable
|
|
244
246
|
});
|
|
245
247
|
};
|
|
246
248
|
const refresh = (namespace) => {
|
|
247
249
|
if (namespace !== void 0 && namespace !== ns) return;
|
|
248
250
|
load();
|
|
249
251
|
};
|
|
250
|
-
const disposers = [
|
|
252
|
+
const disposers = [remote.$on("settings/document-updated", refresh), c.on("connection/reset", () => {
|
|
251
253
|
load();
|
|
252
254
|
})];
|
|
253
255
|
c.effect(() => () => {
|
|
@@ -265,6 +267,20 @@ window.__ModuleLoader__.load({
|
|
|
265
267
|
load
|
|
266
268
|
};
|
|
267
269
|
}
|
|
270
|
+
/** 以 remote.settings 构造命名空间绑定的 api 面。 */
|
|
271
|
+
function createNamespaceApi(remote, ns) {
|
|
272
|
+
return {
|
|
273
|
+
update: async (patch, expectedRevision) => {
|
|
274
|
+
const response = await remote.update(ns, patch, expectedRevision);
|
|
275
|
+
if (!response.ok) throw new Error(response.error.message ?? "settings update failed");
|
|
276
|
+
},
|
|
277
|
+
describe: async () => {
|
|
278
|
+
const response = await remote.describe();
|
|
279
|
+
if (!response.ok) throw new Error(response.error.message ?? "settings describe failed");
|
|
280
|
+
return response.value;
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
}
|
|
268
284
|
//#endregion
|
|
269
285
|
//#region ../shared/src/client/styles.ts
|
|
270
286
|
/**
|
|
@@ -371,7 +387,7 @@ ${extra}
|
|
|
371
387
|
* settings 命名空间字面量(纯常量,零依赖,浏览器半可安全引入)。
|
|
372
388
|
* 服务端经 settingsNamespace() 品牌化后使用(config.ts),浏览器半将其作为
|
|
373
389
|
* settings.plugin.item keyed 槽位的 key —— 同一字面量两处共用,防止漂移。
|
|
374
|
-
* 契约:
|
|
390
|
+
* 契约:0.1.2-alpha.1 起该槽位按「卡片编辑的 settings 命名空间」作 key 分发,
|
|
375
391
|
* 官方配置页只渲染 key 命中 Host 已注册命名空间的卡片。
|
|
376
392
|
* @module llm-pi/ns
|
|
377
393
|
*/
|
|
@@ -936,13 +952,18 @@ ${extra}
|
|
|
936
952
|
"medium",
|
|
937
953
|
"high"
|
|
938
954
|
];
|
|
939
|
-
/**
|
|
955
|
+
/**
|
|
956
|
+
* 逐协议 compat 字段表(来源:compat.ts,逐字段镜像官方 catalog.ts COMPAT_GATES)。
|
|
957
|
+
* 只列 offer 字段(withhold 字段官方写时拒绝,UI 不提供);取值约束对齐官方
|
|
958
|
+
* config.ts compatProfile schema。
|
|
959
|
+
*/
|
|
940
960
|
const COMPAT_FIELDS = {
|
|
941
961
|
"openai-completions": {
|
|
942
962
|
supportsStore: "boolean",
|
|
943
963
|
supportsDeveloperRole: "boolean",
|
|
944
964
|
supportsReasoningEffort: "boolean",
|
|
945
965
|
supportsUsageInStreaming: "boolean",
|
|
966
|
+
supportsFinishReason: "boolean",
|
|
946
967
|
maxTokensField: ["max_completion_tokens", "max_tokens"],
|
|
947
968
|
requiresToolResultName: "boolean",
|
|
948
969
|
requiresAssistantAfterToolResult: "boolean",
|
|
@@ -950,9 +971,10 @@ ${extra}
|
|
|
950
971
|
requiresReasoningContentOnAssistantMessages: "boolean",
|
|
951
972
|
thinkingFormat: [
|
|
952
973
|
"openai",
|
|
953
|
-
"openrouter",
|
|
954
974
|
"deepseek",
|
|
975
|
+
"openrouter",
|
|
955
976
|
"together",
|
|
977
|
+
"baseten",
|
|
956
978
|
"zai",
|
|
957
979
|
"qwen",
|
|
958
980
|
"chat-template",
|
|
@@ -961,44 +983,25 @@ ${extra}
|
|
|
961
983
|
"ant-ling"
|
|
962
984
|
],
|
|
963
985
|
chatTemplateKwargs: "object",
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
zaiToolStream: "boolean",
|
|
967
|
-
supportsOpenAIGrammarTools: "boolean",
|
|
986
|
+
chatTemplateArgs: "object",
|
|
987
|
+
supportsThinkingTokenBudget: "boolean",
|
|
968
988
|
supportsStrictMode: "boolean",
|
|
969
989
|
cacheControlFormat: ["anthropic"],
|
|
970
|
-
sendSessionAffinityHeaders: "boolean",
|
|
971
|
-
deferredToolsMode: ["kimi"],
|
|
972
|
-
sessionAffinityFormat: [
|
|
973
|
-
"openai",
|
|
974
|
-
"openai-nosession",
|
|
975
|
-
"openrouter"
|
|
976
|
-
],
|
|
977
990
|
supportsLongCacheRetention: "boolean"
|
|
978
991
|
},
|
|
979
992
|
"openai-responses": {
|
|
980
993
|
supportsDeveloperRole: "boolean",
|
|
981
|
-
sessionAffinityFormat: [
|
|
982
|
-
"openai",
|
|
983
|
-
"openai-nosession",
|
|
984
|
-
"openrouter"
|
|
985
|
-
],
|
|
986
|
-
supportsLongCacheRetention: "boolean",
|
|
987
994
|
supportsStrictMode: "boolean",
|
|
988
|
-
|
|
989
|
-
supportsToolSearch: "boolean",
|
|
990
|
-
supportsExplicitPromptCacheMode: "boolean"
|
|
995
|
+
supportsLongCacheRetention: "boolean"
|
|
991
996
|
},
|
|
992
997
|
"anthropic-messages": {
|
|
993
998
|
supportsEagerToolInputStreaming: "boolean",
|
|
994
999
|
supportsLongCacheRetention: "boolean",
|
|
995
|
-
sendSessionAffinityHeaders: "boolean",
|
|
996
1000
|
supportsCacheControlOnTools: "boolean",
|
|
997
1001
|
supportsTemperature: "boolean",
|
|
998
1002
|
forceAdaptiveThinking: "boolean",
|
|
999
1003
|
allowEmptySignature: "boolean",
|
|
1000
|
-
supportsStrictTools: "boolean"
|
|
1001
|
-
supportsToolReferences: "boolean"
|
|
1004
|
+
supportsStrictTools: "boolean"
|
|
1002
1005
|
}
|
|
1003
1006
|
};
|
|
1004
1007
|
/** 某协议的全部合法 compat 键(与服务端 compatFieldsOf 一致)。 */
|
|
@@ -1721,7 +1724,7 @@ ${extra}
|
|
|
1721
1724
|
/**
|
|
1722
1725
|
* 「LLM 路由」配置卡片:注册进 settings.plugin.item 插槽(官方插件配置页)。
|
|
1723
1726
|
* 顶部:enabled / catalogUrl / catalogRefreshHours / 只读状态行(kitSource、
|
|
1724
|
-
* modelsDevStatus,来自模型目录端点)+ 保存(settings.
|
|
1727
|
+
* modelsDevStatus,来自模型目录端点)+ 保存(settings.update 全量深合并)与
|
|
1725
1728
|
* 错误/成功提示;下方为 providers 路由列表(新增/删除/字段编辑/compat/模型
|
|
1726
1729
|
* 目录,见 views/)。外壳与基础控件走 @dsh-plus/shared/client 套件。
|
|
1727
1730
|
* @module llm-pi/client/card
|
|
@@ -1807,12 +1810,7 @@ ${extra}
|
|
|
1807
1810
|
const onSave = () => {
|
|
1808
1811
|
setSaving(true);
|
|
1809
1812
|
const revision = scope.getSnapshot().revision;
|
|
1810
|
-
api.
|
|
1811
|
-
ns: SETTINGS_NS,
|
|
1812
|
-
section: toPatch(draft),
|
|
1813
|
-
...revision !== void 0 ? { expectedRevision: revision } : {}
|
|
1814
|
-
}).then(async (response) => {
|
|
1815
|
-
if (!response.result.ok) throw new Error(response.result.error?.message ?? t("saveFailed"));
|
|
1813
|
+
api.update(toPatch(draft), revision).then(async () => {
|
|
1816
1814
|
await scope.load();
|
|
1817
1815
|
const next = scope.getSnapshot().value;
|
|
1818
1816
|
if (next !== void 0) setDraft(draftFromValue(next));
|
|
@@ -2218,8 +2216,8 @@ ${extra}
|
|
|
2218
2216
|
const inject = [
|
|
2219
2217
|
"slots",
|
|
2220
2218
|
"locale",
|
|
2221
|
-
"
|
|
2222
|
-
"remote"
|
|
2219
|
+
"remote",
|
|
2220
|
+
"remote.settings"
|
|
2223
2221
|
];
|
|
2224
2222
|
function apply(ctx) {
|
|
2225
2223
|
const c = ctx;
|
|
@@ -2231,8 +2229,8 @@ ${extra}
|
|
|
2231
2229
|
zh,
|
|
2232
2230
|
en
|
|
2233
2231
|
}), "llm-pi: locale");
|
|
2234
|
-
const
|
|
2235
|
-
const
|
|
2232
|
+
const scope = createSettingsScope(c, SETTINGS_NS, "llm-pi: settings scope");
|
|
2233
|
+
const api = createNamespaceApi(c.get("remote").settings, SETTINGS_NS);
|
|
2236
2234
|
c.slots.inject("settings.plugin.item", () => c.slots.register({
|
|
2237
2235
|
name: "settings.plugin.item",
|
|
2238
2236
|
key: SETTINGS_NS,
|
package/lib/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import z from "@deepseek-ai/schemastery";
|
|
|
2
2
|
import { Context } from "@deepseek-ai/cordis";
|
|
3
3
|
//#region src/config.d.ts
|
|
4
4
|
/** settings 命名空间;webui 配置卡片与插件运行期读取同一份(字面量见 ./ns.ts)。 */
|
|
5
|
-
declare const SETTINGS_NS:
|
|
5
|
+
declare const SETTINGS_NS: Branded<"SettingsNamespace">;
|
|
6
6
|
/** 本插件可为手写 route 提供的协议实现(与官方 PROTOCOLS 表一致)。 */
|
|
7
7
|
declare const PROTOCOL_IDS: readonly ["openai-completions", "openai-responses", "anthropic-messages"];
|
|
8
8
|
type ProtocolId = (typeof PROTOCOL_IDS)[number];
|
|
@@ -28,7 +28,6 @@ interface ModelEntryConfig {
|
|
|
28
28
|
/** 以下仅 adapter: deepseek 的 route 有效(官方 llm-deepseek 目录字段)。 */
|
|
29
29
|
imagePixelBudget?: number;
|
|
30
30
|
imageMaxBytes?: number;
|
|
31
|
-
imageDetail?: 'auto' | 'low';
|
|
32
31
|
}
|
|
33
32
|
/** 单个 provider route 配置(providers 字典的值)。 */
|
|
34
33
|
interface ProviderProfileConfig {
|
|
@@ -56,6 +55,8 @@ interface ProviderProfileConfig {
|
|
|
56
55
|
websocketConnectTimeoutMs?: number;
|
|
57
56
|
streamIdleTimeoutMs?: number;
|
|
58
57
|
maxRequestImageBytes?: number;
|
|
58
|
+
requestImagePixelBudget?: number;
|
|
59
|
+
requestImageMaxBytes?: number;
|
|
59
60
|
retryPolicy?: unknown;
|
|
60
61
|
models?: ModelEntryConfig[];
|
|
61
62
|
/** 以下仅 adapter: deepseek 的 route 有效(透传官方 llm-deepseek 同名策略)。 */
|