@dsh-plus/llm-pi 0.1.13 → 0.1.14

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 CHANGED
@@ -196,14 +196,15 @@ window.__ModuleLoader__.load({
196
196
  //#endregion
197
197
  //#region ../shared/src/client/scope.ts
198
198
  /**
199
- * api 直连实现的命名空间 scope(官方配置页 tab 同款模式)。
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 createApiScope(api, ns, c, label) {
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 response;
222
+ let view;
222
223
  try {
223
- response = await api.describe({});
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 || !response.result.ok) return;
228
- const writable = response.result.value?.writable ?? false;
229
- const view = response.result.value?.namespaces.find((candidate) => candidate.ns === ns);
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: view.value,
242
- revision: view.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 = [c.get("remote").$on("settings/document-updated", refresh), c.on("connection/reset", () => {
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
- * 契约:dsh rc7 起该槽位按「卡片编辑的 settings 命名空间」作 key 分发,
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
- /** 逐协议 compat 字段表(来源:compat.ts FIELDS_BY_PROTOCOL)。 */
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
- openRouterRouting: "object",
965
- vercelGatewayRouting: "object",
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
- supportsOpenAIGrammarTools: "boolean",
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.replace 全量)与
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.replace({
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
- "connection",
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 api = c.get("connection").api.settings;
2235
- const scope = createApiScope(api, SETTINGS_NS, c, "llm-pi: settings scope");
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: import("@deepseek-ai/dsh-settings").SettingsNamespace;
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 同名策略)。 */