@dsh-plus/llm-pi 0.2.0 → 0.2.2

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.
@@ -19,13 +19,15 @@
19
19
  * 模型条目字段集同样现场推导(official-surface.ts)。生效版本只用于状态行显示,
20
20
  * 超出已验证区间也只是提示(kit-meta.ts),永不阻断。
21
21
  *
22
- * 0.1.2-alpha 线的新面(0.1.2-alpha.2 复核包根仍未导出、仅 src 子路径有):
23
- * - resolveProfiles(config.ts):官方解析链,dev 布局树可经 src 子路径复用;
22
+ * 仅 src 子路径导出、包根不导出的两块面:
23
+ * - resolveProfiles(config.ts):官方解析链,源码布局可经 src 子路径复用;
24
24
  * - credentialStoreFrom/authContextFrom(auth.ts):PiAiAdapter 必需 auth 注入。
25
25
  * npm 发布形态(lib/index.js 单 bundle + 无 src/)两者都拿不到:dsh 树优先
26
26
  * 探测 src/*(含 lib/* 候选),未命中时 resolveProfiles 走插件等价实现
27
- * (profiles.ts,门控表对齐官方 catalog.ts)、auth 走内联等价实现
28
- * (auth-inline.ts,recordKeyFor 自包根导出同源注入)——形状自检兜底。
27
+ * (profiles.ts,语义对齐官方 config.ts:resolveProfiles)、auth 走内联等价实现
28
+ * (auth-inline.ts,recordKeyFor 自包根导出同源注入、记录作用域由它现场推导)。
29
+ * 这是**打包形态的恒定事实而非降级**,故按 info 档记入诊断(missingSourceNote),
30
+ * 免得淹没同面板里真正的降级;等价实现由形状自检与单测兜底。
29
31
  * @module llm-pi/resolve-dsh
30
32
  */
31
33
  import { existsSync, readFileSync, realpathSync } from 'node:fs'
@@ -76,7 +78,7 @@ import { type ResolverDeps, resolveProfilesFallback } from './profiles.ts'
76
78
 
77
79
  /**
78
80
  * deepseek 适配器模块表面(可选):dsh-llm-deepseek 的官方 DeepSeekAdapter
79
- * 与目录解析器 + 匿名用户 id。缺失(旧版 dsh 树或形状漂移)不拖垮核心
81
+ * 与目录解析器 + 匿名用户 id。缺失(形状漂移)不拖垮核心
80
82
  * 套件——deepseek 类 route 在构建期以明确错误拒绝,pi 路由不受影响。
81
83
  * 与核心套件强制同源(杜绝跨源模块混用:brand/LlmError 恒等性敏感)。
82
84
  */
@@ -106,6 +108,43 @@ export interface AuthHelpers {
106
108
  authContextFrom(ctx: Context): AuthContext
107
109
  }
108
110
 
111
+ /**
112
+ * 套件诊断条目,配置页按档分块展示:
113
+ * - `info`:当前打包形态下的**恒定事实**,不是缺陷——官方 `src/` 只经子路径导出、
114
+ * npm 发布形态不携带,本插件因此走等价实现(见 {@link missingSourceNote});
115
+ * - `degradation`:推导/加载真的降级了(回退快照、协议缺失、树不可用等)。
116
+ * 分档是为了不让恒定事实淹没真实降级。
117
+ */
118
+ export interface KitDiagnostic {
119
+ level: 'info' | 'degradation'
120
+ message: string
121
+ }
122
+
123
+ /** 生成一条降级诊断(推导失败 / 加载回退)。 */
124
+ export function degradation(message: string): KitDiagnostic {
125
+ return { level: 'degradation', message }
126
+ }
127
+
128
+ /**
129
+ * 官方 `src/` 子路径未随 npm 发布携带时的**形态说明**(info 档)。
130
+ *
131
+ * 官方 `resolveProfiles`(src/config.ts)与认证助手(src/auth.ts)只在子路径导出、
132
+ * 包根不导出,而发布清单只含 `lib/index.js` + `lib/types/**`——任何 npm 安装形态都
133
+ * 拿不到,故这两块常走插件等价实现。此处逐面列出实际走等价实现的部分,并点明
134
+ * **仍取自官方现场推导**的部分(compat 门控 / 协议 / 模型字段集),避免被读成
135
+ * "自动跟随失败"。
136
+ * @param surfaces 走等价实现的官方面名称(如 `profile 解析`)。
137
+ */
138
+ export function missingSourceNote(surfaces: readonly string[]): KitDiagnostic {
139
+ return {
140
+ level: 'info',
141
+ message:
142
+ '官方 @deepseek-ai/dsh-llm-pi-ai 只经 src/ 子路径导出、npm 发布形态不携带 src/:' +
143
+ `${surfaces.join('、')}使用插件等价实现;` +
144
+ 'compat 门控 / 协议集合 / 模型条目字段集仍取自官方安装副本现场推导',
145
+ }
146
+ }
147
+
109
148
  /** 插件运行期所需的全部上游模块表面(单一来源,内部一致)。 */
110
149
  export interface DshKit {
111
150
  /** 解析来源:dsh 安装树 / 插件 vendored 兜底副本。 */
@@ -140,16 +179,22 @@ export interface DshKit {
140
179
  getBuiltinProviders: typeof vendoredCatalog.getBuiltinProviders
141
180
  getBuiltinModels: typeof vendoredCatalog.getBuiltinModels
142
181
  /**
143
- * profile 解析链:dsh 树 dev 布局(src/config.ts 存在)时为官方
144
- * resolveProfiles;npm 形态(无 src)与 vendored 兜底时为插件等价实现。
182
+ * profile 解析链:官方源码布局(`src/config.ts` 存在,如上游工作区)时为官方
183
+ * resolveProfiles;npm 发布形态(不携带 src/,包根也不导出)与 vendored 兜底时
184
+ * 为插件等价实现——该形态事实按 info 档记入诊断(见 {@link missingSourceNote})。
145
185
  */
146
186
  resolveProfiles: ResolveProfiles
147
187
  /**
148
- * PiAiAdapter 必需 auth 注入:dsh 树 dev 布局(src/auth.ts 存在)时为官方
188
+ * PiAiAdapter 必需 auth 注入:官方源码布局(`src/auth.ts` 存在)时为官方
149
189
  * credentialStoreFrom/authContextFrom;其余形态为内联等价实现
150
- * (auth-inline.ts,与官方同语义:记录作用域 llm-pi-ai + recordKeyFor)。
190
+ * (auth-inline.ts,记录键与作用域均取自官方 recordKeyFor)。
151
191
  */
152
192
  auth: AuthHelpers
193
+ /**
194
+ * 官方凭据记录键格式器(包根导出)。auth 助手按它对齐记录键,并**现场推导**
195
+ * 记录作用域(不再手抄官方常量,见 auth-inline.ts);缺失即形状不兼容。
196
+ */
197
+ recordKeyFor: (providerId: string) => CredentialKey
153
198
  /** 附件引用 → 当前模型工具执行世界的只读路径桥(官方 dsh-llm 导出)。 */
154
199
  resolveImageAttachmentAccess: typeof DshLlm.resolveImageAttachmentAccess
155
200
  /** deepseek 文件通道路由所需模块;同源自检失败时为 undefined(见 diagnostics)。 */
@@ -161,8 +206,8 @@ function assertKitShape(kit: DshKit, origin: string): void {
161
206
  const problems: string[] = []
162
207
  if (typeof kit.PiAiAdapter !== 'function') problems.push('PiAiAdapter 不是类')
163
208
  else {
164
- // 0.1.2-alpha.2 的 LlmAdapter 抽象面:prepareCall/providerRetryPolicy 为
165
- // master 适配器必需 override;models.getModels/getModel 语义未变
209
+ // LlmAdapter 抽象面:prepareCall/providerRetryPolicy 为适配器必需 override;
210
+ // models.getModels/getModel 语义
166
211
  // (pi-ai 0.84.2 Models.getModel(provider,id)/getModels(provider),
167
212
  // 由同源 adapter 内部消费,本插件不直调)。
168
213
  for (const method of [
@@ -207,6 +252,7 @@ function assertKitShape(kit: DshKit, origin: string): void {
207
252
  ) {
208
253
  problems.push('auth 助手(credentialStoreFrom/authContextFrom)缺失')
209
254
  }
255
+ if (typeof kit.recordKeyFor !== 'function') problems.push('recordKeyFor 缺失')
210
256
  if (problems.length > 0) {
211
257
  throw new Error(`llm-pi: ${origin} 来源的运行时套件形状不兼容:${problems.join(';')}`)
212
258
  }
@@ -343,7 +389,7 @@ function piAiApiDir(root: string): string {
343
389
  /** 内置三元组的静态加载(协议推导失败或全部工厂加载失败时的兜底)。 */
344
390
  async function loadFallbackTreeFactories(
345
391
  root: string,
346
- diagnostics: string[],
392
+ diagnostics: KitDiagnostic[],
347
393
  ): Promise<Record<string, () => unknown>> {
348
394
  const dir = piAiApiDir(root)
349
395
  const out: Record<string, () => unknown> = {}
@@ -359,8 +405,10 @@ async function loadFallbackTreeFactories(
359
405
  }
360
406
  if (Object.keys(out).length < fallbackProtocols().length) {
361
407
  diagnostics.push(
362
- `pi-ai 协议兜底三元组未能全部加载(${Object.keys(out).join('/') || '空'});` +
363
- '请检查 dsh 安装树里 @earendil-works/pi-ai/dist/api 的形态',
408
+ degradation(
409
+ `pi-ai 协议兜底三元组未能全部加载(${Object.keys(out).join('/') || '空'});` +
410
+ '请检查 dsh 安装树里 @earendil-works/pi-ai/dist/api 的形态',
411
+ ),
364
412
  )
365
413
  }
366
414
  return out
@@ -373,7 +421,7 @@ async function loadFallbackTreeFactories(
373
421
  async function loadTreeProtocols(
374
422
  root: string,
375
423
  derived: string[],
376
- diagnostics: string[],
424
+ diagnostics: KitDiagnostic[],
377
425
  ): Promise<{ protocols: string[]; protocolFactories: Record<string, () => unknown> }> {
378
426
  const dir = piAiApiDir(root)
379
427
  const out: Record<string, () => unknown> = {}
@@ -381,27 +429,31 @@ async function loadTreeProtocols(
381
429
  const file = join(dir, `${api}.lazy.js`)
382
430
  if (!existsSync(file)) {
383
431
  diagnostics.push(
384
- `pi-ai 未提供协议 "${api}" 的惰性实现(缺 ${file});该协议不可用,其余协议不受影响`,
432
+ degradation(
433
+ `pi-ai 未提供协议 "${api}" 的惰性实现(缺 ${file});该协议不可用,其余协议不受影响`,
434
+ ),
385
435
  )
386
436
  continue
387
437
  }
388
438
  try {
389
439
  const factory = protocolFactoryOf((await import(pathToFileURL(file).href)) as never)
390
440
  if (factory === undefined) {
391
- diagnostics.push(`协议 "${api}" 的实现模块未导出唯一 *Api 工厂;该协议不可用`)
441
+ diagnostics.push(degradation(`协议 "${api}" 的实现模块未导出唯一 *Api 工厂;该协议不可用`))
392
442
  continue
393
443
  }
394
444
  out[api] = factory
395
445
  } catch (error) {
396
446
  diagnostics.push(
397
- `协议 "${api}" 的实现加载失败(${error instanceof Error ? error.message : String(error)});该协议不可用`,
447
+ degradation(
448
+ `协议 "${api}" 的实现加载失败(${error instanceof Error ? error.message : String(error)});该协议不可用`,
449
+ ),
398
450
  )
399
451
  }
400
452
  }
401
453
  if (Object.keys(out).length > 0) {
402
454
  return { protocols: derived.filter((api) => out[api] !== undefined), protocolFactories: out }
403
455
  }
404
- diagnostics.push('官方声明的协议一个都加载不到;回退内置三元组')
456
+ diagnostics.push(degradation('官方声明的协议一个都加载不到;回退内置三元组'))
405
457
  const fallback = await loadFallbackTreeFactories(root, diagnostics)
406
458
  return {
407
459
  protocols: fallbackProtocols().filter((api) => fallback[api] !== undefined),
@@ -465,7 +517,7 @@ function installOfficialSurface(options: {
465
517
  adapterModule: Record<string, unknown>
466
518
  catalogModule: Record<string, unknown>
467
519
  origin: string
468
- diagnostics: string[]
520
+ diagnostics: KitDiagnostic[]
469
521
  }): OfficialSurface {
470
522
  const { bundlePath, adapterModule, origin, diagnostics } = options
471
523
  const compatLabel = 'compat 门控表'
@@ -477,8 +529,10 @@ function installOfficialSurface(options: {
477
529
  // 快照模式下未知 compat 键**放行**(交给官方自身校验),只拦快照里明确的
478
530
  // withhold——表落后时"误拒官方新字段"比"多放一个键"严重得多。
479
531
  diagnostics.push(
480
- `${compatLabel}未能从官方 bundle 解析 COMPAT_GATES(${bundlePath});` +
481
- `使用内置快照(未知字段放行、withhold 仍拒绝;请检查 dsh-llm-pi-ai 打包形态)`,
532
+ degradation(
533
+ `${compatLabel}未能从官方 bundle 解析 COMPAT_GATES(${bundlePath});` +
534
+ `使用内置快照(未知字段放行、withhold 仍拒绝;请检查 dsh-llm-pi-ai 打包形态)`,
535
+ ),
482
536
  )
483
537
  installCompatTable(FALLBACK_TABLE)
484
538
  } else {
@@ -488,21 +542,27 @@ function installOfficialSurface(options: {
488
542
  }
489
543
  } catch (error) {
490
544
  const reason = error instanceof Error ? error.message : String(error)
491
- diagnostics.push(`${compatLabel}推导失败(${reason});使用内置快照(未知字段放行)`)
545
+ diagnostics.push(
546
+ degradation(`${compatLabel}推导失败(${reason});使用内置快照(未知字段放行)`),
547
+ )
492
548
  installCompatTable(FALLBACK_TABLE)
493
549
  }
494
550
 
495
551
  const derivedProtocols = deriveProtocols(adapterModule)
496
552
  if (derivedProtocols === undefined) {
497
553
  diagnostics.push(
498
- `${origin}:官方 supportedProtocols() 不可用;协议集合回退内置三元组 ${fallbackProtocols().join('/')}`,
554
+ degradation(
555
+ `${origin}:官方 supportedProtocols() 不可用;协议集合回退内置三元组 ${fallbackProtocols().join('/')}`,
556
+ ),
499
557
  )
500
558
  }
501
559
  const fields = deriveModelEntryFields(adapterModule)
502
560
  if (fields === undefined) {
503
561
  diagnostics.push(
504
- `${origin}:官方 Config schema 的模型条目字段集不可推导;` +
505
- `继承字段回退已知键 ${FALLBACK_MODEL_ENTRY_FIELDS.join('/')}(官方新增字段可能不被继承)`,
562
+ degradation(
563
+ `${origin}:官方 Config schema 的模型条目字段集不可推导;` +
564
+ `继承字段回退已知键 ${FALLBACK_MODEL_ENTRY_FIELDS.join('/')}(官方新增字段可能不被继承)`,
565
+ ),
506
566
  )
507
567
  }
508
568
  const generatedAt = catalogGeneratedAtOf(options.catalogModule)
@@ -570,6 +630,7 @@ function kitFromTree(options: {
570
630
  resolveImageAttachmentAccess: mods.llm[
571
631
  'resolveImageAttachmentAccess'
572
632
  ] as DshKit['resolveImageAttachmentAccess'],
633
+ recordKeyFor,
573
634
  }
574
635
  }
575
636
 
@@ -607,9 +668,9 @@ function vendoredProtocolFactories(): Record<string, () => unknown> {
607
668
  * npm 发布形态不携带 src/、lib 仅 index.js/invariant.js——resolveProfiles 与
608
669
  * auth 助手在此无条件走插件等价实现(内联,见文件头说明);compat 门控表则
609
670
  * 仍从 vendored 副本的 bundle + Config schema 现场推导(与 dsh 树同一推导链)。
610
- * @param diagnostics 可选诊断收集器(回退原因与逐项降级说明)。
671
+ * @param diagnostics 可选诊断收集器(回退原因、形态说明与逐项降级)。
611
672
  */
612
- export function loadVendoredKit(diagnostics: string[] = []): DshKit {
673
+ export function loadVendoredKit(diagnostics: KitDiagnostic[] = []): DshKit {
613
674
  const staticFactories = vendoredProtocolFactories()
614
675
  const surface = installOfficialSurface({
615
676
  bundlePath: vendoredAdapterBundlePath(),
@@ -658,9 +719,11 @@ export function loadVendoredKit(diagnostics: string[] = []): DshKit {
658
719
  authContextFrom: inlineAuthContextFrom,
659
720
  },
660
721
  resolveImageAttachmentAccess: vendoredLlm.resolveImageAttachmentAccess,
722
+ recordKeyFor: vendoredPiAiAdapter.recordKeyFor,
661
723
  ...(deepseek === undefined ? {} : { deepseek }),
662
724
  }
663
725
  assertKitShape(kit, 'vendored')
726
+ diagnostics.push(missingSourceNote(['profile 解析', '认证助手']))
664
727
  return kit
665
728
  }
666
729
 
@@ -689,14 +752,15 @@ export function dshTreeAnchor(
689
752
  /**
690
753
  * 解析运行时套件:优先 dsh 安装树(自动跟随上游),失败回退 vendored 副本;
691
754
  * 两者都过不了形状自检时抛错(调用方应记日志并放弃注册 route)。
692
- * 返回的 diagnostics 记录回退原因与逐项降级说明,供配置卡片与日志展示。
755
+ * 返回的 diagnostics 记录回退原因、打包形态说明(info)与逐项降级(degradation),
756
+ * 供配置卡片与日志分档展示。
693
757
  * @param installAnchor profile 的 dsh 安装锚点(`ctx.profileContext.installAnchor`)。
694
758
  */
695
759
  export async function resolveDshKit(installAnchor?: string | undefined): Promise<{
696
760
  kit: DshKit
697
- diagnostics: string[]
761
+ diagnostics: KitDiagnostic[]
698
762
  }> {
699
- const diagnostics: string[] = []
763
+ const diagnostics: KitDiagnostic[] = []
700
764
  const anchor = dshTreeAnchor(installAnchor)
701
765
  if (anchor !== undefined) {
702
766
  const treePkgDir = join(anchor, 'node_modules', '@deepseek-ai', 'dsh-llm-pi-ai')
@@ -729,39 +793,39 @@ export async function resolveDshKit(installAnchor?: string | undefined): Promise
729
793
  versions: collectTreeVersions(anchor),
730
794
  })
731
795
  assertKitShape(kit, 'dsh-tree')
732
- if (auth === undefined) {
733
- diagnostics.push(
734
- 'dsh 树不含 dsh-llm-pi-ai/src(npm 发布形态);认证助手使用插件内联等价实现',
735
- )
736
- }
737
- if (config === undefined) {
738
- diagnostics.push(
739
- 'dsh 树不含 dsh-llm-pi-ai/src(npm 发布形态);profile 解析使用插件等价实现(compat 门控对齐官方 catalog.ts)',
740
- )
741
- }
796
+ const missingSeams: string[] = []
797
+ if (config === undefined) missingSeams.push('profile 解析')
798
+ if (auth === undefined) missingSeams.push('认证助手')
799
+ if (missingSeams.length > 0) diagnostics.push(missingSourceNote(missingSeams))
742
800
  const tree = await importTreeDeepseek(anchor)
743
801
  if (tree.kit !== undefined) {
744
802
  return { kit: { ...kit, deepseek: tree.kit }, diagnostics }
745
803
  }
746
804
  diagnostics.push(
747
- `dsh 安装树的 dsh-llm-deepseek 不可用(${tree.problem ?? '未知原因'});` +
748
- 'adapter: deepseek 的 route 不可用,pi 路由不受影响',
805
+ degradation(
806
+ `dsh 安装树的 dsh-llm-deepseek 不可用(${tree.problem ?? '未知原因'});` +
807
+ 'adapter: deepseek 的 route 不可用,pi 路由不受影响',
808
+ ),
749
809
  )
750
810
  return { kit, diagnostics }
751
811
  } catch (error) {
752
812
  diagnostics.push(
753
- `dsh 安装树套件不可用(${anchor}):${error instanceof Error ? error.message : String(error)};回退 vendored 副本`,
813
+ degradation(
814
+ `dsh 安装树套件不可用(${anchor}):${error instanceof Error ? error.message : String(error)};回退 vendored 副本`,
815
+ ),
754
816
  )
755
817
  }
756
818
  } else {
757
819
  diagnostics.push(
758
- '未能从 profileContext.installAnchor / process.argv[1] 定位 dsh 安装树;回退 vendored 副本',
820
+ degradation(
821
+ '未能从 profileContext.installAnchor / process.argv[1] 定位 dsh 安装树;回退 vendored 副本',
822
+ ),
759
823
  )
760
824
  }
761
825
  const kit = loadVendoredKit(diagnostics)
762
826
  if (kit.deepseek === undefined) {
763
827
  diagnostics.push(
764
- 'vendored 副本的 dsh-llm-deepseek 形状不兼容;adapter: deepseek 的 route 不可用',
828
+ degradation('vendored 副本的 dsh-llm-deepseek 形状不兼容;adapter: deepseek 的 route 不可用'),
765
829
  )
766
830
  }
767
831
  return { kit, diagnostics }
package/src/service.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * 运行时主逻辑:注册/热更新/发现(逐点对齐官方 dsh-llm-pi-ai apply 的模式)。
3
3
  *
4
- * - profiles 回调按原始 config 对象 identity 备忘;配置变更经 0.1.7
5
- * volatile 原位提交(loader/volatile-update 换代快照)传播,下一请求生效
4
+ * - profiles 回调按原始 config 对象 identity 备忘;配置变更经 volatile 原位提交
5
+ * (loader/volatile-update 换代快照)传播,下一请求生效
6
6
  * (adapter 快照按 profiles identity 失效);
7
7
  * - route 集或注册时捕获的事实(displayName/retryPolicy)变化 → 原子的
8
8
  * handle.replace 重注册;写入被校验拒绝时保留旧注册(官方同款护栏);
@@ -47,7 +47,7 @@ import {
47
47
  } from './official-copy-writer.ts'
48
48
  import { assertServiceable, buildProfiles, isDraftRoute } from './profiles.ts'
49
49
  import { buildDeepseekRoutes, type ResolvedDeepseekRoute } from './profiles-deepseek.ts'
50
- import { type DshKit, resolveDshKit } from './resolve-dsh.ts'
50
+ import { type DshKit, degradation, type KitDiagnostic, resolveDshKit } from './resolve-dsh.ts'
51
51
 
52
52
  /** 配置页「运行期状态」所需的事实(纯 JSON,可直接进 HTTP 响应)。 */
53
53
  export interface LlmPiKitInfo {
@@ -71,8 +71,11 @@ export interface LlmPiKitInfo {
71
71
  compatSource: string
72
72
  /** 官方应急副本状态(路径/生成时间/覆盖 route/警告;error = 最近生成失败)。 */
73
73
  officialCopy: OfficialCopyStatus
74
- /** 回退与逐项降级诊断(有内容时界面显式展示)。 */
75
- diagnostics: string[]
74
+ /**
75
+ * 套件诊断(分档,界面分块展示):`info` = 打包形态说明(恒定事实、非缺陷),
76
+ * `degradation` = 回退与逐项降级。
77
+ */
78
+ diagnostics: KitDiagnostic[]
76
79
  }
77
80
 
78
81
  export interface LlmPiRuntime {
@@ -132,13 +135,16 @@ function makeResolveApiKey(ctx: Context, kit: DshKit) {
132
135
  }
133
136
  }
134
137
 
135
- /** 解析运行期套件并落启动日志(来源/生效版本/协议/逐项降级诊断)。 */
138
+ /** 解析运行期套件并落启动日志(来源/生效版本/协议/形态说明与逐项降级)。 */
136
139
  async function loadRuntimeKit(
137
140
  ctx: Context,
138
141
  logger: PluginLogger,
139
- ): Promise<{ kit: DshKit; diagnostics: string[] }> {
142
+ ): Promise<{ kit: DshKit; diagnostics: KitDiagnostic[] }> {
140
143
  const { kit, diagnostics } = await resolveDshKit(ctx.get('profileContext')?.installAnchor)
141
- for (const line of diagnostics) logger.warn(line)
144
+ for (const item of diagnostics) {
145
+ if (item.level === 'info') logger.info(item.message)
146
+ else logger.warn(item.message)
147
+ }
142
148
  logger.info(
143
149
  `运行时套件来源:${kit.source};pi-ai ${kit.versions.piAi ?? '?'} / ` +
144
150
  `dsh-llm-pi-ai ${kit.versions.piAiAdapter ?? '?'};协议 ${kit.protocols.join('/')}`,
@@ -201,8 +207,8 @@ function createAdapter(options: {
201
207
  profiles,
202
208
  resolveApiKey: makeResolveApiKey(ctx, kit),
203
209
  resolveAttachments: () => ctx.get('attachments'),
204
- // 0.1.2-alpha.2 必需(包根仍未导出官方 auth 助手):登录/OAuth 类 provider 与
205
- // pi-ai 自有凭据写入的落点。dsh 树 dev 布局(src/auth.ts 存在)时为官方助手,
210
+ // 官方 auth 助手只在 src 子路径导出:登录/OAuth 类 provider 与 pi-ai 自有
211
+ // 凭据写入的落点。dsh 树 dev 布局(src/auth.ts 存在)时为官方助手,
206
212
  // 其余形态为内联等价实现(resolve-dsh.ts 探测,见 auth-inline.ts)。
207
213
  auth: {
208
214
  credentials: kit.auth.credentialStoreFrom(ctx),
@@ -372,7 +378,7 @@ export async function startRuntime(
372
378
  ): Promise<LlmPiRuntime> {
373
379
  const logger = ctx.logger('llm-pi')
374
380
  // cordis 行级 config 可能未经 schema 解析(insert 行无 config 键时为原始空对象),
375
- // 在此统一规范化;0.1.7 loader 解析出的 volatile 活动字段形态直接透传
381
+ // 在此统一规范化;loader 解析出的 volatile 活动字段形态直接透传
376
382
  // (hasVolatileRefs 辨识——重复校验会把引用再包一层、破坏 loader 原位提交)。
377
383
  const fields: LlmPiConfigFields = hasVolatileRefs(rawConfig)
378
384
  ? (rawConfig as LlmPiConfigFields)
@@ -434,7 +440,7 @@ export async function startRuntime(
434
440
  ensureDirectory()
435
441
  void copyWriter.ensureOfficialCopy()
436
442
 
437
- // 0.1.7 替代 installSection(validate/setSource/onChange 三钩子):
443
+ // 替代 installSection(validate/setSource/onChange 三钩子):
438
444
  // - 活动引用原位提交 → volatile-update 触发快照换代与重注册(原 onChange 体);
439
445
  // - internal/config waterfall 承接写入校验(原 validate;官方 llm-pi-ai
440
446
  // 同款):configEditor.edit 落盘前先跑 waterfall,handler throw 即拒绝整笔写入。
@@ -479,8 +485,8 @@ export async function startRuntime(
479
485
  officialCopy: copy,
480
486
  diagnostics: [
481
487
  ...diagnostics,
482
- ...copy.warnings.map((warning) => `应急副本:${warning}`),
483
- ...(copy.error === undefined ? [] : [`应急副本:生成失败(${copy.error})`]),
488
+ ...copy.warnings.map((warning) => degradation(`应急副本:${warning}`)),
489
+ ...(copy.error === undefined ? [] : [degradation(`应急副本:生成失败(${copy.error})`)]),
484
490
  ],
485
491
  }
486
492
  }