dsh-data-domain-knowledge 0.1.0-alpha.1

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.
Files changed (231) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +360 -0
  3. package/cordis.patch.yml +410 -0
  4. package/eval/README.md +76 -0
  5. package/eval/evaluate-retrieval.mjs +121 -0
  6. package/eval/queries.example.jsonl +2 -0
  7. package/lib/client.js +111415 -0
  8. package/lib/types/config-schema.d.ts +35 -0
  9. package/lib/types/config-schema.d.ts.map +1 -0
  10. package/lib/types/config-schema.js +34 -0
  11. package/lib/types/config-schema.js.map +1 -0
  12. package/lib/types/convert/core-loader.d.ts +32 -0
  13. package/lib/types/convert/core-loader.d.ts.map +1 -0
  14. package/lib/types/convert/core-loader.js +60 -0
  15. package/lib/types/convert/core-loader.js.map +1 -0
  16. package/lib/types/convert/host.d.ts +88 -0
  17. package/lib/types/convert/host.d.ts.map +1 -0
  18. package/lib/types/convert/host.js +479 -0
  19. package/lib/types/convert/host.js.map +1 -0
  20. package/lib/types/convert/ingest.d.ts +125 -0
  21. package/lib/types/convert/ingest.d.ts.map +1 -0
  22. package/lib/types/convert/ingest.js +228 -0
  23. package/lib/types/convert/ingest.js.map +1 -0
  24. package/lib/types/convert/settings-schema.d.ts +18 -0
  25. package/lib/types/convert/settings-schema.d.ts.map +1 -0
  26. package/lib/types/convert/settings-schema.js +26 -0
  27. package/lib/types/convert/settings-schema.js.map +1 -0
  28. package/lib/types/convert/types.d.ts +46 -0
  29. package/lib/types/convert/types.d.ts.map +1 -0
  30. package/lib/types/convert/types.js +41 -0
  31. package/lib/types/convert/types.js.map +1 -0
  32. package/lib/types/diagnosis/cards.d.ts +71 -0
  33. package/lib/types/diagnosis/cards.d.ts.map +1 -0
  34. package/lib/types/diagnosis/cards.js +482 -0
  35. package/lib/types/diagnosis/cards.js.map +1 -0
  36. package/lib/types/diagnosis/problem-classes.d.ts +51 -0
  37. package/lib/types/diagnosis/problem-classes.d.ts.map +1 -0
  38. package/lib/types/diagnosis/problem-classes.js +66 -0
  39. package/lib/types/diagnosis/problem-classes.js.map +1 -0
  40. package/lib/types/diagnosis/schema.d.ts +65 -0
  41. package/lib/types/diagnosis/schema.d.ts.map +1 -0
  42. package/lib/types/diagnosis/schema.js +208 -0
  43. package/lib/types/diagnosis/schema.js.map +1 -0
  44. package/lib/types/diagnosis/seed-source.d.ts +20 -0
  45. package/lib/types/diagnosis/seed-source.d.ts.map +1 -0
  46. package/lib/types/diagnosis/seed-source.js +96 -0
  47. package/lib/types/diagnosis/seed-source.js.map +1 -0
  48. package/lib/types/diagnosis/seed.d.ts +50 -0
  49. package/lib/types/diagnosis/seed.d.ts.map +1 -0
  50. package/lib/types/diagnosis/seed.js +242 -0
  51. package/lib/types/diagnosis/seed.js.map +1 -0
  52. package/lib/types/diagnosis/store.d.ts +81 -0
  53. package/lib/types/diagnosis/store.d.ts.map +1 -0
  54. package/lib/types/diagnosis/store.js +409 -0
  55. package/lib/types/diagnosis/store.js.map +1 -0
  56. package/lib/types/diagnosis/types.d.ts +124 -0
  57. package/lib/types/diagnosis/types.d.ts.map +1 -0
  58. package/lib/types/diagnosis/types.js +13 -0
  59. package/lib/types/diagnosis/types.js.map +1 -0
  60. package/lib/types/directory-picker.d.ts +94 -0
  61. package/lib/types/directory-picker.d.ts.map +1 -0
  62. package/lib/types/directory-picker.js +110 -0
  63. package/lib/types/directory-picker.js.map +1 -0
  64. package/lib/types/extract-model.d.ts +76 -0
  65. package/lib/types/extract-model.d.ts.map +1 -0
  66. package/lib/types/extract-model.js +193 -0
  67. package/lib/types/extract-model.js.map +1 -0
  68. package/lib/types/extract.d.ts +121 -0
  69. package/lib/types/extract.d.ts.map +1 -0
  70. package/lib/types/extract.js +549 -0
  71. package/lib/types/extract.js.map +1 -0
  72. package/lib/types/fts.d.ts +96 -0
  73. package/lib/types/fts.d.ts.map +1 -0
  74. package/lib/types/fts.js +184 -0
  75. package/lib/types/fts.js.map +1 -0
  76. package/lib/types/index.d.ts +39 -0
  77. package/lib/types/index.d.ts.map +1 -0
  78. package/lib/types/index.js +1112 -0
  79. package/lib/types/index.js.map +1 -0
  80. package/lib/types/intent/engine.d.ts +108 -0
  81. package/lib/types/intent/engine.d.ts.map +1 -0
  82. package/lib/types/intent/engine.js +501 -0
  83. package/lib/types/intent/engine.js.map +1 -0
  84. package/lib/types/intent/host.d.ts +88 -0
  85. package/lib/types/intent/host.d.ts.map +1 -0
  86. package/lib/types/intent/host.js +389 -0
  87. package/lib/types/intent/host.js.map +1 -0
  88. package/lib/types/intent/preset-tools.d.ts +37 -0
  89. package/lib/types/intent/preset-tools.d.ts.map +1 -0
  90. package/lib/types/intent/preset-tools.js +45 -0
  91. package/lib/types/intent/preset-tools.js.map +1 -0
  92. package/lib/types/intent/settings-schema.d.ts +59 -0
  93. package/lib/types/intent/settings-schema.d.ts.map +1 -0
  94. package/lib/types/intent/settings-schema.js +57 -0
  95. package/lib/types/intent/settings-schema.js.map +1 -0
  96. package/lib/types/intent/store.d.ts +75 -0
  97. package/lib/types/intent/store.d.ts.map +1 -0
  98. package/lib/types/intent/store.js +139 -0
  99. package/lib/types/intent/store.js.map +1 -0
  100. package/lib/types/intent/tools.d.ts +63 -0
  101. package/lib/types/intent/tools.d.ts.map +1 -0
  102. package/lib/types/intent/tools.js +108 -0
  103. package/lib/types/intent/tools.js.map +1 -0
  104. package/lib/types/intent/types.d.ts +189 -0
  105. package/lib/types/intent/types.d.ts.map +1 -0
  106. package/lib/types/intent/types.js +62 -0
  107. package/lib/types/intent/types.js.map +1 -0
  108. package/lib/types/knowledge-bases.d.ts +266 -0
  109. package/lib/types/knowledge-bases.d.ts.map +1 -0
  110. package/lib/types/knowledge-bases.js +1107 -0
  111. package/lib/types/knowledge-bases.js.map +1 -0
  112. package/lib/types/layout.d.ts +262 -0
  113. package/lib/types/layout.d.ts.map +1 -0
  114. package/lib/types/layout.js +312 -0
  115. package/lib/types/layout.js.map +1 -0
  116. package/lib/types/migrate.d.ts +110 -0
  117. package/lib/types/migrate.d.ts.map +1 -0
  118. package/lib/types/migrate.js +280 -0
  119. package/lib/types/migrate.js.map +1 -0
  120. package/lib/types/recall-rank.d.ts +158 -0
  121. package/lib/types/recall-rank.d.ts.map +1 -0
  122. package/lib/types/recall-rank.js +261 -0
  123. package/lib/types/recall-rank.js.map +1 -0
  124. package/lib/types/runtime.d.ts +568 -0
  125. package/lib/types/runtime.d.ts.map +1 -0
  126. package/lib/types/runtime.js +3045 -0
  127. package/lib/types/runtime.js.map +1 -0
  128. package/lib/types/settings-schema.d.ts +117 -0
  129. package/lib/types/settings-schema.d.ts.map +1 -0
  130. package/lib/types/settings-schema.js +92 -0
  131. package/lib/types/settings-schema.js.map +1 -0
  132. package/lib/types/settings-volatile.d.ts +102 -0
  133. package/lib/types/settings-volatile.d.ts.map +1 -0
  134. package/lib/types/settings-volatile.js +114 -0
  135. package/lib/types/settings-volatile.js.map +1 -0
  136. package/lib/types/types.d.ts +799 -0
  137. package/lib/types/types.d.ts.map +1 -0
  138. package/lib/types/types.js +387 -0
  139. package/lib/types/types.js.map +1 -0
  140. package/lib/types/wiki-types.d.ts +68 -0
  141. package/lib/types/wiki-types.d.ts.map +1 -0
  142. package/lib/types/wiki-types.js +322 -0
  143. package/lib/types/wiki-types.js.map +1 -0
  144. package/package.json +101 -0
  145. package/preset/tita-data-agent/agent.cordis.yml +376 -0
  146. package/preset/tita-data-agent/preset.yml +3 -0
  147. package/python/requirements.txt +8 -0
  148. package/scripts/doctor.mjs +70 -0
  149. package/scripts/e2e-pipeline.mjs +355 -0
  150. package/scripts/install-agent-preset.mjs +92 -0
  151. package/scripts/setup-embedding.sh +34 -0
  152. package/scripts/sync-agent-preset.mjs +188 -0
  153. package/src/client/AgentPresetCard.tsx +247 -0
  154. package/src/client/DirectoryPicker.tsx +357 -0
  155. package/src/client/InfoHint.tsx +65 -0
  156. package/src/client/IntentLogicTab.tsx +185 -0
  157. package/src/client/IntentTab.tsx +715 -0
  158. package/src/client/KnowledgeBaseTab.tsx +1454 -0
  159. package/src/client/KnowledgeGraphView.tsx +306 -0
  160. package/src/client/KnowledgePanel.tsx +381 -0
  161. package/src/client/KnowledgeStepRail.tsx +60 -0
  162. package/src/client/NodeSettings.tsx +392 -0
  163. package/src/client/PreviewSections.tsx +116 -0
  164. package/src/client/RecallPanel.tsx +399 -0
  165. package/src/client/TypeDefinitionDrawer.tsx +215 -0
  166. package/src/client/WikiFlowCard.tsx +226 -0
  167. package/src/client/WikiTypeEditor.tsx +332 -0
  168. package/src/client/agent-preset.ts +121 -0
  169. package/src/client/arch/AgentArchitectureGraph.tsx +219 -0
  170. package/src/client/arch/NodeLogicPanel.tsx +133 -0
  171. package/src/client/arch/ProblemDetailPanel.tsx +88 -0
  172. package/src/client/arch/model.ts +691 -0
  173. package/src/client/architecture.css +191 -0
  174. package/src/client/architecture.tsx +530 -0
  175. package/src/client/attribution/AttributionGraph.tsx +104 -0
  176. package/src/client/attribution/AttributionTab.tsx +332 -0
  177. package/src/client/attribution/CaseView.tsx +102 -0
  178. package/src/client/attribution/GraphStage.tsx +87 -0
  179. package/src/client/attribution/RunView.tsx +184 -0
  180. package/src/client/attribution/StageChrome.tsx +403 -0
  181. package/src/client/attribution/ViewSwitch.tsx +107 -0
  182. package/src/client/attribution/graph-options.ts +381 -0
  183. package/src/client/attribution/model.ts +462 -0
  184. package/src/client/config-scope.ts +119 -0
  185. package/src/client/convert/ConvertPanel.tsx +594 -0
  186. package/src/client/convert/styles.css +138 -0
  187. package/src/client/convert/styles.ts +49 -0
  188. package/src/client/format.ts +39 -0
  189. package/src/client/graph/layout.ts +181 -0
  190. package/src/client/graph.css +113 -0
  191. package/src/client/index.ts +98 -0
  192. package/src/client/problem-domains.ts +114 -0
  193. package/src/client/styles.css +940 -0
  194. package/src/client/styles.ts +11 -0
  195. package/src/client/useFitScale.ts +68 -0
  196. package/src/config-schema.ts +45 -0
  197. package/src/convert/core-loader.ts +68 -0
  198. package/src/convert/host.ts +579 -0
  199. package/src/convert/ingest.ts +367 -0
  200. package/src/convert/settings-schema.ts +27 -0
  201. package/src/convert/types.ts +65 -0
  202. package/src/diagnosis/cards.ts +498 -0
  203. package/src/diagnosis/problem-classes.ts +117 -0
  204. package/src/diagnosis/schema.ts +260 -0
  205. package/src/diagnosis/seed-source.ts +107 -0
  206. package/src/diagnosis/seed.ts +291 -0
  207. package/src/diagnosis/store.ts +432 -0
  208. package/src/diagnosis/types.ts +152 -0
  209. package/src/directory-picker.ts +164 -0
  210. package/src/extract-model.ts +227 -0
  211. package/src/extract.ts +632 -0
  212. package/src/fts.ts +203 -0
  213. package/src/index.ts +1091 -0
  214. package/src/intent/README.md +63 -0
  215. package/src/intent/engine.ts +527 -0
  216. package/src/intent/host.ts +462 -0
  217. package/src/intent/preset-tools.ts +48 -0
  218. package/src/intent/settings-schema.ts +63 -0
  219. package/src/intent/store.ts +143 -0
  220. package/src/intent/tools.ts +139 -0
  221. package/src/intent/types.ts +245 -0
  222. package/src/knowledge-bases.ts +1160 -0
  223. package/src/layout.ts +350 -0
  224. package/src/migrate.ts +262 -0
  225. package/src/python/embedding_worker.py +471 -0
  226. package/src/recall-rank.ts +299 -0
  227. package/src/runtime.ts +3069 -0
  228. package/src/settings-schema.ts +94 -0
  229. package/src/settings-volatile.ts +122 -0
  230. package/src/types.ts +1140 -0
  231. package/src/wiki-types.ts +357 -0
@@ -0,0 +1,94 @@
1
+ /**
2
+ * 目录选择:把 DSH 宿主的 `ctx.directoryPicker` 接到 TitaAgent 控制台上(0029)。
3
+ *
4
+ * ## 为什么不让用户手输路径
5
+ *
6
+ * 路径是**磁盘事实**,不是用户脑子里的字符串。让人手打 `/Users/xxx/Desktop/…`
7
+ * 的结果是:拼错一个字符、`~` 没展开、复制粘贴带上了尾随空格 —— 而这一处的错误
8
+ * 代价特别大,它决定了整个 Agent 的东西存在哪。所以设置里那个「根路径」是一个
9
+ * **选择**动作,不是一个输入框。
10
+ *
11
+ * ## 为什么要适配两种交互
12
+ *
13
+ * 宿主把「怎么选目录」抽象成一个 capability,形状有两种:
14
+ *
15
+ * - `native`:在**宿主那台机器**上弹系统文件夹对话框,返回一个绝对路径。
16
+ * 浏览器和宿主在同一台机器上时这是最好的形态 —— 用户看到的是他熟悉的访达。
17
+ * - `browse`:宿主只提供「列一层 / 建子目录」两个原语,由调用方自己在页面里画
18
+ * 浏览界面。浏览器在远端(或宿主没有显示器)时这是唯一能用的形态。
19
+ *
20
+ * 两者**不能只挑一个**:本机部署走 native,远程访问走 browse,而这是启动时根据
21
+ * 绑定地址 / SSH / 显示器判定的(`dsh-host-directory-picker-auto`)。所以这里
22
+ * 如实把 kind 转给前端,由前端决定弹系统框还是画浏览框 —— 前端的默认写法是
23
+ * 「拿到 kind 再分叉」,而不是假设自己是哪一种。
24
+ *
25
+ * ## 为什么类型是结构化的
26
+ *
27
+ * `@deepseek-ai/dsh-host-directory-picker` 是 DSH 安装里的包,不是 npm 上可依赖的
28
+ * 版本,插件不能 import 它(会把 DSH 的内部路径焊进依赖图)。所以这里只声明我们
29
+ * 真正用到的那几个成员 —— 服务是按名字从 ctx 里取的,取不到就是没有,退化成
30
+ * 「宿主没提供目录选择器」这一条如实回答,而不是崩掉。
31
+ *
32
+ * @module
33
+ */
34
+ /** 一层目录里的一行:一个子目录,或一个面包屑祖先。 */
35
+ export interface DirectoryEntry {
36
+ /** 显示用的名字(根面包屑带的是完整路径)。 */
37
+ name: string;
38
+ /** 宿主机上的绝对路径 —— 调用方永远不自己拼路径段。 */
39
+ path: string;
40
+ /** 宿主平台约定的隐藏项(POSIX 上是点开头)。 */
41
+ hidden: boolean;
42
+ }
43
+ /** 一层目录 + 它的祖先链。 */
44
+ export interface DirectoryListing {
45
+ path: string;
46
+ /** 宿主账号的 home,面包屑的「Home」锚点。 */
47
+ home: string;
48
+ crumbs: DirectoryEntry[];
49
+ entries: DirectoryEntry[];
50
+ /** 后端把 entries 截断在它的完整结果上限上了。 */
51
+ truncated: boolean;
52
+ }
53
+ /** 宿主的目录选择能力。两个原语都可能是 `undefined` —— 取决于 kind。 */
54
+ export interface DirectoryPickerCapability {
55
+ kind: string;
56
+ pick?(signal: AbortSignal): Promise<string | null>;
57
+ list?(path?: string, signal?: AbortSignal): Promise<DirectoryListing>;
58
+ createDirectory?(path: string, name: string): Promise<string>;
59
+ }
60
+ /** `ctx.directoryPicker` 的结构化视图。 */
61
+ export interface DirectoryPickerLike {
62
+ capability(): DirectoryPickerCapability;
63
+ }
64
+ /** 目录选择失败的业务码。前端据此给出「怎么办」而不是一句「失败了」。 */
65
+ export type PickerErrorCode = 'PICKER_UNAVAILABLE' | 'PICK_CANCELLED' | 'DIRECTORY_UNREADABLE' | 'DIRECTORY_EXISTS' | 'DIRECTORY_CREATE_FAILED';
66
+ /** 带业务码的目录选择失败。 */
67
+ export declare class PickerError extends Error {
68
+ readonly code: PickerErrorCode;
69
+ constructor(code: PickerErrorCode, message: string);
70
+ }
71
+ /** 从 ctx 里按名字取目录选择服务。取不到返回 `undefined`(宿主没挂这个能力)。 */
72
+ export declare function pickerOf(ctx: {
73
+ get(name: string): unknown;
74
+ }): DirectoryPickerLike | undefined;
75
+ /** 宿主当前提供的是哪种交互。取不到服务时返回 `null`。 */
76
+ export declare function pickerKind(picker: DirectoryPickerLike | undefined): string | null;
77
+ /**
78
+ * 开一次选择。
79
+ *
80
+ * native 会**阻塞到用户给出答案**(关掉对话框也算答案:`path` 为 `null`),所以
81
+ * 调用方的 HTTP 请求会一直挂着 —— 这正是系统对话框的语义,不该用超时把它打断。
82
+ * browse 立刻返回,让前端去画浏览界面。
83
+ */
84
+ export declare function pickDirectory(picker: DirectoryPickerLike | undefined, signal: AbortSignal): Promise<{
85
+ kind: 'native';
86
+ path: string | null;
87
+ } | {
88
+ kind: 'browse';
89
+ }>;
90
+ /** 列一层目录(browse 形态)。 */
91
+ export declare function listDirectory(picker: DirectoryPickerLike | undefined, path: string | undefined, signal: AbortSignal): Promise<DirectoryListing>;
92
+ /** 在某个目录下建一个子目录(browse 形态)。 */
93
+ export declare function createDirectory(picker: DirectoryPickerLike | undefined, path: string, name: string): Promise<string>;
94
+ //# sourceMappingURL=directory-picker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"directory-picker.d.ts","sourceRoot":"","sources":["../../src/directory-picker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,+BAA+B;AAC/B,MAAM,WAAW,cAAc;IAC7B,2BAA2B;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,iCAAiC;IACjC,IAAI,EAAE,MAAM,CAAA;IACZ,+BAA+B;IAC/B,MAAM,EAAE,OAAO,CAAA;CAChB;AAED,oBAAoB;AACpB,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAA;IACZ,+BAA+B;IAC/B,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,cAAc,EAAE,CAAA;IACxB,OAAO,EAAE,cAAc,EAAE,CAAA;IACzB,iCAAiC;IACjC,SAAS,EAAE,OAAO,CAAA;CACnB;AAED,kDAAkD;AAClD,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAA;IAClD,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAA;IACrE,eAAe,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;CAC9D;AAED,oCAAoC;AACpC,MAAM,WAAW,mBAAmB;IAClC,UAAU,IAAI,yBAAyB,CAAA;CACxC;AAED,wCAAwC;AACxC,MAAM,MAAM,eAAe,GACvB,oBAAoB,GACpB,gBAAgB,GAChB,sBAAsB,GACtB,kBAAkB,GAClB,yBAAyB,CAAA;AAE7B,mBAAmB;AACnB,qBAAa,WAAY,SAAQ,KAAK;IACpC,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAA;gBAClB,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM;CAKnD;AAED,qDAAqD;AACrD,wBAAgB,QAAQ,CAAC,GAAG,EAAE;IAAE,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,GAAG,mBAAmB,GAAG,SAAS,CAG7F;AAED,oCAAoC;AACpC,wBAAgB,UAAU,CAAC,MAAM,EAAE,mBAAmB,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAOjF;AAED;;;;;;GAMG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,mBAAmB,GAAG,SAAS,EACvC,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAC,CAYvE;AAED,wBAAwB;AACxB,wBAAsB,aAAa,CACjC,MAAM,EAAE,mBAAmB,GAAG,SAAS,EACvC,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,gBAAgB,CAAC,CAU3B;AAED,+BAA+B;AAC/B,wBAAsB,eAAe,CACnC,MAAM,EAAE,mBAAmB,GAAG,SAAS,EACvC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,MAAM,CAAC,CAejB"}
@@ -0,0 +1,110 @@
1
+ /**
2
+ * 目录选择:把 DSH 宿主的 `ctx.directoryPicker` 接到 TitaAgent 控制台上(0029)。
3
+ *
4
+ * ## 为什么不让用户手输路径
5
+ *
6
+ * 路径是**磁盘事实**,不是用户脑子里的字符串。让人手打 `/Users/xxx/Desktop/…`
7
+ * 的结果是:拼错一个字符、`~` 没展开、复制粘贴带上了尾随空格 —— 而这一处的错误
8
+ * 代价特别大,它决定了整个 Agent 的东西存在哪。所以设置里那个「根路径」是一个
9
+ * **选择**动作,不是一个输入框。
10
+ *
11
+ * ## 为什么要适配两种交互
12
+ *
13
+ * 宿主把「怎么选目录」抽象成一个 capability,形状有两种:
14
+ *
15
+ * - `native`:在**宿主那台机器**上弹系统文件夹对话框,返回一个绝对路径。
16
+ * 浏览器和宿主在同一台机器上时这是最好的形态 —— 用户看到的是他熟悉的访达。
17
+ * - `browse`:宿主只提供「列一层 / 建子目录」两个原语,由调用方自己在页面里画
18
+ * 浏览界面。浏览器在远端(或宿主没有显示器)时这是唯一能用的形态。
19
+ *
20
+ * 两者**不能只挑一个**:本机部署走 native,远程访问走 browse,而这是启动时根据
21
+ * 绑定地址 / SSH / 显示器判定的(`dsh-host-directory-picker-auto`)。所以这里
22
+ * 如实把 kind 转给前端,由前端决定弹系统框还是画浏览框 —— 前端的默认写法是
23
+ * 「拿到 kind 再分叉」,而不是假设自己是哪一种。
24
+ *
25
+ * ## 为什么类型是结构化的
26
+ *
27
+ * `@deepseek-ai/dsh-host-directory-picker` 是 DSH 安装里的包,不是 npm 上可依赖的
28
+ * 版本,插件不能 import 它(会把 DSH 的内部路径焊进依赖图)。所以这里只声明我们
29
+ * 真正用到的那几个成员 —— 服务是按名字从 ctx 里取的,取不到就是没有,退化成
30
+ * 「宿主没提供目录选择器」这一条如实回答,而不是崩掉。
31
+ *
32
+ * @module
33
+ */
34
+ /** 带业务码的目录选择失败。 */
35
+ export class PickerError extends Error {
36
+ code;
37
+ constructor(code, message) {
38
+ super(message);
39
+ this.code = code;
40
+ this.name = 'PickerError';
41
+ }
42
+ }
43
+ /** 从 ctx 里按名字取目录选择服务。取不到返回 `undefined`(宿主没挂这个能力)。 */
44
+ export function pickerOf(ctx) {
45
+ const service = ctx.get('directoryPicker');
46
+ return service && typeof service.capability === 'function' ? service : undefined;
47
+ }
48
+ /** 宿主当前提供的是哪种交互。取不到服务时返回 `null`。 */
49
+ export function pickerKind(picker) {
50
+ if (!picker)
51
+ return null;
52
+ try {
53
+ return picker.capability()?.kind ?? null;
54
+ }
55
+ catch {
56
+ return null;
57
+ }
58
+ }
59
+ /**
60
+ * 开一次选择。
61
+ *
62
+ * native 会**阻塞到用户给出答案**(关掉对话框也算答案:`path` 为 `null`),所以
63
+ * 调用方的 HTTP 请求会一直挂着 —— 这正是系统对话框的语义,不该用超时把它打断。
64
+ * browse 立刻返回,让前端去画浏览界面。
65
+ */
66
+ export async function pickDirectory(picker, signal) {
67
+ const capability = picker?.capability();
68
+ if (!capability) {
69
+ throw new PickerError('PICKER_UNAVAILABLE', '宿主没有提供目录选择器,无法打开文件夹对话框。');
70
+ }
71
+ if (capability.kind === 'native') {
72
+ if (typeof capability.pick !== 'function') {
73
+ throw new PickerError('PICKER_UNAVAILABLE', '宿主的目录选择器声明为 native,但没有提供 pick。');
74
+ }
75
+ return { kind: 'native', path: await capability.pick(signal) };
76
+ }
77
+ return { kind: 'browse' };
78
+ }
79
+ /** 列一层目录(browse 形态)。 */
80
+ export async function listDirectory(picker, path, signal) {
81
+ const capability = picker?.capability();
82
+ if (!capability || capability.kind !== 'browse' || typeof capability.list !== 'function') {
83
+ throw new PickerError('PICKER_UNAVAILABLE', '宿主没有提供可浏览的目录列表。');
84
+ }
85
+ try {
86
+ return await capability.list(path, signal);
87
+ }
88
+ catch (cause) {
89
+ throw new PickerError('DIRECTORY_UNREADABLE', cause instanceof Error ? cause.message : String(cause));
90
+ }
91
+ }
92
+ /** 在某个目录下建一个子目录(browse 形态)。 */
93
+ export async function createDirectory(picker, path, name) {
94
+ const capability = picker?.capability();
95
+ if (!capability || capability.kind !== 'browse' || typeof capability.createDirectory !== 'function') {
96
+ throw new PickerError('PICKER_UNAVAILABLE', '宿主没有提供新建目录的能力。');
97
+ }
98
+ const trimmed = name.trim();
99
+ if (!trimmed || trimmed.includes('/') || trimmed.includes('\\') || trimmed === '.' || trimmed === '..') {
100
+ throw new PickerError('DIRECTORY_CREATE_FAILED', '目录名不能为空、不能包含路径分隔符,也不能是 . 或 ..');
101
+ }
102
+ try {
103
+ return await capability.createDirectory(path, trimmed);
104
+ }
105
+ catch (cause) {
106
+ const message = cause instanceof Error ? cause.message : String(cause);
107
+ throw new PickerError(/exist/i.test(message) ? 'DIRECTORY_EXISTS' : 'DIRECTORY_CREATE_FAILED', message);
108
+ }
109
+ }
110
+ //# sourceMappingURL=directory-picker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"directory-picker.js","sourceRoot":"","sources":["../../src/directory-picker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * 模型驱动的候选抽取与**实体归并**(#3b)。
3
+ *
4
+ * ## 为什么需要这一步,而不是继续改规则
5
+ *
6
+ * Pass 0 的规则抽取用**小节标题**当实体身份(`candidateEntityId(candidate.name)`)。
7
+ * 于是同一件东西只要换个标题写法,就是两个实体。这不是理论问题,是实测出来的:
8
+ *
9
+ * - 年报里的小节叫「毛利率变动及其驱动因素」;
10
+ * - 口径手册里的小节叫「毛利率(口径补充)」;
11
+ * - 结果:`新建 2 / 并入 0`,两张互不相干的卡片,
12
+ * 而「实体已存在就追加正文」那条分支**永远不会触发**。
13
+ *
14
+ * 想去掉括号后缀、去掉「及其驱动因素」这类尾巴,是**语义判断**:`毛利率` 与
15
+ * `毛利率变动及其驱动因素` 是同一个东西,而 `应收账款周转天数` 与 `库存周转天数`
16
+ * 不是 —— 两者字面都带「周转天数」。阈值化的字符串规则在第二步上必然出错,
17
+ * 所以这件事必须交给模型。
18
+ *
19
+ * ## 这一层只问一个问题
20
+ *
21
+ * 它**不**让模型自由编造卡片,也不让它决定正文:正文永远是来源里的原文片段,
22
+ * 模型只回答两件它擅长、而规则做不好的事 ——
23
+ *
24
+ * 1. 「这份来源里有哪些**实体**」(规则只会按小节切,切出来的是标题不是实体);
25
+ * 2. 「这个实体是不是已经在下表里了」(给出已有卡片的 `existing_id`)。
26
+ *
27
+ * 第 2 问是归并的关键:**判断权在模型,决定权在这里**。模型说「是同一个」,
28
+ * 我们就走追加;说「不是」,就新建。模型给出的 `existing_id` 必须能在已有卡片里
29
+ * 找到,找不到就退回新建 —— 不能让模型凭一个不存在的 id 把内容写丢。
30
+ *
31
+ * ## 为什么要注入 `call`
32
+ *
33
+ * 模型调用是这一层唯一的非纯部分。把它作为参数注入,这个模块就能在没有模型的环境里
34
+ * 被完整测试(见 `tests/extract-model.test.mjs`)——否则「归并对不对」这件事只能靠
35
+ * 真跑一次模型来验,而那是不可重复的。
36
+ *
37
+ * @module
38
+ */
39
+ import { type ExtractionCandidate } from './extract.js';
40
+ import type { KnowledgeCard, SchemaType, SourceRaw, WikiTypeDef } from './types.js';
41
+ /** 一次纯文本模型调用:给出 system 与 prompt,拿回模型的原始文本。 */
42
+ export type ModelCall = (request: {
43
+ system: string;
44
+ prompt: string;
45
+ }) => Promise<string>;
46
+ /** 归并条目:与规则抽取的 `NormalizedCandidates['merges']` 保持同一形状。 */
47
+ export interface ModelMerge {
48
+ key: string;
49
+ entityId: string;
50
+ entityType: SchemaType;
51
+ sourceId: string;
52
+ body: string;
53
+ }
54
+ export interface ModelExtractionResult {
55
+ /** 判定为「wiki 里还没有」的实体 → 新建卡片。 */
56
+ fresh: ExtractionCandidate[];
57
+ /** 判定为「wiki 里已经有了」的实体 → 正文追加进那张卡。 */
58
+ merges: ModelMerge[];
59
+ warnings: string[];
60
+ }
61
+ export interface ModelExtractionInput {
62
+ source: SourceRaw;
63
+ /** 已启用的 wiki 类型:模型只能从这些 id 里选。 */
64
+ wikiTypes: WikiTypeDef[];
65
+ /** 当前库里的卡片:既是「已存在」的候选集,也是给模型的上下文。 */
66
+ existing: KnowledgeCard[];
67
+ call: ModelCall;
68
+ }
69
+ /**
70
+ * 用模型抽取实体,并把它们判归到「新建」或「追加到已有卡片」两条路上。
71
+ *
72
+ * 失败一律降级而不抛出:模型不可用时返回空结果 + 一条 warning,让上层继续跑规则抽取。
73
+ * 「因为模型挂了所以整次编译失败」是不能接受的 —— 那条链路本来就不依赖模型。
74
+ */
75
+ export declare function extractWithModel(input: ModelExtractionInput): Promise<ModelExtractionResult>;
76
+ //# sourceMappingURL=extract-model.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extract-model.d.ts","sourceRoot":"","sources":["../../src/extract-model.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,OAAO,EAAqB,KAAK,mBAAmB,EAAE,MAAM,cAAc,CAAA;AAC1E,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAEnF,8CAA8C;AAC9C,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;AAExF,2DAA2D;AAC3D,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAA;IACX,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,UAAU,CAAA;IACtB,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,qBAAqB;IACpC,gCAAgC;IAChC,KAAK,EAAE,mBAAmB,EAAE,CAAA;IAC5B,qCAAqC;IACrC,MAAM,EAAE,UAAU,EAAE,CAAA;IACpB,QAAQ,EAAE,MAAM,EAAE,CAAA;CACnB;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,SAAS,CAAA;IACjB,kCAAkC;IAClC,SAAS,EAAE,WAAW,EAAE,CAAA;IACxB,qCAAqC;IACrC,QAAQ,EAAE,aAAa,EAAE,CAAA;IACzB,IAAI,EAAE,SAAS,CAAA;CAChB;AA2ED;;;;;GAKG;AACH,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CA4ElG"}
@@ -0,0 +1,193 @@
1
+ /**
2
+ * 模型驱动的候选抽取与**实体归并**(#3b)。
3
+ *
4
+ * ## 为什么需要这一步,而不是继续改规则
5
+ *
6
+ * Pass 0 的规则抽取用**小节标题**当实体身份(`candidateEntityId(candidate.name)`)。
7
+ * 于是同一件东西只要换个标题写法,就是两个实体。这不是理论问题,是实测出来的:
8
+ *
9
+ * - 年报里的小节叫「毛利率变动及其驱动因素」;
10
+ * - 口径手册里的小节叫「毛利率(口径补充)」;
11
+ * - 结果:`新建 2 / 并入 0`,两张互不相干的卡片,
12
+ * 而「实体已存在就追加正文」那条分支**永远不会触发**。
13
+ *
14
+ * 想去掉括号后缀、去掉「及其驱动因素」这类尾巴,是**语义判断**:`毛利率` 与
15
+ * `毛利率变动及其驱动因素` 是同一个东西,而 `应收账款周转天数` 与 `库存周转天数`
16
+ * 不是 —— 两者字面都带「周转天数」。阈值化的字符串规则在第二步上必然出错,
17
+ * 所以这件事必须交给模型。
18
+ *
19
+ * ## 这一层只问一个问题
20
+ *
21
+ * 它**不**让模型自由编造卡片,也不让它决定正文:正文永远是来源里的原文片段,
22
+ * 模型只回答两件它擅长、而规则做不好的事 ——
23
+ *
24
+ * 1. 「这份来源里有哪些**实体**」(规则只会按小节切,切出来的是标题不是实体);
25
+ * 2. 「这个实体是不是已经在下表里了」(给出已有卡片的 `existing_id`)。
26
+ *
27
+ * 第 2 问是归并的关键:**判断权在模型,决定权在这里**。模型说「是同一个」,
28
+ * 我们就走追加;说「不是」,就新建。模型给出的 `existing_id` 必须能在已有卡片里
29
+ * 找到,找不到就退回新建 —— 不能让模型凭一个不存在的 id 把内容写丢。
30
+ *
31
+ * ## 为什么要注入 `call`
32
+ *
33
+ * 模型调用是这一层唯一的非纯部分。把它作为参数注入,这个模块就能在没有模型的环境里
34
+ * 被完整测试(见 `tests/extract-model.test.mjs`)——否则「归并对不对」这件事只能靠
35
+ * 真跑一次模型来验,而那是不可重复的。
36
+ *
37
+ * @module
38
+ */
39
+ import { candidateEntityId } from './extract.js';
40
+ /** 单个实体最多给模型的正文长度:够判断语义,又不至于把上下文撑爆。 */
41
+ const BODY_LIMIT = 1200;
42
+ /**
43
+ * 系统提示。**刻意写死在这里**而不是做成设置项:它不是用户的偏好,是这个模块与模型
44
+ * 之间的接口契约(输出必须是一段可解析的 JSON)。允许用户改它,等于允许用户把这个
45
+ * 解析器改坏。
46
+ */
47
+ const SYSTEM = [
48
+ 'You extract wiki entities from a business document and decide which of them already exist.',
49
+ 'Answer with a single JSON object and nothing else. No prose, no code fence.',
50
+ 'Shape: {"entities":[{"name":string,"type":string,"summary":string,"body":string,"existing_id":string|null}]}',
51
+ 'Rules:',
52
+ '- "name" is the entity name as a business person would say it (e.g. 毛利率). Not a section heading.',
53
+ '- "type" MUST be one of the allowed type ids given in the prompt.',
54
+ '- "body" must be verbatim text from the document that backs this entity. Never invent facts.',
55
+ '- "existing_id" is the entityId of the existing card this entity is the SAME thing as, or null.',
56
+ ' Same thing means the same business concept; a narrower or different concept is NOT the same.',
57
+ '- Prefer few, real entities over many headings.',
58
+ ].join('\n');
59
+ /** 从一串可能带 ``` 围栏的文本里取出 JSON 对象并解析。 */
60
+ function parseJsonObject(raw) {
61
+ const trimmed = raw.trim();
62
+ const fenced = trimmed.match(/```(?:json)?\s*([\s\S]*?)```/);
63
+ const body = (fenced ? fenced[1] : trimmed).trim();
64
+ try {
65
+ return JSON.parse(body);
66
+ }
67
+ catch {
68
+ // 模型有时会在 JSON 前后带一句解释:退一步,取第一个 `{` 到最后一个 `}`。
69
+ const start = body.indexOf('{');
70
+ const end = body.lastIndexOf('}');
71
+ if (start < 0 || end <= start)
72
+ return undefined;
73
+ try {
74
+ return JSON.parse(body.slice(start, end + 1));
75
+ }
76
+ catch {
77
+ return undefined;
78
+ }
79
+ }
80
+ }
81
+ /** 把模型的回答收敛成「合法实体数组」;任何不合法的一条都丢掉并记一条 warning。 */
82
+ function readEntities(raw, allowedTypes, warnings) {
83
+ if (raw === null || typeof raw !== 'object') {
84
+ warnings.push('模型输出不是 JSON 对象,本次抽取按空处理');
85
+ return [];
86
+ }
87
+ const list = raw.entities;
88
+ if (!Array.isArray(list)) {
89
+ warnings.push('模型输出里没有 entities 数组,本次抽取按空处理');
90
+ return [];
91
+ }
92
+ const kept = [];
93
+ for (const item of list) {
94
+ if (item === null || typeof item !== 'object')
95
+ continue;
96
+ const record = item;
97
+ const name = typeof record.name === 'string' ? record.name.trim() : '';
98
+ const type = typeof record.type === 'string' ? record.type.trim() : '';
99
+ const body = typeof record.body === 'string' ? record.body.trim() : '';
100
+ if (!name)
101
+ continue;
102
+ if (!allowedTypes.has(type)) {
103
+ warnings.push(`模型给出的类型「${type}」不在已启用类型里,候选「${name}」被丢掉`);
104
+ continue;
105
+ }
106
+ if (!body) {
107
+ warnings.push(`候选「${name}」没有正文,被丢掉(卡片不能没有正文)`);
108
+ continue;
109
+ }
110
+ kept.push({ ...record, name, type, body });
111
+ }
112
+ return kept;
113
+ }
114
+ /**
115
+ * 用模型抽取实体,并把它们判归到「新建」或「追加到已有卡片」两条路上。
116
+ *
117
+ * 失败一律降级而不抛出:模型不可用时返回空结果 + 一条 warning,让上层继续跑规则抽取。
118
+ * 「因为模型挂了所以整次编译失败」是不能接受的 —— 那条链路本来就不依赖模型。
119
+ */
120
+ export async function extractWithModel(input) {
121
+ const { source, wikiTypes, existing, call } = input;
122
+ const warnings = [];
123
+ const enabled = wikiTypes.filter(def => def.enabled);
124
+ const allowedTypes = new Set(enabled.map(def => String(def.id)));
125
+ const catalog = existing
126
+ .slice(0, 200)
127
+ .map(card => `- ${card.entityId} :: ${card.title}(${card.entityType})`)
128
+ .join('\n');
129
+ const types = enabled
130
+ .map(def => `- ${def.id} :: ${def.label}${def.description ? ` — ${def.description}` : ''}`)
131
+ .join('\n');
132
+ const prompt = [
133
+ '# Allowed wiki type ids',
134
+ types || '(没有任何已启用类型)',
135
+ '',
136
+ '# Existing wiki cards (entityId :: title)',
137
+ catalog || '(这个库还是空的)',
138
+ '',
139
+ '# Document',
140
+ `title: ${source.title}`,
141
+ `source_id: ${source.sourceId}`,
142
+ '',
143
+ source.content.slice(0, BODY_LIMIT * 8),
144
+ ].join('\n');
145
+ let raw;
146
+ try {
147
+ raw = await call({ system: SYSTEM, prompt });
148
+ }
149
+ catch (cause) {
150
+ warnings.push(`模型抽取不可用:${cause instanceof Error ? cause.message : String(cause)}`);
151
+ return { fresh: [], merges: [], warnings };
152
+ }
153
+ const byId = new Map(existing.map(card => [`${card.entityType}:${card.entityId}`, card]));
154
+ const byEntityId = new Map(existing.map(card => [card.entityId, card]));
155
+ const fresh = [];
156
+ const merges = [];
157
+ const claimed = new Set();
158
+ for (const entity of readEntities(parseJsonObject(raw), allowedTypes, warnings)) {
159
+ const name = String(entity.name);
160
+ const type = String(entity.type);
161
+ const body = String(entity.body).slice(0, BODY_LIMIT);
162
+ const wantedId = typeof entity.existing_id === 'string' ? entity.existing_id.trim() : '';
163
+ // 模型给的 id 必须真的存在:它指着不存在的卡片时退回新建,绝不能让正文丢在空中。
164
+ const target = (wantedId ? byEntityId.get(wantedId) : undefined) ?? byId.get(`${type}:${name}`);
165
+ if (target) {
166
+ const key = `${target.entityType}:${target.entityId}`;
167
+ // 同一张卡在一次抽取里被多个候选指向时只并一次,正文在这里先合起来。
168
+ const already = merges.find(entry => entry.key === key);
169
+ if (already)
170
+ already.body = `${already.body}\n\n${body}`;
171
+ else
172
+ merges.push({ key, entityId: target.entityId, entityType: target.entityType, sourceId: source.sourceId, body });
173
+ claimed.add(key);
174
+ continue;
175
+ }
176
+ const entityId = candidateEntityId(name);
177
+ const key = `${type}:${entityId}`;
178
+ if (claimed.has(key))
179
+ continue;
180
+ claimed.add(key);
181
+ fresh.push({
182
+ kind: 'entity',
183
+ name,
184
+ type,
185
+ body,
186
+ aliases: [],
187
+ evidence: { sourceId: source.sourceId },
188
+ confidence: 0.7,
189
+ });
190
+ }
191
+ return { fresh, merges, warnings };
192
+ }
193
+ //# sourceMappingURL=extract-model.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extract-model.js","sourceRoot":"","sources":["../../src/extract-model.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,121 @@
1
+ import type { KnowledgeCard, SchemaType, SourceRaw, WikiTypeDef } from './types.js';
2
+ /**
3
+ * Pass 0 · 候选抽取 + 归一(与库内判重)。
4
+ *
5
+ * 这一层是「SourceRaw → Wiki」的第一个编译阶段,也是唯一一个**不调用模型**的阶段:
6
+ * 它只做「文档里明明白白写着什么」这件事。三个设计判断:
7
+ *
8
+ * 1. **纯函数。** 不碰磁盘、不碰模型、不碰网络,所以它可以被直接单测,
9
+ * 也可以在重建之外被复用(Agent 想先看看会抽出什么)。真正落盘的是 `rebuild()`。
10
+ * 2. **只认有据可查的候选。** 每个候选都必须带着 `evidence`(来源 id + 小节 / 原文片段);
11
+ * 抽不出证据的位置宁可不出候选,也不编一个名字出来。
12
+ * 3. **related ≠ same。** `relation` 候选永远只变成图的边,绝不参与卡片合并 ——
13
+ * 「A 和 B 有关系」和「A 就是 B」是两件事,混起来会把两张卡片糊成一张,
14
+ * 而且糊掉之后没有任何痕迹能还原。
15
+ */
16
+ export interface CandidateEvidence {
17
+ sourceId: string;
18
+ /** 候选来自哪个 `##`/`###` 小节(声明式候选可自带)。 */
19
+ heading?: string;
20
+ /** 支撑这个候选的原文片段;只作证据展示,不参与判重。 */
21
+ quote?: string;
22
+ }
23
+ export interface ExtractionCandidate {
24
+ kind: 'entity' | 'concept' | 'relation';
25
+ /** Display name, e.g. 「销售口径」. */
26
+ name: string;
27
+ /** The wiki card type this candidate should become. Must be an enabled WikiTypeDef id. */
28
+ type: SchemaType;
29
+ evidence: CandidateEvidence;
30
+ /** Other spellings that mean the same thing (from `[[Name|alias]]` and frontmatter). */
31
+ aliases?: string[];
32
+ /** Markdown body that backs this candidate (used as the card body). */
33
+ body?: string;
34
+ /** For kind === 'relation': the other end. */
35
+ target?: {
36
+ name: string;
37
+ type?: SchemaType;
38
+ };
39
+ /** For kind === 'relation': the relation id, e.g. 'relates_to'. */
40
+ relation?: string;
41
+ confidence: number;
42
+ }
43
+ /** 抽取关系候选时使用的默认关系 id;图里也只认这个 id(见 `rebuild()` 的边装配)。 */
44
+ export declare const RELATES_TO = "relates_to";
45
+ /**
46
+ * 每份来源最多抽多少张卡片候选。
47
+ *
48
+ * 这是**有意为之的上限**,不是省略号:一份长文档的小节可以有几十个,放开就会把
49
+ * 一个知识库灌成「一篇文档 = 几十张未审核卡片」,人再也不会去看它们。宁可少抽,
50
+ * 剩下的由 Agent 用声明式候选主动补。
51
+ */
52
+ export declare const MAX_CANDIDATES_PER_SOURCE = 12;
53
+ /**
54
+ * 名字归一:小写 + 把非字母数字的连续段折成 `-`。
55
+ *
56
+ * **必须与 `candidateKey` / `buildAliasIndex` 用同一套归一**,否则「GMV 口径」和
57
+ * 「gmv-口径」在索引里是两个键,判重就会漏。这里刻意用小写化而不是运行时 slug 的
58
+ * 原样保留,因为判重是「同一个指称」的问题,大小写不构成区别。
59
+ */
60
+ export declare function normalizeCandidateName(value: string): string;
61
+ export declare function candidateKey(candidate: {
62
+ type: string;
63
+ name: string;
64
+ }): string;
65
+ /**
66
+ * 候选落到磁盘时用的 `entity_id`。
67
+ *
68
+ * 卡片 id 必须过 `SAFE_ID`(ASCII),而候选名常常是中文,所以中文名不能直接当 id:
69
+ * 这里退化成 `candidate-<fnv1a>` 的稳定哈希。名字本身仍然完整地写进卡片 title,
70
+ * 并作为 alias 进索引,所以下一次判重照样能按名字找到它 —— 判重认的是名字,不是 id。
71
+ */
72
+ export declare function candidateEntityId(name: string): string;
73
+ export declare function extractCandidates(source: SourceRaw, wikiTypes: WikiTypeDef[]): ExtractionCandidate[];
74
+ /**
75
+ * 现有卡片的判重索引。
76
+ *
77
+ * 三处都登记:`entityType + entityId`(技术 id)、`entityType + title`(人写的中文名)、
78
+ * `metadata.aliases` 里的每个写法。**别名是关键字**:Agent 写卡片时把「GMV 口径」登记
79
+ * 成 `gmv-kpi` 的别名,抽取器下一次就认得这两者是同一个指称,不会再造第二张卡。
80
+ */
81
+ export declare function buildAliasIndex(cards: KnowledgeCard[]): Map<string, KnowledgeCard>;
82
+ export interface NormalizedCandidates {
83
+ fresh: ExtractionCandidate[];
84
+ /**
85
+ * Candidates whose referent already exists: merge into that card.
86
+ *
87
+ * `body` 是**这次新抽到的正文**,必须一起带出去。只带 `sourceId` 的话,调用方
88
+ * 除了「记一笔来源」什么也做不了 —— 新写进来源里的内容会**静默消失**,卡片永远
89
+ * 停在第一次抽取时的样子(落点是 `runtime.ts` 的 `appendExtracted`)。
90
+ */
91
+ merges: Array<{
92
+ key: string;
93
+ entityId: string;
94
+ entityType: SchemaType;
95
+ sourceId: string;
96
+ body: string;
97
+ }>;
98
+ /**
99
+ * Relation candidates are never merged — they become graph edges.
100
+ *
101
+ * `fromKey` / `toKey` 是**图上的节点键**(`<entityType>:<entityId>`),不是候选键
102
+ * (`<type>:<归一化名字>`)。两者在名字是 ASCII 时长得一样,在中文名上完全不同 ——
103
+ * 中文名的卡片 id 会退化成 `candidate-<hash>`。这里必须先解析成真正的节点键,
104
+ * 否则装配图时按候选键去找节点,**所有中文名之间的关系都会被当成「端点不存在」丢掉**。
105
+ */
106
+ relations: Array<{
107
+ fromKey: string;
108
+ toKey: string;
109
+ relation: string;
110
+ sourceId: string;
111
+ }>;
112
+ }
113
+ /**
114
+ * 归一:把候选分成「新建」「并入已有卡片」「关系」三类。
115
+ *
116
+ * 关系两端也走同一套判重,所以边只可能连到**真实存在的 wiki 节点**上;解析不出来的
117
+ * 端点会带着一个稳定 key 出去,由 `rebuild()` 在装配图时丢弃并计数,而不是在这里
118
+ * 凭空造一个节点。
119
+ */
120
+ export declare function normalizeCandidates(candidates: ExtractionCandidate[], index: Map<string, KnowledgeCard>): NormalizedCandidates;
121
+ //# sourceMappingURL=extract.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extract.d.ts","sourceRoot":"","sources":["../../src/extract.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAEnF;;;;;;;;;;;;;GAaG;AAEH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAA;IAChB,sCAAsC;IACtC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,gCAAgC;IAChC,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,QAAQ,GAAG,SAAS,GAAG,UAAU,CAAA;IACvC,iCAAiC;IACjC,IAAI,EAAE,MAAM,CAAA;IACZ,0FAA0F;IAC1F,IAAI,EAAE,UAAU,CAAA;IAChB,QAAQ,EAAE,iBAAiB,CAAA;IAC3B,wFAAwF;IACxF,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,uEAAuE;IACvE,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,8CAA8C;IAC9C,MAAM,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,UAAU,CAAA;KAAE,CAAA;IAC5C,mEAAmE;IACnE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,wDAAwD;AACxD,eAAO,MAAM,UAAU,eAAe,CAAA;AAEtC;;;;;;GAMG;AACH,eAAO,MAAM,yBAAyB,KAAK,CAAA;AAiB3C;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED,wBAAgB,YAAY,CAAC,SAAS,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAE9E;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAItD;AAmPD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,GAAG,mBAAmB,EAAE,CAyJpG;AAID;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,aAAa,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAclF;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,mBAAmB,EAAE,CAAA;IAC5B;;;;;;OAMG;IACH,MAAM,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,UAAU,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACxG;;;;;;;OAOG;IACH,SAAS,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CACzF;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,mBAAmB,EAAE,EAAE,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,GAAG,oBAAoB,CAoF9H"}