@dsh-plus/llm-pi 0.1.26 → 0.1.28

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
@@ -168,7 +168,10 @@ window.__ModuleLoader__.load({
168
168
  confirm: "Confirm",
169
169
  cancel: "Cancel"
170
170
  };
171
- /** own 覆盖同键合并(返回新对象,入参不可变)。 */
171
+ /**
172
+ * own 覆盖同键合并(返回新对象,入参不可变)。
173
+ * 返回类型保留两侧键集合,调用方据此派生 DictKey。
174
+ */
172
175
  function mergeDict(base, own) {
173
176
  return {
174
177
  ...base,
@@ -396,6 +399,73 @@ ${extra}
396
399
  }));
397
400
  }
398
401
  //#endregion
402
+ //#region src/client/constants.ts
403
+ /**
404
+ * 浏览器半内联常量:与服务端 packages/llm-pi/src/config.ts、compat.ts 逐字对齐。
405
+ * 浏览器半不能 import 服务端模块(tsdown 只打包 client 侧入口),
406
+ * 改动服务端这些常量时必须同步本文件。
407
+ * @module llm-pi/client/constants
408
+ */
409
+ /** 协议枚举(来源:config.ts PROTOCOL_IDS)。 */
410
+ const PROTOCOL_IDS = [
411
+ "openai-completions",
412
+ "openai-responses",
413
+ "anthropic-messages"
414
+ ];
415
+ /** thinking 档位(来源:config.ts THINKING_LEVELS)。 */
416
+ const THINKING_LEVELS = [
417
+ "off",
418
+ "minimal",
419
+ "low",
420
+ "medium",
421
+ "high",
422
+ "xhigh",
423
+ "max"
424
+ ];
425
+ /** 请求模态(来源:config.ts MODALITIES)。 */
426
+ const MODALITIES = ["text", "image"];
427
+ /** cacheRetention 枚举(来源:config.ts providerProfile.cacheRetention)。 */
428
+ const CACHE_RETENTION_OPTIONS = [
429
+ "none",
430
+ "short",
431
+ "long"
432
+ ];
433
+ /** transport 枚举(来源:config.ts providerProfile.transport)。 */
434
+ const TRANSPORT_OPTIONS = [
435
+ "sse",
436
+ "websocket",
437
+ "websocket-cached",
438
+ "auto"
439
+ ];
440
+ /** thinkingBudgets 档位键(来源:config.ts thinkingBudgets)。 */
441
+ const BUDGET_KEYS = [
442
+ "minimal",
443
+ "low",
444
+ "medium",
445
+ "high"
446
+ ];
447
+ /**
448
+ * 逐协议 compat 字段表:**服务端推导结果经 /catalog 下发**,浏览器半不再手抄
449
+ * (手抄遗漏官方新增字段 = UI 不渲染 + 保存被后端拒绝;见 compat-gates.ts)。
450
+ * 未拿到服务端表时用 EMPTY(UI 只渲染提示行),不放内置副本兜底——宁可少画
451
+ * 控件,也不给出可能与官方不符的字段集。
452
+ */
453
+ let compatTable = {};
454
+ /** 安装服务端下发的字段表(card 挂载/刷新目录时调用)。 */
455
+ function installCompatFields(table) {
456
+ compatTable = table;
457
+ }
458
+ /** 某协议的全部合法 compat 键(与服务端 compatFieldsOf 一致)。 */
459
+ function compatFieldsOf(api) {
460
+ return Object.keys(compatTable[api] ?? {});
461
+ }
462
+ /** 某协议某字段的取值约束(与服务端 compatFieldSpec 一致)。 */
463
+ function compatFieldSpec(api, field) {
464
+ return compatTable[api]?.[field];
465
+ }
466
+ /** api 未设置时的渲染回退组(最常见的协议;保存仍由后端按实际协议校验)。 */
467
+ const COMPAT_FALLBACK_API = "openai-completions";
468
+ //#endregion
399
469
  //#region src/client/draft.ts
400
470
  function numToText(value) {
401
471
  return value === void 0 ? "" : String(value);
@@ -734,6 +804,53 @@ ${extra}
734
804
  ]
735
805
  });
736
806
  }
807
+ /**
808
+ * 整数字段:compat 的数值型开关(如 vllmPriority,官方 z.number().step(1))。
809
+ * 本地保留文本态(与 JsonField 同款 epoch 播种),仅在解析为整数时回写草稿——
810
+ * 小数/非数字显示错误且不提交,与服务端 checkValue 的整数语义一致
811
+ * (后端仍做最终校验)。
812
+ */
813
+ function IntegerField(props) {
814
+ const [text, setText] = (0, react.useState)(() => props.value === void 0 ? "" : String(props.value));
815
+ (0, react.useEffect)(() => {
816
+ setText(props.value === void 0 ? "" : String(props.value));
817
+ }, [props.epoch]);
818
+ const trimmed = text.trim();
819
+ const parsed = trimmed === "" ? void 0 : Number(trimmed);
820
+ const ok = trimmed === "" || parsed !== void 0 && Number.isInteger(parsed);
821
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
822
+ className: `lpc-field${props.wide === true ? " lpc-wide" : ""}`,
823
+ children: [
824
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
825
+ className: "lpc-head",
826
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
827
+ className: "lpc-label",
828
+ htmlFor: props.id,
829
+ children: props.label
830
+ })
831
+ }),
832
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
833
+ id: props.id,
834
+ className: `lpc-input${ok ? "" : " lpc-inputInvalid"}`,
835
+ type: "text",
836
+ inputMode: "numeric",
837
+ "aria-invalid": ok ? void 0 : true,
838
+ value: text,
839
+ disabled: props.disabled === true,
840
+ onChange: (event) => {
841
+ const next = event.target.value;
842
+ setText(next);
843
+ const value = next.trim() === "" ? void 0 : Number(next.trim());
844
+ props.onEdit(value !== void 0 && Number.isInteger(value) ? value : void 0);
845
+ }
846
+ }),
847
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
848
+ className: ok ? "lpc-hint" : "lpc-invalid",
849
+ children: ok ? props.hint ?? "" : props.invalidLabel
850
+ })
851
+ ]
852
+ });
853
+ }
737
854
  function SelectField(props) {
738
855
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
739
856
  className: `lpc-field${props.wide === true ? " lpc-wide" : ""}`,
@@ -891,114 +1008,6 @@ ${extra}
891
1008
  });
892
1009
  }
893
1010
  //#endregion
894
- //#region src/client/constants.ts
895
- /**
896
- * 浏览器半内联常量:与服务端 packages/llm-pi/src/config.ts、compat.ts 逐字对齐。
897
- * 浏览器半不能 import 服务端模块(tsdown 只打包 client 侧入口),
898
- * 改动服务端这些常量时必须同步本文件。
899
- * @module llm-pi/client/constants
900
- */
901
- /** 协议枚举(来源:config.ts PROTOCOL_IDS)。 */
902
- const PROTOCOL_IDS = [
903
- "openai-completions",
904
- "openai-responses",
905
- "anthropic-messages"
906
- ];
907
- /** thinking 档位(来源:config.ts THINKING_LEVELS)。 */
908
- const THINKING_LEVELS = [
909
- "off",
910
- "minimal",
911
- "low",
912
- "medium",
913
- "high",
914
- "xhigh",
915
- "max"
916
- ];
917
- /** 请求模态(来源:config.ts MODALITIES)。 */
918
- const MODALITIES = ["text", "image"];
919
- /** cacheRetention 枚举(来源:config.ts providerProfile.cacheRetention)。 */
920
- const CACHE_RETENTION_OPTIONS = [
921
- "none",
922
- "short",
923
- "long"
924
- ];
925
- /** transport 枚举(来源:config.ts providerProfile.transport)。 */
926
- const TRANSPORT_OPTIONS = [
927
- "sse",
928
- "websocket",
929
- "websocket-cached",
930
- "auto"
931
- ];
932
- /** thinkingBudgets 档位键(来源:config.ts thinkingBudgets)。 */
933
- const BUDGET_KEYS = [
934
- "minimal",
935
- "low",
936
- "medium",
937
- "high"
938
- ];
939
- /**
940
- * 逐协议 compat 字段表(来源:compat.ts,逐字段镜像官方 catalog.ts COMPAT_GATES)。
941
- * 只列 offer 字段(withhold 字段官方写时拒绝,UI 不提供);取值约束对齐官方
942
- * config.ts compatProfile schema。
943
- */
944
- const COMPAT_FIELDS = {
945
- "openai-completions": {
946
- supportsStore: "boolean",
947
- supportsDeveloperRole: "boolean",
948
- supportsReasoningEffort: "boolean",
949
- supportsUsageInStreaming: "boolean",
950
- supportsFinishReason: "boolean",
951
- maxTokensField: ["max_completion_tokens", "max_tokens"],
952
- requiresToolResultName: "boolean",
953
- requiresAssistantAfterToolResult: "boolean",
954
- requiresThinkingAsText: "boolean",
955
- requiresReasoningContentOnAssistantMessages: "boolean",
956
- thinkingFormat: [
957
- "openai",
958
- "deepseek",
959
- "openrouter",
960
- "together",
961
- "baseten",
962
- "zai",
963
- "qwen",
964
- "chat-template",
965
- "qwen-chat-template",
966
- "string-thinking",
967
- "ant-ling"
968
- ],
969
- chatTemplateKwargs: "object",
970
- chatTemplateArgs: "object",
971
- supportsThinkingTokenBudget: "boolean",
972
- supportsStrictMode: "boolean",
973
- cacheControlFormat: ["anthropic"],
974
- supportsLongCacheRetention: "boolean"
975
- },
976
- "openai-responses": {
977
- supportsDeveloperRole: "boolean",
978
- supportsStrictMode: "boolean",
979
- supportsLongCacheRetention: "boolean"
980
- },
981
- "anthropic-messages": {
982
- supportsEagerToolInputStreaming: "boolean",
983
- supportsLongCacheRetention: "boolean",
984
- supportsCacheControlOnTools: "boolean",
985
- supportsTemperature: "boolean",
986
- forceAdaptiveThinking: "boolean",
987
- allowEmptySignature: "boolean",
988
- supportsStrictTools: "boolean"
989
- }
990
- };
991
- /** 某协议的全部合法 compat 键(与服务端 compatFieldsOf 一致)。 */
992
- function compatFieldsOf(api) {
993
- return Object.keys(COMPAT_FIELDS[api] ?? {});
994
- }
995
- /** 某协议某字段的取值约束(与服务端 compatFieldSpec 一致)。 */
996
- function compatFieldSpec(api, field) {
997
- return COMPAT_FIELDS[api]?.[field];
998
- }
999
- /** api 未设置时的渲染回退组(最常见的协议;保存仍由后端按实际协议校验)。 */
1000
- const COMPAT_FALLBACK_API = "openai-completions";
1001
- //#endregion
1002
1011
  //#region src/client/views/compat.tsx
1003
1012
  /** api 变更后裁剪 compat:只保留新渲染组的字段,避免保存时被后端拒绝。 */
1004
1013
  function pruneCompatForApi(compat, api) {
@@ -1052,6 +1061,15 @@ ${extra}
1052
1061
  invalidText: props.t("invalidJson"),
1053
1062
  onEdit: (value) => setField(field, value)
1054
1063
  }, field);
1064
+ if (spec === "integer" || spec === "number") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IntegerField, {
1065
+ id: `${props.idPrefix}-${field}`,
1066
+ label: field,
1067
+ value: props.compat[field],
1068
+ epoch: props.epoch,
1069
+ invalidLabel: props.t("invalidInteger"),
1070
+ disabled: props.disabled === true,
1071
+ onEdit: (value) => setField(field, value)
1072
+ }, field);
1055
1073
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SelectField, {
1056
1074
  id: `${props.idPrefix}-${field}`,
1057
1075
  label: field,
@@ -1742,6 +1760,7 @@ ${extra}
1742
1760
  if (!alive) return;
1743
1761
  setKitSource(result.kitSource ?? null);
1744
1762
  setModelsDevStatus(result.status ?? null);
1763
+ if (result.compat !== void 0) installCompatFields(result.compat.fields);
1745
1764
  }).catch(() => {});
1746
1765
  return () => {
1747
1766
  alive = false;
@@ -2023,6 +2042,7 @@ ${extra}
2023
2042
  retryPolicy: "重试策略(JSON)",
2024
2043
  retryPolicyHint: "dsh-llm RetryPolicy 形状;非法 JSON 不会提交。",
2025
2044
  invalidJson: "JSON 格式错误(该字段不会提交)。",
2045
+ invalidInteger: "必须是整数(该字段不会提交)。",
2026
2046
  compatGroup: "Compat 覆盖",
2027
2047
  compatApiHint: "api 未设置时暂按 openai-completions 字段组渲染;保存时后端按实际协议校验。",
2028
2048
  compatUnset: "未设置",
@@ -2103,6 +2123,7 @@ ${extra}
2103
2123
  retryPolicy: "Retry policy (JSON)",
2104
2124
  retryPolicyHint: "dsh-llm RetryPolicy shape; invalid JSON is not submitted.",
2105
2125
  invalidJson: "Invalid JSON (this field will not be submitted).",
2126
+ invalidInteger: "Must be an integer (this field will not be submitted).",
2106
2127
  compatGroup: "Compat overrides",
2107
2128
  compatApiHint: "When api is unset, fields render per openai-completions; the backend validates per the effective protocol.",
2108
2129
  compatUnset: "Unset",
package/lib/index.d.ts CHANGED
@@ -4,13 +4,13 @@ import { Context } from "@deepseek-ai/cordis";
4
4
  /** settings 命名空间(字面量即合法命名空间,0.1.2-alpha.2 起编译期校验;webui 配置卡片与插件运行期读取同一份)。 */
5
5
  declare const SETTINGS_NS = "dsh-plus-llm-pi";
6
6
  /** 本插件可为手写 route 提供的协议实现(与官方 PROTOCOLS 表一致)。 */
7
- declare const PROTOCOL_IDS: readonly ["openai-completions", "openai-responses", "anthropic-messages"];
7
+ declare const PROTOCOL_IDS: readonly ['openai-completions', 'openai-responses', 'anthropic-messages'];
8
8
  type ProtocolId = (typeof PROTOCOL_IDS)[number];
9
9
  /** pi-ai 思考档位,升级序。 */
10
- declare const THINKING_LEVELS: readonly ["off", "minimal", "low", "medium", "high", "xhigh", "max"];
11
- declare const MODALITIES: readonly ["text", "image"];
10
+ declare const THINKING_LEVELS: readonly ['off', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max'];
11
+ declare const MODALITIES: readonly ['text', 'image'];
12
12
  /** 路由适配器种类:pi = PiAiAdapter(默认);deepseek = 官方 DeepSeekAdapter(文件通道)。 */
13
- declare const ADAPTER_KINDS: readonly ["pi", "deepseek"];
13
+ declare const ADAPTER_KINDS: readonly ['pi', 'deepseek'];
14
14
  type AdapterKind = (typeof ADAPTER_KINDS)[number];
15
15
  type ThinkingLevel = (typeof THINKING_LEVELS)[number];
16
16
  type Modality = (typeof MODALITIES)[number];
@@ -35,6 +35,13 @@ interface ProviderProfileConfig {
35
35
  extends?: string;
36
36
  displayName?: string;
37
37
  api?: ProtocolId;
38
+ /**
39
+ * 端点;缺省继承 extends 源 provider 的端点。
40
+ *
41
+ * 不并 `| undefined`:schemastery 的输入契约用 null 表示「显式置空」,省略即未设置;
42
+ * 消费方按 `baseURL ?? 默认值` 处理。并上 undefined 会与 ObjectS 的 `string | null`
43
+ * 冲突(exactOptionalPropertyTypes 下二者不可互赋)。
44
+ */
38
45
  baseURL?: string;
39
46
  apiKeyEnv?: string;
40
47
  headers?: Record<string, string>;
@@ -89,7 +96,7 @@ declare const Config: z<LlmPiConfigInput, LlmPiConfig>;
89
96
  //#endregion
90
97
  //#region src/index.d.ts
91
98
  declare const name = "dsh-plus-llm-pi";
92
- declare const inject: readonly ["credentials", "llm"];
99
+ declare const inject: readonly ['credentials', 'llm'];
93
100
  declare function apply(ctx: Context, config: LlmPiConfig): Promise<void>;
94
101
  //#endregion
95
102
  export { Config, type LlmPiConfig, type ModelEntryConfig, type ProviderProfileConfig, SETTINGS_NS, apply, inject, name };